Files
moltbot/src/agents/pi-tools.abort.ts
Tak Hoffman 9c7823350b feat: add /tools runtime availability view (#54088)
* test(memory): lock qmd status counts regression

* feat: make /tools show what the agent can use right now

* fix: sync web ui slash commands with the shared registry

* feat: add profile and unavailable counts to /tools

* refine: keep /tools focused on available tools

* fix: resolve /tools review regressions

* fix: honor model compat in /tools inventory

* fix: sync generated protocol models for /tools

* fix: restore canonical slash command names

* fix: avoid ci lint drift in google helper exports

* perf: stop computing unused /tools unavailable counts

* docs: clarify /tools runtime behavior
2026-03-24 21:09:51 -05:00

73 lines
1.9 KiB
TypeScript

import { copyPluginToolMeta } from "../plugins/tools.js";
import { bindAbortRelay } from "../utils/fetch-timeout.js";
import { copyChannelAgentToolMeta } from "./channel-tools.js";
import type { AnyAgentTool } from "./pi-tools.types.js";
function throwAbortError(): never {
const err = new Error("Aborted");
err.name = "AbortError";
throw err;
}
/**
* Checks if an object is a valid AbortSignal using structural typing.
* This is more reliable than `instanceof` across different realms (VM, iframe, etc.)
* where the AbortSignal constructor may differ.
*/
function isAbortSignal(obj: unknown): obj is AbortSignal {
return obj instanceof AbortSignal;
}
function combineAbortSignals(a?: AbortSignal, b?: AbortSignal): AbortSignal | undefined {
if (!a && !b) {
return undefined;
}
if (a && !b) {
return a;
}
if (b && !a) {
return b;
}
if (a?.aborted) {
return a;
}
if (b?.aborted) {
return b;
}
if (typeof AbortSignal.any === "function" && isAbortSignal(a) && isAbortSignal(b)) {
return AbortSignal.any([a, b]);
}
const controller = new AbortController();
const onAbort = bindAbortRelay(controller);
a?.addEventListener("abort", onAbort, { once: true });
b?.addEventListener("abort", onAbort, { once: true });
return controller.signal;
}
export function wrapToolWithAbortSignal(
tool: AnyAgentTool,
abortSignal?: AbortSignal,
): AnyAgentTool {
if (!abortSignal) {
return tool;
}
const execute = tool.execute;
if (!execute) {
return tool;
}
const wrappedTool: AnyAgentTool = {
...tool,
execute: async (toolCallId, params, signal, onUpdate) => {
const combined = combineAbortSignals(signal, abortSignal);
if (combined?.aborted) {
throwAbortError();
}
return await execute(toolCallId, params, combined, onUpdate);
},
};
copyPluginToolMeta(tool, wrappedTool);
copyChannelAgentToolMeta(tool as never, wrappedTool as never);
return wrappedTool;
}