diff --git a/src/agent/agent.ts b/src/agent/agent.ts index 0d7f665..3290347 100644 --- a/src/agent/agent.ts +++ b/src/agent/agent.ts @@ -50,6 +50,19 @@ import { const ZERO_USAGE: TokenUsage = { input_tokens: 0, output_tokens: 0 } +/** + * Combine two {@link AbortSignal}s so that aborting either one cancels the + * returned signal. Works on Node 18+ (no `AbortSignal.any` required). + */ +function mergeAbortSignals(a: AbortSignal, b: AbortSignal): AbortSignal { + const controller = new AbortController() + if (a.aborted || b.aborted) { controller.abort(); return controller.signal } + const abort = () => controller.abort() + a.addEventListener('abort', abort, { once: true }) + b.addEventListener('abort', abort, { once: true }) + return controller.signal +} + function addUsage(a: TokenUsage, b: TokenUsage): TokenUsage { return { input_tokens: a.input_tokens + b.input_tokens, @@ -298,11 +311,17 @@ export class Agent { const timeoutSignal = this.config.timeoutMs !== undefined && this.config.timeoutMs > 0 ? AbortSignal.timeout(this.config.timeoutMs) : undefined + // Merge caller-provided abortSignal with the timeout signal so that + // either cancellation source is respected. + const callerAbort = callerOptions?.abortSignal + const effectiveAbort = timeoutSignal && callerAbort + ? mergeAbortSignals(timeoutSignal, callerAbort) + : timeoutSignal ?? callerAbort const runOptions: RunOptions = { ...callerOptions, onMessage: internalOnMessage, ...(needsRunId ? { runId: generateRunId() } : undefined), - ...(timeoutSignal ? { abortSignal: timeoutSignal } : undefined), + ...(effectiveAbort ? { abortSignal: effectiveAbort } : undefined), } const result = await runner.run(messages, runOptions) diff --git a/src/tool/text-tool-extractor.ts b/src/tool/text-tool-extractor.ts index 79e3197..8c64d1d 100644 --- a/src/tool/text-tool-extractor.ts +++ b/src/tool/text-tool-extractor.ts @@ -211,15 +211,6 @@ export function extractToolCallsFromText( const results: ToolUseBlock[] = [] for (const obj of jsonObjects) { - // Handle array of tool calls - if (Array.isArray(obj)) { - for (const item of obj) { - const block = parseToolCallJSON(item, nameSet) - if (block !== null) results.push(block) - } - continue - } - const block = parseToolCallJSON(obj, nameSet) if (block !== null) results.push(block) }