@prestyj/agent 4.4.0 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/agent.ts","../src/agent-loop.ts"],"sourcesContent":["// Core\nexport { Agent, AgentStream } from \"./agent.js\";\nexport {\n agentLoop,\n isAbortError,\n isContextOverflow,\n isBillingError,\n isUsageLimitError,\n setStreamDiagnostic,\n} from \"./agent-loop.js\";\nexport type { StreamDiagnosticFn } from \"./agent-loop.js\";\n\n// Types\nexport type {\n StructuredToolResult,\n ToolExecuteResult,\n ToolContext,\n ToolExecutionMode,\n AgentTool,\n AgentTextDeltaEvent,\n AgentThinkingDeltaEvent,\n AgentToolCallStartEvent,\n AgentToolCallUpdateEvent,\n AgentToolCallEndEvent,\n AgentToolCallDeltaEvent,\n AgentServerToolCallEvent,\n AgentServerToolResultEvent,\n AgentSteeringMessageEvent,\n AgentFollowUpMessageEvent,\n AgentRetryEvent,\n AgentTurnEndEvent,\n AgentDoneEvent,\n AgentErrorEvent,\n AgentEvent,\n AgentOptions,\n AgentResult,\n} from \"./types.js\";\n","import { EventStream, type Message } from \"@prestyj/ai\";\nimport { agentLoop } from \"./agent-loop.js\";\nimport type { AgentEvent, AgentOptions, AgentResult } from \"./types.js\";\n\n// ── AgentStream ─────────────────────────────────────────────\n\n/**\n * Dual-nature result: async iterable for streaming events,\n * thenable for awaiting the final AgentResult.\n *\n * ```ts\n * // Stream events\n * for await (const event of agent.prompt(\"hello\")) { ... }\n *\n * // Or just await the result\n * const result = await agent.prompt(\"hello\");\n * ```\n */\nexport class AgentStream implements AsyncIterable<AgentEvent> {\n private events: EventStream<AgentEvent>;\n private resultPromise: Promise<AgentResult>;\n private resolveResult!: (r: AgentResult) => void;\n private rejectResult!: (e: Error) => void;\n private hasConsumer = false;\n\n constructor(generator: AsyncGenerator<AgentEvent, AgentResult>, onDone: () => void) {\n this.events = new EventStream<AgentEvent>();\n this.resultPromise = new Promise<AgentResult>((resolve, reject) => {\n this.resolveResult = resolve;\n this.rejectResult = reject;\n });\n this.pump(generator, onDone);\n }\n\n private async pump(\n generator: AsyncGenerator<AgentEvent, AgentResult>,\n onDone: () => void,\n ): Promise<void> {\n try {\n let next = await generator.next();\n while (!next.done) {\n this.events.push(next.value);\n next = await generator.next();\n }\n this.events.close();\n this.resolveResult(next.value);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.events.abort(error);\n this.rejectResult(error);\n } finally {\n onDone();\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<AgentEvent> {\n this.hasConsumer = true;\n return this.events[Symbol.asyncIterator]();\n }\n\n then<TResult1 = AgentResult, TResult2 = never>(\n onfulfilled?: ((value: AgentResult) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n this.drainEvents().catch(() => {});\n return this.resultPromise.then(onfulfilled, onrejected);\n }\n\n private async drainEvents(): Promise<void> {\n if (this.hasConsumer) return;\n this.hasConsumer = true;\n for await (const _ of this.events) {\n // consume silently\n }\n }\n}\n\n// ── Agent ───────────────────────────────────────────────────\n\nexport class Agent {\n private messages: Message[] = [];\n private _running = false;\n private options: AgentOptions;\n private steeringQueue: Message[] = [];\n private followUpQueue: Message[] = [];\n\n constructor(options: AgentOptions) {\n this.options = options;\n if (options.system) {\n this.messages.push({ role: \"system\", content: options.system });\n }\n if (options.priorMessages && options.priorMessages.length > 0) {\n this.messages.push(...options.priorMessages);\n }\n }\n\n /** Snapshot of the current message history. Used for session persistence. */\n getMessages(): Message[] {\n return [...this.messages];\n }\n\n /**\n * Swap the abort signal used for subsequent prompts. Call this after\n * `controller.abort()` so the next prompt() call gets a fresh, unaborted\n * signal — without losing message history.\n */\n setSignal(signal: AbortSignal | undefined): void {\n this.options = { ...this.options, signal };\n }\n\n get running(): boolean {\n return this._running;\n }\n\n /** Queue a steering message for injection after current tool execution completes. */\n steer(msg: Message): void {\n this.steeringQueue.push(msg);\n }\n\n /** Queue a follow-up message for injection when the agent would otherwise stop. */\n followUp(msg: Message): void {\n this.followUpQueue.push(msg);\n }\n\n prompt(content: string): AgentStream {\n if (this._running) {\n throw new Error(\"Agent is already running\");\n }\n this._running = true;\n\n this.messages.push({ role: \"user\", content });\n\n const optionsWithQueues: AgentOptions = {\n ...this.options,\n getSteeringMessages: async () => {\n const callerResult = (await this.options.getSteeringMessages?.()) ?? [];\n const queued = this.steeringQueue.splice(0);\n const all = [...(callerResult ?? []), ...queued];\n return all.length > 0 ? all : null;\n },\n getFollowUpMessages: async () => {\n const callerResult = (await this.options.getFollowUpMessages?.()) ?? [];\n const queued = this.followUpQueue.splice(0);\n const all = [...(callerResult ?? []), ...queued];\n return all.length > 0 ? all : null;\n },\n };\n\n const generator = agentLoop(this.messages, optionsWithQueues);\n return new AgentStream(generator, () => {\n this._running = false;\n });\n }\n}\n","import { ZodError, prettifyError } from \"zod\";\nimport {\n stream,\n EventStream,\n type Message,\n type ToolCall,\n type ToolResult,\n type ToolResultContent,\n type Usage,\n type ContentPart,\n type AssistantMessage,\n isHardBillingMessage,\n} from \"@prestyj/ai\";\nimport type {\n AgentEvent,\n AgentOptions,\n AgentResult,\n AgentTool,\n ToolContext,\n ToolExecuteResult,\n StructuredToolResult,\n} from \"./types.js\";\n\nconst DEFAULT_MAX_TURNS = 300;\n\n/**\n * Lightweight stream diagnostic callback. When set, the agent loop calls this\n * at every phase boundary with timing and state info. This lets the hosting\n * app (ezcoder, come-alive, etc.) log stall diagnostics without the agent\n * package needing fs/process dependencies.\n */\nexport type StreamDiagnosticFn = (phase: string, data?: Record<string, unknown>) => void;\n\n/** Global diagnostic hook — set by the hosting app before calling agentLoop. */\nlet _diagFn: StreamDiagnosticFn | null = null;\n\n/** Register a diagnostic callback for stream stall tracing. */\nexport function setStreamDiagnostic(fn: StreamDiagnosticFn | null): void {\n _diagFn = fn;\n}\n\nfunction diag(phase: string, data?: Record<string, unknown>): void {\n _diagFn?.(phase, data);\n}\n\n/**\n * Detect abort errors — user-initiated cancellation or AbortSignal.\n * These should be caught and handled gracefully, not re-thrown.\n */\nexport function isAbortError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (err.name === \"AbortError\") return true;\n const msg = err.message.toLowerCase();\n return msg.includes(\"aborted\") || msg.includes(\"abort\");\n}\n\n/**\n * Detect context window overflow errors from LLM providers.\n *\n * Patterns drawn from observed errors across Anthropic, OpenAI, OpenAI Codex,\n * Bedrock, Ollama, and OpenAI-compatible Chinese providers (GLM, Kimi, MiniMax).\n */\nexport function isContextOverflow(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n // 402 is always credit/payment exhaustion — never a context overflow. Guards\n // against e.g. OpenRouter's 402 \"requires more credits, or fewer max_tokens...\n // you requested up to N tokens\" being misread as overflow and triggering\n // futile compaction retries.\n const overflowStatus = (err as Error & { statusCode?: unknown }).statusCode;\n if (overflowStatus === 402) return false;\n if (isBillingError(err)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"prompt is too long\") ||\n msg.includes(\"prompt too long\") ||\n msg.includes(\"input is too long\") ||\n msg.includes(\"context_length_exceeded\") ||\n msg.includes(\"context_window_exceeded\") ||\n msg.includes(\"maximum context length\") ||\n msg.includes(\"exceeds model context window\") ||\n msg.includes(\"exceeds the context window\") ||\n msg.includes(\"content_too_large\") ||\n msg.includes(\"request_too_large\") ||\n msg.includes(\"reduce the length\") ||\n msg.includes(\"please shorten\") ||\n (msg.includes(\"token\") && msg.includes(\"exceed\"))\n );\n}\n\nexport interface ContextOverflowDetails {\n observedTokens?: number;\n observedLimit?: number;\n}\n\nfunction parseOverflowNumber(value: string): number {\n return Number(value.replace(/[,_\\s]/g, \"\"));\n}\n\n/** Extract provider-reported token counts from common context overflow messages. */\nexport function extractContextOverflowDetails(err: unknown): ContextOverflowDetails {\n if (!(err instanceof Error)) return {};\n const text = err.message;\n const patterns: Array<{ regex: RegExp; tokensGroup: number; limitGroup: number }> = [\n // Anthropic/OpenAI-compatible: \"203456 tokens > 200000 maximum\"\n {\n regex: /([\\d,_.\\s]+)\\s*tokens?\\s*>\\s*([\\d,_.\\s]+)\\s*(?:maximum|max|limit)?/i,\n tokensGroup: 1,\n limitGroup: 2,\n },\n // OpenAI: \"maximum context length is 128000 tokens ... resulted in 130000 tokens\"\n {\n regex:\n /maximum context length is\\s*([\\d,_.\\s]+)\\s*tokens?[\\s\\S]*?resulted in\\s*([\\d,_.\\s]+)\\s*tokens?/i,\n tokensGroup: 2,\n limitGroup: 1,\n },\n // Generic: \"130000 input tokens exceeds 128000 token limit\"\n {\n regex:\n /([\\d,_.\\s]+)\\s*(?:input\\s*)?tokens?[\\s\\S]{0,80}?exceeds?[\\s\\S]{0,80}?([\\d,_.\\s]+)\\s*(?:token\\s*)?(?:limit|maximum|max)/i,\n tokensGroup: 1,\n limitGroup: 2,\n },\n ];\n\n for (const pattern of patterns) {\n const match = text.match(pattern.regex);\n if (!match) continue;\n const observedTokens = parseOverflowNumber(match[pattern.tokensGroup] ?? \"\");\n const observedLimit = parseOverflowNumber(match[pattern.limitGroup] ?? \"\");\n return {\n ...(Number.isFinite(observedTokens) && observedTokens > 0 ? { observedTokens } : {}),\n ...(Number.isFinite(observedLimit) && observedLimit > 0 ? { observedLimit } : {}),\n };\n }\n\n return {};\n}\n\n/**\n * Detect billing/quota errors — these should NOT be retried.\n * GLM returns HTTP 429 with \"Insufficient balance\" for quota exhaustion.\n */\nexport function isBillingError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n // HTTP 402 (Payment Required) is always a hard credit/payment stop across our\n // provider set (DeepSeek, OpenRouter, ...). Never retriable.\n const statusCode = (err as Error & { statusCode?: unknown }).statusCode;\n if (statusCode === 402) return true;\n // Shared marker list (single source of truth in @prestyj/ai) so the\n // provider boundary and this classifier can't drift apart.\n return isHardBillingMessage(err.message);\n}\n\n/**\n * Detect subscription/plan usage-window exhaustion (e.g. an Anthropic OAuth\n * plan running out of usage). Unlike a transient per-minute 429, this does NOT\n * clear with a quick retry — the user must wait for the window to reset — so the\n * loop surfaces it immediately instead of retrying for minutes. Matches the\n * canonical message gg-ai stamps onto the provider error.\n */\nexport function isUsageLimitError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n return /usage limit reached/i.test(err.message);\n}\n\n/**\n * Read a provider-stated reset time off the error and convert it to a delay in\n * milliseconds from now. Providers like Gemini return a short `retryDelay` for a\n * transient per-minute throttle, which gg-ai stamps onto the ProviderError as\n * `resetsAt` (unix seconds). Returns undefined when absent or already elapsed.\n */\nexport function serverResetDelayMs(err: unknown): number | undefined {\n if (!(err instanceof Error)) return undefined;\n const resetsAt = (err as Error & { resetsAt?: unknown }).resetsAt;\n if (typeof resetsAt !== \"number\" || !Number.isFinite(resetsAt)) return undefined;\n const delayMs = resetsAt * 1000 - Date.now();\n return delayMs > 0 ? delayMs : undefined;\n}\n\n/**\n * Detect overloaded/rate-limit errors from LLM providers.\n * HTTP 429 (rate limit) or 529/503 (overloaded).\n * Excludes billing/quota errors which won't resolve with a retry.\n */\n/**\n * Detect tool pairing errors — orphaned tool_use or tool_result blocks.\n * These are 400 errors that can be recovered by repairing the message history.\n */\nexport function isToolPairingError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n return (\n (msg.includes(\"tool_use\") && msg.includes(\"tool_result\")) ||\n msg.includes(\"unexpected `tool_use_id`\") ||\n msg.includes(\"tool_use ids found without\") ||\n // Moonshot/OpenAI-compatible: \"tool call id <id> is not found\"\n (msg.includes(\"tool call id\") && msg.includes(\"is not found\"))\n );\n}\n\n/**\n * Detect Anthropic's thinking-block integrity errors. These 400s fire when a\n * signed `thinking`/`redacted_thinking` block in the latest assistant message\n * can't be validated — typically a partial/invalid signature from an\n * interrupted stream, or a block whose position shifted. Recoverable once by\n * stripping thinking blocks from the message history and re-sending.\n */\nexport function isThinkingBlockError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n if (!msg.includes(\"thinking\")) return false;\n return (\n msg.includes(\"cannot be modified\") ||\n msg.includes(\"must remain as they were\") ||\n (msg.includes(\"signature\") && msg.includes(\"invalid\")) ||\n // \"Expected `thinking` or `redacted_thinking`, but found `text`\"\n (msg.includes(\"expected\") && msg.includes(\"but found\"))\n );\n}\n\n/**\n * Distinguish rate-limit (HTTP 429), server-side overload (HTTP 529), and\n * transient provider 5xx/API failures. Returns null for errors that should not\n * enter the retry bucket. All kinds use the same backoff schedule, but the UI\n * shows different copy and the log line records the true cause.\n */\nexport function classifyOverload(\n err: unknown,\n): \"rate_limit\" | \"overloaded\" | \"provider_error\" | null {\n if (!(err instanceof Error)) return null;\n if (isBillingError(err)) return null;\n // Usage-window exhaustion is not retriable — keep it out of the backoff bucket.\n if (isUsageLimitError(err)) return null;\n const msg = err.message.toLowerCase();\n const errorWithStatus = err as Error & { statusCode?: unknown };\n const statusCode =\n typeof errorWithStatus.statusCode === \"number\" ? errorWithStatus.statusCode : undefined;\n // 402 is billing/credits — never retry, never treat as overload.\n if (statusCode === 402) return null;\n if (\n statusCode === 429 ||\n msg.includes(\"rate_limit\") ||\n msg.includes(\"rate limit\") ||\n msg.includes(\"too many requests\") ||\n msg.includes(\"429\")\n ) {\n return \"rate_limit\";\n }\n if (statusCode === 529 || msg.includes(\"overloaded\") || msg.includes(\"529\")) {\n return \"overloaded\";\n }\n if (\n statusCode === 500 ||\n statusCode === 502 ||\n statusCode === 503 ||\n statusCode === 504 ||\n msg.includes(\"api_error\") ||\n msg.includes(\"server_error\") ||\n msg.includes(\"internal server error\") ||\n msg.includes(\"bad gateway\") ||\n msg.includes(\"service unavailable\") ||\n msg.includes(\"gateway timeout\")\n ) {\n return \"provider_error\";\n }\n return null;\n}\n\nexport function isOverloaded(err: unknown): boolean {\n return classifyOverload(err) !== null;\n}\n\n/**\n * Detect malformed-stream errors — the SDK's SSE decoder threw a JSON parse\n * error mid-stream, typically because a chunk was truncated or corrupted by\n * an intermediary (CDN, proxy). Same class of transport failure as a stall:\n * replaying the request — and ideally flipping to non-streaming — recovers.\n */\nexport function isMalformedStream(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (err.name === \"SyntaxError\") return true;\n const cause = (err as { cause?: unknown }).cause;\n if (cause instanceof Error && cause.name === \"SyntaxError\") return true;\n const msg = err.message;\n // V8 JSON.parse error messages: \"Expected ... in JSON at position N\"\n // and \"Unexpected token ... in JSON at position N\"\n return /\\bin JSON at position \\d+/i.test(msg);\n}\n\n/**\n * Detect socket-level transport failures — the remote peer (or an\n * intermediary) closed the TCP connection mid-stream before the response\n * finished. Surfaces as `TypeError: terminated` from undici/fetch, or as\n * `ECONNRESET` / `socket hang up` / `UND_ERR_SOCKET` from the underlying\n * Node http layer. Undici nests the real cause one or more levels deep,\n * so we walk the `.cause` chain. Same recovery as a stall: replay the\n * request, optionally as non-streaming.\n */\nexport function isTransportFailure(err: unknown): boolean {\n const codes = new Set([\n \"ECONNRESET\",\n \"ECONNREFUSED\",\n \"ECONNABORTED\",\n \"ETIMEDOUT\",\n \"EPIPE\",\n \"EHOSTUNREACH\",\n \"ENETUNREACH\",\n \"ENOTFOUND\",\n \"UND_ERR_SOCKET\",\n \"UND_ERR_CONNECT_TIMEOUT\",\n \"UND_ERR_HEADERS_TIMEOUT\",\n \"UND_ERR_BODY_TIMEOUT\",\n \"UND_ERR_RESPONSE_STATUS_CODE\",\n \"UND_ERR_REQ_CONTENT_LENGTH_MISMATCH\",\n \"UND_ERR_RES_CONTENT_LENGTH_MISMATCH\",\n ]);\n const messages = [\n /^terminated$/i,\n /\\bother side closed\\b/i,\n /\\bsocket hang up\\b/i,\n /\\bfetch failed\\b/i,\n /\\bbody timeout error\\b/i,\n /\\bsse stream disconnected\\b/i,\n /\\bfailed to reconnect sse stream\\b/i,\n ];\n const seen = new Set<unknown>();\n let cur: unknown = err;\n while (cur && typeof cur === \"object\" && !seen.has(cur)) {\n seen.add(cur);\n const e = cur as { code?: unknown; message?: unknown; cause?: unknown };\n if (typeof e.code === \"string\" && codes.has(e.code)) return true;\n if (typeof e.message === \"string\") {\n for (const re of messages) if (re.test(e.message)) return true;\n }\n cur = e.cause;\n }\n return false;\n}\n\n/**\n * Promise-returning sleep that rejects with AbortError if `signal` fires.\n * Used by retry backoffs so ESC/Ctrl+C cancel immediately instead of having\n * to wait out the full delay (up to 30s per overload retry × 10 retries).\n */\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(new DOMException(\"Aborted\", \"AbortError\"));\n }\n return new Promise<void>((resolve, reject) => {\n let onAbort: (() => void) | null = null;\n const timer = setTimeout(() => {\n if (onAbort) signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n onAbort = () => {\n clearTimeout(timer);\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nexport async function* agentLoop(\n messages: Message[],\n options: AgentOptions,\n): AsyncGenerator<AgentEvent, AgentResult> {\n const maxTurns = options.maxTurns ?? DEFAULT_MAX_TURNS;\n const maxContinuations = options.maxContinuations ?? 5;\n const toolMap = new Map<string, AgentTool>((options.tools ?? []).map((t) => [t.name, t]));\n\n const totalUsage: Usage = { inputTokens: 0, outputTokens: 0 };\n let turn = 0;\n let firstTurn = true;\n let consecutivePauses = 0;\n let toolPairingRepaired = false;\n let thinkingBlocksStripped = false;\n let overloadRetries = 0;\n let emptyResponseRetries = 0;\n let stallRetries = 0;\n let overflowCompactionAttempts = 0;\n let toolResultTruncationAttempted = false;\n const invalidToolArgumentCounts = new Map<string, number>();\n // Non-streaming fallback mode. After repeated stream stalls, flip to a\n // plain non-streaming request/response -- often survives broken SSE\n // connections (transient CDN / proxy issues) that streaming retries cannot.\n let useNonStreamingFallback = false;\n const MAX_OVERLOAD_RETRIES = 10;\n const MAX_EMPTY_RESPONSE_RETRIES = 2;\n const MAX_STALL_RETRIES = 5;\n const MAX_OVERFLOW_COMPACTIONS = 2;\n // After this many streaming stalls in a row, switch to non-streaming mode\n // for the remaining stall retries. Keeps the first two retries fast (the\n // cheap \"transient glitch\" case) before paying for a full response round-trip.\n const STALL_RETRIES_BEFORE_NON_STREAMING = 2;\n const STALL_DELAY_MS = 1_000; // Brief pause before retry -- just enough to avoid tight loops\n const OVERLOAD_BASE_DELAY_MS = 2_000;\n const OVERLOAD_MAX_DELAY_MS = 30_000;\n const STREAM_FIRST_EVENT_TIMEOUT_MS = 45_000; // 45s to get first event (Opus thinks long)\n // 90s of true API silence between events once streaming starts. This measures\n // only time the *API* was quiet -- the timer is armed after we finish yielding\n // each event downstream, so slow UI/consumer render time is excluded (see the\n // resetIdleTimer() call after the yield, below). 30s here previously caused\n // false aborts on large `write`/`edit` tool-call streams when the Ink UI lagged\n // tens of seconds behind. 90s matches Claude Code's default idle watchdog.\n const STREAM_IDLE_TIMEOUT_MS = 90_000; // 90s of API silence between events\n // Anthropic models can pause 10-20s mid-stream while computing the next chunk\n // (e.g. generating tool call args for a large write). 10s was too aggressive\n // and caused false \"stream stalled\" errors, especially in plan mode.\n const STREAM_HARD_TIMEOUT_MS = 90_000; // 90s absolute cap before output starts\n // Once output events (text_delta) are actively streaming, extend the hard\n // timeout -- long responses (plan mode, detailed explanations) can legitimately\n // take 2-3+ minutes while events flow continuously.\n const STREAM_OUTPUT_HARD_TIMEOUT_MS = 300_000; // 5min hard cap once output is flowing\n // Reasoning models (MiMo) can pause 3-5 minutes between thinking and output\n // generation. Once we've seen thinking events, extend timeouts significantly.\n const STREAM_THINKING_IDLE_TIMEOUT_MS = 300_000; // 5min idle after thinking\n const STREAM_THINKING_HARD_TIMEOUT_MS = 600_000; // 10min hard cap with thinking\n // Non-streaming mode has no per-event idle -- the entire response arrives in\n // one HTTP round-trip. Use a single generous hard cap instead. This matches\n // Claude Code's v2.1.110/111 behaviour: cap non-streaming retries so API\n // unreachability doesn't cause multi-minute hangs, but not so aggressively\n // that slow-but-healthy backends get killed.\n const NON_STREAMING_HARD_TIMEOUT_MS = 300_000; // 5min for full non-streaming response\n // Runaway tool-call circuit breaker. When a model glitches mid-tool-call it\n // can emit tens of thousands of toolcall_delta events without ever closing,\n // burning the entire stall-retry budget (~25 min) on what is clearly a\n // non-recoverable model error. Cap accumulated arg chars and event count;\n // exceeding either is a hard, non-retriable failure. Thresholds are generous\n // enough to allow legitimate large file writes through `write`.\n const MAX_TOOLCALL_DELTA_CHARS = 1_000_000; // 1 MB of accumulated tool-call args\n const MAX_TOOLCALL_DELTA_EVENTS = 20_000; // 20k delta events in one stream\n\n try {\n while (turn < maxTurns) {\n options.signal?.throwIfAborted();\n turn++;\n\n // Estimate message payload size for diagnostics\n let msgChars = 0;\n for (const m of messages) {\n if (typeof m.content === \"string\") msgChars += m.content.length;\n else if (Array.isArray(m.content)) {\n for (const p of m.content) {\n if (\"text\" in p && typeof p.text === \"string\") msgChars += p.text.length;\n if (\"content\" in p && typeof p.content === \"string\") msgChars += p.content.length;\n }\n }\n }\n diag(\"turn_start\", {\n turn,\n messages: messages.length,\n chars: msgChars,\n provider: options.provider,\n model: options.model,\n });\n\n // ── Initial steering poll: catch messages queued before the first LLM call ──\n if (firstTurn && options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n }\n }\n firstTurn = false;\n\n // ── Mid-loop context transform (compaction / truncation) ──\n if (options.transformContext) {\n diag(\"transform_start\");\n const transformed = await options.transformContext(messages);\n if (transformed !== messages) {\n diag(\"transform_compacted\", {\n before: messages.length,\n after: transformed.length,\n });\n messages.length = 0;\n messages.push(...transformed);\n }\n diag(\"transform_end\");\n }\n\n // ── Repair tool pairing: ensure every tool_use has an adjacent tool_result ──\n repairToolPairingAdjacent(messages);\n\n // ── Call LLM with overflow recovery ──\n let response;\n // Per-attempt abort controller: allows idle timeout to abort the stream\n // without affecting the caller's signal. The caller's abort is forwarded.\n const streamController = new AbortController();\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\n let hardTimer: ReturnType<typeof setTimeout> | null = null;\n let idleTimedOut = false;\n\n // Stream event counters — declared here so timeout callbacks can access them\n let streamEventCount = 0;\n let lastEventTime = Date.now();\n let streamCallStart = Date.now();\n // Track event types for diagnostics — shows what arrived before a stall\n const eventTypeCounts: Record<string, number> = {};\n let lastEventType = \"\";\n // Runaway tool-call detection — accumulated across all toolcall_delta\n // events in this stream attempt. When tripped we abort the stream and\n // bail out without retrying (the model has glitched, retries won't help).\n let toolcallDeltaChars = 0;\n let toolcallDeltaCount = 0;\n let runawayDetected: { kind: \"chars\" | \"events\"; chars: number; events: number } | null =\n null;\n // Track consumer processing time — helps distinguish \"API stopped sending\"\n // from \"our consumer was slow to pull the next event\"\n let lastYieldEndTime = Date.now();\n let maxConsumerLagMs = 0;\n\n // Forward caller abort to the per-attempt controller\n const forwardAbort = () => streamController.abort();\n options.signal?.addEventListener(\"abort\", forwardAbort, { once: true });\n\n // Three-phase idle timeout:\n // - Before first event: STREAM_FIRST_EVENT_TIMEOUT_MS (45s) -- Opus can\n // take 30s+ to start on large contexts, that's not a stall.\n // - After output event (text_delta, server_toolcall): STREAM_IDLE_TIMEOUT_MS\n // (10s) -- once output is streaming, 10s of silence is dead. Retry fast.\n // - After thinking events only: STREAM_THINKING_IDLE_TIMEOUT_MS (5min) --\n // reasoning models (MiMo) can pause minutes between thinking and output.\n //\n // In non-streaming fallback mode the entire response arrives in a single\n // HTTP round-trip, so the idle timer is disabled -- only the hard timeout\n // applies. Synthesized events all arrive at once when the response returns.\n let hasReceivedEvent = false;\n let hasReceivedThinking = false;\n const resetIdleTimer = () => {\n if (useNonStreamingFallback) return; // no inter-event idle in non-streaming mode\n if (idleTimer) clearTimeout(idleTimer);\n const timeoutMs = hasReceivedEvent\n ? STREAM_IDLE_TIMEOUT_MS\n : hasReceivedThinking\n ? STREAM_THINKING_IDLE_TIMEOUT_MS\n : STREAM_FIRST_EVENT_TIMEOUT_MS;\n idleTimer = setTimeout(() => {\n diag(\"idle_timeout_fired\", {\n events: streamEventCount,\n sinceLastEventMs: Date.now() - lastEventTime,\n lastEventType,\n maxConsumerLagMs,\n phase: hasReceivedEvent\n ? \"mid_stream\"\n : hasReceivedThinking\n ? \"post_thinking\"\n : \"first_event\",\n eventTypes: eventTypeCounts,\n });\n idleTimedOut = true;\n streamController.abort();\n }, timeoutMs);\n };\n\n // Hard timeout: absolute cap per LLM call. Safety net for streams that\n // keep sending sparse events (e.g. keep-alive pings) but never complete.\n // Extended dynamically when thinking events arrive (see thinking_delta handler).\n // Non-streaming fallback uses a single larger cap since there's no stream\n // to observe -- just wait for the full response up to the cap.\n let hardTimeoutMs = useNonStreamingFallback\n ? NON_STREAMING_HARD_TIMEOUT_MS\n : STREAM_HARD_TIMEOUT_MS;\n hardTimer = setTimeout(() => {\n diag(\"hard_timeout_fired\", {\n events: typeof streamEventCount !== \"undefined\" ? streamEventCount : 0,\n nonStreaming: useNonStreamingFallback,\n });\n idleTimedOut = true;\n streamController.abort();\n }, hardTimeoutMs);\n\n try {\n diag(\"stream_call\", { nonStreaming: useNonStreamingFallback });\n streamCallStart = Date.now();\n const result = stream({\n provider: options.provider,\n model: options.model,\n messages,\n tools: options.tools,\n serverTools: options.serverTools,\n webSearch: options.webSearch,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n thinking: options.thinking,\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n signal: streamController.signal,\n accountId: options.accountId,\n projectId: options.projectId,\n cacheRetention: options.cacheRetention,\n promptCacheKey: options.promptCacheKey,\n serviceTier: options.serviceTier,\n supportsImages: options.supportsImages,\n supportsVideo: options.supportsVideo,\n compaction: options.compaction,\n clearToolUses: options.clearToolUses,\n userAgent: options.userAgent,\n defaultHeaders: options.defaultHeaders,\n // Flip to non-streaming fallback after repeated stream stalls.\n ...(useNonStreamingFallback ? { streaming: false } : {}),\n });\n diag(\"stream_created\", { setupMs: Date.now() - streamCallStart });\n\n // Suppress unhandled rejection if the iterator path throws first\n result.response.catch(() => {});\n\n // Forward streaming deltas — reset idle timer on each event\n streamEventCount = 0;\n hasReceivedEvent = false;\n lastEventTime = Date.now();\n streamCallStart = Date.now();\n // Reset to streamCallStart so the first event's consumerLag reflects\n // network/provider latency, not the time spent before stream() returned.\n lastYieldEndTime = Date.now();\n resetIdleTimer();\n for await (const event of result) {\n // Measure consumer lag: time between finishing previous yield and\n // receiving this event. For event #1 this still includes network/\n // provider latency; for subsequent events it isolates how long\n // React/UI rendering held up the next pull.\n const pullTime = Date.now();\n const consumerLag = pullTime - lastYieldEndTime;\n // Only track mid-stream lag — first event lag is dominated by\n // server-side TTFB and would mask real UI starvation issues.\n if (streamEventCount > 0 && consumerLag > maxConsumerLagMs) {\n maxConsumerLagMs = consumerLag;\n }\n\n streamEventCount++;\n eventTypeCounts[event.type] = (eventTypeCounts[event.type] ?? 0) + 1;\n lastEventType = event.type;\n\n // Flip to mid-stream timeout on confirmed output events — text\n // deltas, completed tool calls, and tool call deltas (large file\n // writes can stream toolcall_delta for minutes without any text_delta).\n // Reasoning models (MiMo) are handled separately below — they can\n // stream hundreds of thinking events then pause minutes before output.\n if (\n (event.type === \"text_delta\" ||\n event.type === \"server_toolcall\" ||\n event.type === \"toolcall_delta\") &&\n !hasReceivedEvent\n ) {\n hasReceivedEvent = true;\n // Extend hard timeout now that output is actively streaming.\n // Long responses (plan mode, detailed code) can exceed 90s while\n // events flow continuously — the idle timeout (10s) catches real stalls.\n if (hardTimer && hardTimeoutMs < STREAM_OUTPUT_HARD_TIMEOUT_MS) {\n clearTimeout(hardTimer);\n hardTimeoutMs = STREAM_OUTPUT_HARD_TIMEOUT_MS;\n hardTimer = setTimeout(() => {\n diag(\"hard_timeout_fired\", { events: streamEventCount });\n idleTimedOut = true;\n streamController.abort();\n }, hardTimeoutMs);\n }\n }\n // Track thinking events — extends idle timeout and hard timeout\n // so reasoning models aren't killed during thinking→output transition.\n if (event.type === \"thinking_delta\" && !hasReceivedThinking) {\n hasReceivedThinking = true;\n // Extend the hard timeout now that we know the model is reasoning\n if (hardTimer) clearTimeout(hardTimer);\n hardTimeoutMs = STREAM_THINKING_HARD_TIMEOUT_MS;\n hardTimer = setTimeout(() => {\n diag(\"hard_timeout_fired\", { events: streamEventCount });\n idleTimedOut = true;\n streamController.abort();\n }, hardTimeoutMs);\n }\n\n const now = Date.now();\n const gap = now - lastEventTime;\n // Log first event and any suspiciously long gaps\n if (streamEventCount === 1) {\n diag(\"first_event\", { type: event.type, ttfMs: now - streamCallStart });\n } else if (gap > 3000) {\n diag(\"slow_gap\", {\n type: event.type,\n gapMs: gap,\n eventNum: streamEventCount,\n sinceStartMs: now - streamCallStart,\n });\n }\n lastEventTime = now;\n // The event is in hand -- the API has proven liveness, so stop the idle\n // timer for the duration of downstream processing. We re-arm it after\n // the yield completes (see below) so the idle window measures only API\n // silence, never the time our consumer/UI spent rendering this event.\n if (idleTimer) {\n clearTimeout(idleTimer);\n idleTimer = null;\n }\n if (event.type === \"text_delta\") {\n yield { type: \"text_delta\" as const, text: event.text };\n } else if (event.type === \"thinking_delta\") {\n yield { type: \"thinking_delta\" as const, text: event.text };\n } else if (event.type === \"server_toolcall\") {\n yield {\n type: \"server_tool_call\" as const,\n id: event.id,\n name: event.name,\n input: event.input,\n };\n } else if (event.type === \"server_toolresult\") {\n yield {\n type: \"server_tool_result\" as const,\n toolUseId: event.toolUseId,\n resultType: event.resultType,\n data: event.data,\n };\n } else if (event.type === \"toolcall_delta\") {\n const chunkChars = event.argsJson?.length ?? 0;\n toolcallDeltaChars += chunkChars;\n toolcallDeltaCount++;\n if (\n !runawayDetected &&\n (toolcallDeltaChars > MAX_TOOLCALL_DELTA_CHARS ||\n toolcallDeltaCount > MAX_TOOLCALL_DELTA_EVENTS)\n ) {\n runawayDetected = {\n kind: toolcallDeltaChars > MAX_TOOLCALL_DELTA_CHARS ? \"chars\" : \"events\",\n chars: toolcallDeltaChars,\n events: toolcallDeltaCount,\n };\n diag(\"runaway_toolcall_detected\", {\n ...runawayDetected,\n provider: options.provider,\n model: options.model,\n });\n streamController.abort();\n }\n yield {\n type: \"toolcall_delta\" as const,\n chars: chunkChars,\n };\n }\n lastYieldEndTime = Date.now();\n // Re-arm the idle timer only now that we're done yielding -- the\n // countdown to the next event excludes the render time above.\n resetIdleTimer();\n }\n\n diag(\"stream_done\", {\n events: streamEventCount,\n totalMs: Date.now() - streamCallStart,\n maxConsumerLagMs,\n eventTypes: eventTypeCounts,\n });\n response = await result.response;\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n diag(\"stream_error\", {\n error: errMsg.slice(0, 200),\n events: streamEventCount,\n totalMs: Date.now() - streamCallStart,\n idleTimedOut,\n aborted: !!options.signal?.aborted,\n eventTypes: eventTypeCounts,\n provider: options.provider,\n model: options.model,\n });\n // Subscription/plan usage-window exhaustion (e.g. Anthropic OAuth plan\n // out of usage). Not a transient throttle — retrying just burns minutes\n // before failing, which looks like a hang. Surface immediately so the\n // host UI shows a clear \"usage finished\" message. The conversation in\n // `messages` is left intact so the user can resume once it resets.\n if (isUsageLimitError(err)) {\n diag(\"usage_limit_reached\", {\n provider: options.provider,\n model: options.model,\n });\n throw err;\n }\n // Context overflow: try a forced compaction before giving up.\n // The pre-turn transformContext check uses estimated tokens, which can\n // underestimate code-heavy content. When the API confirms overflow we\n // compact unconditionally and retry the turn, capped at\n // MAX_OVERFLOW_COMPACTIONS to avoid loops when compaction can't reduce\n // enough (e.g. single huge user message).\n if (isContextOverflow(err)) {\n const overflowDetails = extractContextOverflowDetails(err);\n diag(\"context_overflow_detected\", {\n ...overflowDetails,\n error: errMsg.slice(0, 500),\n messages: messages.length,\n });\n\n const overflowToolResultMaxChars = Math.min(\n options.maxToolResultChars ?? 100_000,\n 100_000,\n );\n if (!toolResultTruncationAttempted) {\n toolResultTruncationAttempted = true;\n const truncated = truncateOversizedToolResults(messages, overflowToolResultMaxChars);\n diag(\"overflow_tool_result_truncation\", {\n truncated,\n maxChars: overflowToolResultMaxChars,\n });\n if (truncated) {\n yield {\n type: \"retry\" as const,\n reason: \"overflow_compact\" as const,\n attempt: overflowCompactionAttempts + 1,\n maxAttempts: MAX_OVERFLOW_COMPACTIONS,\n delayMs: 0,\n ...overflowDetails,\n silent: true,\n };\n turn--;\n continue;\n }\n }\n\n if (options.transformContext && overflowCompactionAttempts < MAX_OVERFLOW_COMPACTIONS) {\n overflowCompactionAttempts++;\n diag(\"overflow_compact_start\", {\n attempt: overflowCompactionAttempts,\n maxAttempts: MAX_OVERFLOW_COMPACTIONS,\n messages: messages.length,\n ...overflowDetails,\n });\n try {\n const compacted = await options.transformContext(messages, { force: true });\n if (compacted !== messages && compacted.length < messages.length) {\n messages.length = 0;\n messages.push(...compacted);\n diag(\"overflow_compact_success\", {\n attempt: overflowCompactionAttempts,\n messages: messages.length,\n ...overflowDetails,\n });\n yield {\n type: \"retry\" as const,\n reason: \"overflow_compact\" as const,\n attempt: overflowCompactionAttempts,\n maxAttempts: MAX_OVERFLOW_COMPACTIONS,\n delayMs: 0,\n ...overflowDetails,\n };\n turn--;\n continue;\n }\n diag(\"overflow_compact_noop\", {\n attempt: overflowCompactionAttempts,\n before: messages.length,\n after: compacted.length,\n ...overflowDetails,\n });\n } catch (compactErr) {\n diag(\"overflow_compact_failed\", {\n error: compactErr instanceof Error ? compactErr.message : String(compactErr),\n ...overflowDetails,\n });\n }\n }\n yield { type: \"error\" as const, error: err instanceof Error ? err : new Error(errMsg) };\n throw err;\n }\n // Transient provider errors (5xx), overload, and rate-limit: exponential backoff.\n const overloadKind = classifyOverload(err);\n if (overloadRetries < MAX_OVERLOAD_RETRIES && overloadKind) {\n overloadRetries++;\n // Honor a server-stated reset time (e.g. Gemini's RetryInfo.retryDelay)\n // when present, so we wait exactly as long as the provider asked\n // instead of guessing with blind exponential backoff. Fall back to\n // exponential backoff otherwise.\n const serverDelayMs = serverResetDelayMs(err);\n const delayMs =\n serverDelayMs !== undefined\n ? Math.min(serverDelayMs, OVERLOAD_MAX_DELAY_MS)\n : Math.min(\n OVERLOAD_BASE_DELAY_MS * 2 ** (overloadRetries - 1),\n OVERLOAD_MAX_DELAY_MS,\n );\n diag(\"retry\", {\n reason: overloadKind,\n attempt: overloadRetries,\n maxAttempts: MAX_OVERLOAD_RETRIES,\n delayMs,\n });\n yield {\n type: \"retry\" as const,\n reason: overloadKind,\n attempt: overloadRetries,\n maxAttempts: MAX_OVERLOAD_RETRIES,\n delayMs,\n };\n await abortableSleep(delayMs, options.signal);\n turn--; // Don't count the failed turn\n continue;\n }\n // Stream stall: the API connection hung without closing.\n // Malformed stream: the SDK's SSE decoder hit truncated/corrupted JSON.\n // Both are transport failures — retry with exponential backoff and flip\n // to non-streaming mode after STALL_RETRIES_BEFORE_NON_STREAMING attempts,\n // since broken SSE often recovers when replayed as plain HTTP.\n // Runaway tool-call: the model never closed a tool-call block and\n // blew past the size/count caps. Retrying just reproduces the loop,\n // so surface a clear error and stop. Checked before the abort branch\n // since we ourselves aborted the stream to break the runaway.\n if (runawayDetected) {\n diag(\"runaway_toolcall_aborted\", {\n ...runawayDetected,\n provider: options.provider,\n model: options.model,\n });\n const detail =\n runawayDetected.kind === \"chars\"\n ? `${(runawayDetected.chars / 1024).toFixed(0)} KB of tool-call arguments`\n : `${runawayDetected.events} tool-call delta events`;\n yield {\n type: \"error\" as const,\n error: new Error(\n `The model glitched mid-tool-call and produced ${detail} without closing the call. ` +\n `This is usually an upstream model bug — try the same request again or switch models. ` +\n `Your conversation is preserved.`,\n ),\n };\n break;\n }\n const malformed = isMalformedStream(err);\n const socketDrop = isTransportFailure(err);\n const transportFailure =\n (idleTimedOut || malformed || socketDrop) && !options.signal?.aborted;\n if (transportFailure && stallRetries < MAX_STALL_RETRIES) {\n stallRetries++;\n const cause = malformed\n ? \"malformed_stream\"\n : socketDrop\n ? \"socket_drop\"\n : \"stream_stall\";\n if (!useNonStreamingFallback && stallRetries >= STALL_RETRIES_BEFORE_NON_STREAMING) {\n useNonStreamingFallback = true;\n diag(\"non_streaming_fallback_enabled\", {\n stallRetries,\n provider: options.provider,\n model: options.model,\n cause,\n });\n }\n const delayMs = Math.min(STALL_DELAY_MS * 2 ** (stallRetries - 1), 8_000);\n diag(\"retry\", {\n reason: cause,\n attempt: stallRetries,\n maxAttempts: MAX_STALL_RETRIES,\n delayMs,\n events: streamEventCount,\n nonStreaming: useNonStreamingFallback,\n });\n yield {\n type: \"retry\" as const,\n reason: \"stream_stall\" as const,\n attempt: stallRetries,\n maxAttempts: MAX_STALL_RETRIES,\n delayMs,\n silent: stallRetries <= 2,\n };\n await abortableSleep(delayMs, options.signal);\n turn--; // Don't count the failed turn\n continue;\n }\n // Stream stall retries exhausted — surface a clear error so the UI\n // can distinguish \"gave up after stalls\" from \"completed normally\".\n if (transportFailure) {\n diag(\"stall_exhausted\", {\n stallRetries: MAX_STALL_RETRIES,\n provider: options.provider,\n model: options.model,\n });\n yield {\n type: \"error\" as const,\n error: new Error(\n `The API provider's stream stalled ${MAX_STALL_RETRIES} times — the provider may be experiencing capacity issues. ` +\n `Your conversation is preserved. Send another message to retry.`,\n ),\n };\n break;\n }\n // Tool pairing 400: orphaned tool_result or tool_use in message history.\n // Run repair and retry once — if repair can't fix it, surface the error.\n if (isToolPairingError(err) && !toolPairingRepaired) {\n toolPairingRepaired = true;\n diag(\"tool_pairing_repair\", { error: errMsg.slice(0, 200) });\n repairToolPairingAdjacent(messages);\n turn--;\n continue;\n }\n // Thinking-block integrity 400: a signed thinking block in the latest\n // assistant message couldn't be validated (commonly a partial signature\n // from an interrupted stream). Strip thinking from history — preserving\n // the reasoning as text — and retry once.\n if (isThinkingBlockError(err) && !thinkingBlocksStripped) {\n thinkingBlocksStripped = true;\n diag(\"thinking_block_repair\", { error: errMsg.slice(0, 200) });\n stripThinkingBlocks(messages);\n turn--;\n continue;\n }\n // Abort errors (user cancellation) — exit loop cleanly instead of\n // crashing the process with an unhandled rejection.\n if (isAbortError(err) || options.signal?.aborted) {\n diag(\"aborted\", { turn, provider: options.provider, model: options.model });\n break;\n }\n // Unhandled error — log before throwing so the crash is traceable\n diag(\"unhandled_error\", {\n error: errMsg.slice(0, 500),\n turn,\n provider: options.provider,\n model: options.model,\n });\n throw err;\n } finally {\n if (idleTimer) clearTimeout(idleTimer);\n if (hardTimer) clearTimeout(hardTimer);\n options.signal?.removeEventListener(\"abort\", forwardAbort);\n }\n\n overloadRetries = 0;\n stallRetries = 0;\n\n // Detect empty/degenerate responses — the API occasionally returns 0 tokens\n // with no content, or \"thinks\" without producing actionable output.\n // Reasoning models (MiMo, DeepSeek) may report outputTokens > 0 from\n // thinking alone while producing no text or tool calls — still a dud.\n const contentArr = Array.isArray(response.message.content) ? response.message.content : null;\n const hasActionableContent =\n response.message.content !== \"\" &&\n contentArr !== null &&\n contentArr.some(\n (p) => p.type === \"text\" || p.type === \"tool_call\" || p.type === \"server_tool_call\",\n );\n if (!hasActionableContent) {\n if (emptyResponseRetries < MAX_EMPTY_RESPONSE_RETRIES) {\n emptyResponseRetries++;\n diag(\"retry\", {\n reason: \"empty_response\",\n attempt: emptyResponseRetries,\n maxAttempts: MAX_EMPTY_RESPONSE_RETRIES,\n provider: options.provider,\n model: options.model,\n contentTypes: contentArr?.map((p) => p.type).join(\",\") ?? \"empty\",\n });\n yield {\n type: \"retry\" as const,\n reason: \"empty_response\" as const,\n attempt: emptyResponseRetries,\n maxAttempts: MAX_EMPTY_RESPONSE_RETRIES,\n delayMs: 0,\n };\n turn--; // Don't count the failed turn — keep useNonStreamingFallback set\n // so the retry doesn't bounce back into a streaming connection that\n // will stall again with the same upstream problem.\n continue;\n }\n // Exhausted retries — fall through and let the agent finish\n }\n emptyResponseRetries = 0;\n\n // Only clear the non-streaming fallback after an actionable response —\n // an empty non-streaming reply means the upstream issue hasn't resolved,\n // so staying in non-streaming mode avoids retrying into another stall.\n useNonStreamingFallback = false;\n\n // Accumulate usage\n totalUsage.inputTokens += response.usage.inputTokens;\n totalUsage.outputTokens += response.usage.outputTokens;\n if (response.usage.cacheRead) {\n totalUsage.cacheRead = (totalUsage.cacheRead ?? 0) + response.usage.cacheRead;\n }\n if (response.usage.cacheWrite) {\n totalUsage.cacheWrite = (totalUsage.cacheWrite ?? 0) + response.usage.cacheWrite;\n }\n\n // Append assistant message to conversation\n messages.push(response.message);\n\n yield {\n type: \"turn_end\" as const,\n turn,\n stopReason: response.stopReason,\n usage: response.usage,\n };\n\n // Server-side tool hit iteration limit — re-send to continue.\n // Do NOT add an extra user message; the API detects the trailing\n // server_tool_use block and resumes automatically.\n if (response.stopReason === \"pause_turn\") {\n consecutivePauses++;\n if (consecutivePauses >= maxContinuations) {\n break; // Safety limit — fall through to agent_done below\n }\n continue;\n }\n consecutivePauses = 0;\n\n // Extract tool calls — separate client-executed from provider built-in (e.g. Moonshot $web_search)\n const allToolCalls = extractToolCalls(response.message.content);\n\n // If no tool calls to execute, check for steering messages before stopping.\n // Check content (not just stopReason) because some providers (e.g. GLM)\n // return finish_reason=\"stop\" even when tool calls are present.\n if (response.stopReason !== \"tool_use\" && allToolCalls.length === 0) {\n // Check for queued steering messages — if present, inject and continue\n // the loop instead of returning (follow-up pattern).\n if (options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n continue; // Next iteration will call LLM with injected messages\n }\n }\n // Follow-up: lower priority than steering — only when agent would otherwise stop.\n if (options.getFollowUpMessages) {\n const followUp = await options.getFollowUpMessages();\n if (followUp && followUp.length > 0) {\n for (const msg of followUp) {\n yield { type: \"follow_up_message\" as const, content: msg.content };\n messages.push(msg);\n }\n continue;\n }\n }\n yield {\n type: \"agent_done\" as const,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n return {\n message: response.message,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n }\n const toolCalls: ToolCall[] = [];\n const toolResults: ToolResult[] = [];\n\n for (const tc of allToolCalls) {\n if (tc.name.startsWith(\"$\")) {\n // Provider built-in tool (e.g. Moonshot $web_search) — not locally executed.\n // Still needs a tool_result for the message history round-trip.\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: JSON.stringify(tc.args),\n });\n } else {\n toolCalls.push(tc);\n }\n }\n\n let fatalToolArgumentError: Error | null = null;\n const markFatalToolArgumentError = (error: Error): void => {\n fatalToolArgumentError = error;\n };\n const executionOptions: ToolBatchExecutionOptions = {\n signal: options.signal,\n maxToolResultChars: options.maxToolResultChars,\n toolMap,\n invalidToolArgumentCounts,\n markFatalToolArgumentError,\n };\n const hasSequentialToolCall = toolCalls.some(\n (toolCall) => toolMap.get(toolCall.name)?.executionMode === \"sequential\",\n );\n const executionResult = hasSequentialToolCall\n ? yield* executeToolCallsSequential(toolCalls, toolResults, executionOptions)\n : yield* executeToolCallsParallel(toolCalls, toolResults, executionOptions);\n messages.push({ role: \"tool\", content: executionResult.toolResults });\n const toolsAborted = executionResult.aborted;\n\n if (fatalToolArgumentError) {\n yield { type: \"error\" as const, error: fatalToolArgumentError };\n break;\n }\n\n // Exit loop after cleaning up aborted tools\n if (toolsAborted) break;\n\n // ── Steering messages: inject user messages queued during tool execution ──\n // Polled after tools complete so the next LLM call sees them in context.\n if (options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n }\n }\n }\n } finally {\n // Sanitize orphaned server_tool_use blocks on abort.\n // When a stream is aborted mid-server-tool (e.g. web_search), the\n // assistant message containing the server_tool_use may already be in\n // the messages array, but the corresponding web_search_tool_result\n // never arrived. The API rejects the next request with a 400 if it\n // finds an unmatched server_tool_use, so we strip it here.\n sanitizeOrphanedServerTools(messages);\n }\n\n // Exceeded max turns — return last assistant message\n let lastAssistant: AssistantMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]!.role === \"assistant\") {\n lastAssistant = messages[i] as AssistantMessage;\n break;\n }\n }\n\n yield {\n type: \"agent_done\" as const,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n\n return {\n message: lastAssistant ?? { role: \"assistant\" as const, content: [] },\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n}\n\ninterface ToolExecutionRecord {\n toolCallId: string;\n content: ToolResultContent;\n isError: boolean;\n}\n\ninterface ToolBatchExecutionOptions {\n signal?: AbortSignal;\n maxToolResultChars?: number;\n toolMap: Map<string, AgentTool>;\n invalidToolArgumentCounts: Map<string, number>;\n markFatalToolArgumentError: (error: Error) => void;\n}\n\ninterface ToolBatchExecutionResult {\n toolResults: ToolResult[];\n aborted: boolean;\n}\n\ninterface ToolEventState {\n finalized: boolean;\n}\n\nfunction pushToolEvent(\n eventStream: EventStream<AgentEvent>,\n state: ToolEventState,\n event: AgentEvent,\n): void {\n if (!state.finalized) eventStream.push(event);\n}\n\nasync function executeSingleToolCall(\n toolCall: ToolCall,\n options: ToolBatchExecutionOptions,\n pushEvent: (event: AgentEvent) => void,\n): Promise<ToolExecutionRecord> {\n const startTime = Date.now();\n\n pushEvent({\n type: \"tool_call_start\" as const,\n toolCallId: toolCall.id,\n name: toolCall.name,\n args: toolCall.args,\n });\n\n let resultContent: ToolResultContent;\n let details: unknown;\n let isError = false;\n\n const tool = options.toolMap.get(toolCall.name);\n if (!tool) {\n resultContent = `Unknown tool: ${toolCall.name}`;\n isError = true;\n } else {\n try {\n const parsed = tool.parameters.parse(toolCall.args);\n const ctx: ToolContext = {\n signal: options.signal ?? AbortSignal.timeout(300_000),\n toolCallId: toolCall.id,\n onUpdate: (update: unknown) => {\n pushEvent({\n type: \"tool_call_update\" as const,\n toolCallId: toolCall.id,\n update,\n });\n },\n };\n const raw = await tool.execute(parsed, ctx);\n const normalized = normalizeToolResult(raw);\n resultContent = normalized.content;\n details = normalized.details;\n for (const key of options.invalidToolArgumentCounts.keys()) {\n if (key.startsWith(`${toolCall.name}:`)) options.invalidToolArgumentCounts.delete(key);\n }\n } catch (err) {\n isError = true;\n if (err instanceof ZodError) {\n // Zod v4's default `.message` is a JSON dump of `.issues`, which\n // the model can't act on. Prettify into \"field X: expected Y,\n // received Z\" lines so the next call comes back with valid args.\n const prettyError = prettifyError(err);\n const failureKey = `${toolCall.name}:${prettyError}`;\n const failureCount = (options.invalidToolArgumentCounts.get(failureKey) ?? 0) + 1;\n options.invalidToolArgumentCounts.set(failureKey, failureCount);\n resultContent =\n `Invalid arguments for tool \\`${toolCall.name}\\`:\\n` +\n prettyError +\n \"\\nRe-issue the call with each field as the correct type.\";\n if (failureCount >= 3) {\n options.markFatalToolArgumentError(\n new Error(\n `The model repeatedly issued invalid arguments for tool \\`${toolCall.name}\\`. ` +\n `This is usually an upstream model/tool-calling bug. Your conversation is preserved; ` +\n `send another message or switch models to continue.`,\n ),\n );\n }\n } else {\n resultContent = err instanceof Error ? err.message : String(err);\n }\n }\n }\n\n const durationMs = Date.now() - startTime;\n\n pushEvent({\n type: \"tool_call_end\" as const,\n toolCallId: toolCall.id,\n result: toolResultPreview(resultContent),\n details,\n isError,\n durationMs,\n });\n\n return { toolCallId: toolCall.id, content: resultContent, isError };\n}\n\nasync function* executeToolCallsSequential(\n toolCalls: ToolCall[],\n initialToolResults: ToolResult[],\n options: ToolBatchExecutionOptions,\n): AsyncGenerator<AgentEvent, ToolBatchExecutionResult> {\n const eventStream = new EventStream<AgentEvent>();\n const state: ToolEventState = { finalized: false };\n const resultsById = new Map<string, ToolExecutionRecord>();\n const abortHandler = () => eventStream.abort(new Error(\"aborted\"));\n options.signal?.addEventListener(\"abort\", abortHandler, { once: true });\n\n void (async () => {\n try {\n for (const toolCall of toolCalls) {\n if (options.signal?.aborted) break;\n const record = await executeSingleToolCall(toolCall, options, (event) =>\n pushToolEvent(eventStream, state, event),\n );\n resultsById.set(record.toolCallId, record);\n }\n if (!state.finalized) eventStream.close();\n } catch (err) {\n if (!state.finalized) eventStream.abort(err instanceof Error ? err : new Error(String(err)));\n }\n })();\n\n let aborted = false;\n try {\n for await (const event of eventStream) {\n yield event;\n }\n } catch (err) {\n if (isAbortError(err) || options.signal?.aborted) {\n aborted = true;\n } else {\n throw err;\n }\n } finally {\n options.signal?.removeEventListener(\"abort\", abortHandler);\n state.finalized = true;\n }\n\n const toolResults = buildToolResults(initialToolResults, toolCalls, resultsById);\n capToolResults(toolResults, options.maxToolResultChars);\n return { toolResults, aborted };\n}\n\nasync function* executeToolCallsParallel(\n toolCalls: ToolCall[],\n initialToolResults: ToolResult[],\n options: ToolBatchExecutionOptions,\n): AsyncGenerator<AgentEvent, ToolBatchExecutionResult> {\n const eventStream = new EventStream<AgentEvent>();\n const state: ToolEventState = { finalized: false };\n const resultsById = new Map<string, ToolExecutionRecord>();\n const abortHandler = () => eventStream.abort(new Error(\"aborted\"));\n options.signal?.addEventListener(\"abort\", abortHandler, { once: true });\n\n Promise.all(\n toolCalls.map(async (toolCall) => {\n const record = await executeSingleToolCall(toolCall, options, (event) =>\n pushToolEvent(eventStream, state, event),\n );\n resultsById.set(record.toolCallId, record);\n }),\n )\n .then(() => {\n if (!state.finalized) eventStream.close();\n })\n .catch((err) => {\n if (!state.finalized) eventStream.abort(err instanceof Error ? err : new Error(String(err)));\n });\n\n let aborted = false;\n try {\n for await (const event of eventStream) {\n yield event;\n }\n } catch (err) {\n if (isAbortError(err) || options.signal?.aborted) {\n aborted = true;\n } else {\n throw err;\n }\n } finally {\n options.signal?.removeEventListener(\"abort\", abortHandler);\n state.finalized = true;\n }\n\n const toolResults = buildToolResults(initialToolResults, toolCalls, resultsById);\n capToolResults(toolResults, options.maxToolResultChars);\n return { toolResults, aborted };\n}\n\nfunction buildToolResults(\n initialToolResults: ToolResult[],\n toolCalls: ToolCall[],\n resultsById: Map<string, ToolExecutionRecord>,\n): ToolResult[] {\n const toolResults = [...initialToolResults];\n for (const toolCall of toolCalls) {\n const result = resultsById.get(toolCall.id);\n if (result) {\n toolResults.push({\n type: \"tool_result\",\n toolCallId: toolCall.id,\n content: result.content,\n isError: result.isError || undefined,\n });\n } else {\n toolResults.push({\n type: \"tool_result\",\n toolCallId: toolCall.id,\n content: \"Tool execution was aborted.\",\n isError: true,\n });\n }\n }\n return toolResults;\n}\n\nfunction capToolResults(toolResults: ToolResult[], maxToolResultChars: number | undefined): void {\n if (!maxToolResultChars) return;\n const hardMax = 400_000; // absolute ceiling regardless of context window\n const max = Math.min(maxToolResultChars, hardMax);\n for (const toolResult of toolResults) {\n if (typeof toolResult.content !== \"string\" || toolResult.content.length <= max) continue;\n // Keep 70% head + 30% tail to preserve errors/diagnostics at the end.\n const headChars = Math.floor(max * 0.7);\n const tailChars = max - headChars;\n const head = toolResult.content.slice(0, headChars);\n const tail = toolResult.content.slice(-tailChars);\n const omitted = toolResult.content.length - headChars - tailChars;\n toolResult.content = head + `\\n\\n[... ${omitted} characters omitted ...]\\n\\n` + tail;\n }\n}\n\nfunction normalizeToolResult(raw: ToolExecuteResult): StructuredToolResult {\n return typeof raw === \"string\" ? { content: raw } : raw;\n}\n\n/** Flatten tool result content to a plain-text preview for the tool_call_end event.\n * Image blocks become a \"[image]\" placeholder so the UI has something to render. */\nfunction toolResultPreview(content: ToolResultContent): string {\n if (typeof content === \"string\") return content;\n return content\n .map((block) => (block.type === \"text\" ? block.text : `[image ${block.mediaType}]`))\n .join(\"\\n\");\n}\n\nfunction truncateToolResultText(text: string, maxChars: number): string {\n if (text.length <= maxChars) return text;\n const tailChars = Math.min(Math.floor(maxChars * 0.3), 20_000);\n const headChars = Math.max(maxChars - tailChars, 0);\n const omitted = text.length - headChars - tailChars;\n return `${text.slice(0, headChars)}\\n\\n[... ${omitted} characters omitted after context overflow ...]\\n\\n${text.slice(-tailChars)}`;\n}\n\nfunction truncateOversizedToolResults(messages: Message[], maxChars: number): boolean {\n if (maxChars <= 0) return false;\n let changed = false;\n for (const msg of messages) {\n if (msg.role !== \"tool\" || !Array.isArray(msg.content)) continue;\n const results = msg.content as ToolResult[];\n for (const result of results) {\n if (typeof result.content === \"string\") {\n const truncated = truncateToolResultText(result.content, maxChars);\n if (truncated !== result.content) {\n result.content = truncated;\n changed = true;\n }\n } else {\n for (const block of result.content) {\n if (block.type !== \"text\") continue;\n const truncated = truncateToolResultText(block.text, maxChars);\n if (truncated !== block.text) {\n block.text = truncated;\n changed = true;\n }\n }\n }\n }\n }\n return changed;\n}\n\nfunction extractToolCalls(content: string | ContentPart[]): ToolCall[] {\n if (typeof content === \"string\") return [];\n return content.filter((part): part is ToolCall => part.type === \"tool_call\");\n}\n\n/**\n * Remove orphaned server_tool_use blocks from the last assistant message.\n * When a stream is aborted mid-server-tool (e.g. web_search), the assistant\n * message may contain a server_tool_call without a matching server_tool_result.\n * The API rejects the next request if these are unmatched.\n */\nfunction sanitizeOrphanedServerTools(messages: Message[]): void {\n // Find the last assistant message\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role !== \"assistant\") continue;\n if (typeof msg.content === \"string\" || !Array.isArray(msg.content)) break;\n\n // Collect server_tool_call ids and matched server_tool_result ids\n const serverToolIds = new Set<string>();\n const resultToolIds = new Set<string>();\n for (const part of msg.content) {\n if (part.type === \"server_tool_call\") serverToolIds.add(part.id);\n if (part.type === \"server_tool_result\") resultToolIds.add(part.toolUseId);\n }\n\n // Find unmatched server_tool_call blocks\n const orphanedIds = new Set<string>();\n for (const id of serverToolIds) {\n if (!resultToolIds.has(id)) orphanedIds.add(id);\n }\n\n if (orphanedIds.size === 0) break;\n\n // Strip orphaned server_tool_call blocks from the content\n const filtered = msg.content.filter(\n (part) => !(part.type === \"server_tool_call\" && orphanedIds.has(part.id)),\n );\n\n if (filtered.length === 0) {\n // Nothing left — remove the entire message\n messages.splice(i, 1);\n } else {\n (msg as { content: ContentPart[] }).content = filtered;\n }\n break;\n }\n}\n\n/**\n * Ensure every assistant message with tool_call blocks is immediately followed\n * by a tool message with matching tool_result entries. This prevents Anthropic\n * API 400 errors (\"tool_use ids found without tool_result blocks immediately\n * after\") that can occur after compaction, session restore, or abort recovery.\n *\n * Repairs in-place by inserting synthetic tool_result messages where needed.\n */\nfunction repairToolPairingAdjacent(messages: Message[]): void {\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]!;\n if (msg.role !== \"assistant\") continue;\n if (typeof msg.content === \"string\" || !Array.isArray(msg.content)) continue;\n\n const toolCallIds = (msg.content as ContentPart[])\n .filter((p) => p.type === \"tool_call\")\n .map((p) => (p as ContentPart & { type: \"tool_call\"; id: string }).id);\n if (toolCallIds.length === 0) continue;\n\n const next = messages[i + 1];\n if (next?.role === \"tool\" && Array.isArray(next.content)) {\n // Tool message exists — check for missing results\n const existingIds = new Set((next.content as ToolResult[]).map((r) => r.toolCallId));\n const missing = toolCallIds.filter((id) => !existingIds.has(id));\n if (missing.length > 0) {\n for (const id of missing) {\n (next.content as ToolResult[]).push({\n type: \"tool_result\",\n toolCallId: id,\n content: \"Tool execution was interrupted.\",\n isError: true,\n });\n }\n }\n } else {\n // No tool message follows — insert a synthetic one\n messages.splice(i + 1, 0, {\n role: \"tool\" as const,\n content: toolCallIds.map((id) => ({\n type: \"tool_result\" as const,\n toolCallId: id,\n content: \"Tool execution was interrupted.\",\n isError: true,\n })),\n });\n }\n }\n\n // Reverse repair: strip tool_result entries whose tool_use_id has no matching\n // tool_call in the preceding assistant message. This can happen when compaction\n // or stall recovery removes an assistant message but leaves its tool_result behind.\n const toolCallIdSet = new Set<string>();\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]!;\n if (msg.role === \"assistant\" && Array.isArray(msg.content)) {\n for (const p of msg.content as ContentPart[]) {\n if (p.type === \"tool_call\") toolCallIdSet.add((p as ToolCall).id);\n }\n }\n if (msg.role === \"tool\" && Array.isArray(msg.content)) {\n const results = msg.content as ToolResult[];\n const filtered = results.filter((r) => toolCallIdSet.has(r.toolCallId));\n if (filtered.length === 0) {\n // Entire tool message is orphaned — remove it\n messages.splice(i, 1);\n i--;\n } else if (filtered.length < results.length) {\n (msg as { content: ToolResult[] }).content = filtered;\n }\n }\n }\n}\n\n/**\n * Strip thinking / redacted_thinking content from every assistant message in\n * place. Last-resort recovery when Anthropic rejects the request for a\n * thinking-block integrity violation (e.g. a corrupt signature from an\n * interrupted stream). Reasoning text is preserved as a plain text block so no\n * conversational context is lost; tool_call/tool_result pairing is untouched.\n */\nfunction stripThinkingBlocks(messages: Message[]): void {\n for (const msg of messages) {\n if (msg.role !== \"assistant\" || !Array.isArray(msg.content)) continue;\n const next: ContentPart[] = [];\n for (const part of msg.content as ContentPart[]) {\n if (part.type === \"thinking\") {\n if (part.text) next.push({ type: \"text\", text: part.text });\n continue;\n }\n if (part.type === \"raw\") {\n const t = (part.data as { type?: string }).type;\n if (t === \"thinking\" || t === \"redacted_thinking\") continue;\n }\n next.push(part);\n }\n (msg as { content: ContentPart[] }).content = next;\n }\n}\n"],"mappings":"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","names":["import_ai"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/agent.ts","../src/agent-loop.ts"],"sourcesContent":["// Core\nexport { Agent, AgentStream } from \"./agent.js\";\nexport {\n agentLoop,\n isAbortError,\n isContextOverflow,\n isBillingError,\n isUsageLimitError,\n setStreamDiagnostic,\n} from \"./agent-loop.js\";\nexport type { StreamDiagnosticFn } from \"./agent-loop.js\";\n\n// Types\nexport type {\n StructuredToolResult,\n ToolExecuteResult,\n ToolContext,\n ToolExecutionMode,\n AgentTool,\n AgentTextDeltaEvent,\n AgentThinkingDeltaEvent,\n AgentToolCallStartEvent,\n AgentToolCallUpdateEvent,\n AgentToolCallEndEvent,\n AgentToolCallDeltaEvent,\n AgentServerToolCallEvent,\n AgentServerToolResultEvent,\n AgentSteeringMessageEvent,\n AgentFollowUpMessageEvent,\n AgentRetryEvent,\n AgentTurnEndEvent,\n AgentDoneEvent,\n AgentErrorEvent,\n AgentEvent,\n AgentOptions,\n AgentResult,\n} from \"./types.js\";\n","import { EventStream, type Message } from \"@prestyj/ai\";\nimport { agentLoop } from \"./agent-loop.js\";\nimport type { AgentEvent, AgentOptions, AgentResult } from \"./types.js\";\n\n// ── AgentStream ─────────────────────────────────────────────\n\n/**\n * Dual-nature result: async iterable for streaming events,\n * thenable for awaiting the final AgentResult.\n *\n * ```ts\n * // Stream events\n * for await (const event of agent.prompt(\"hello\")) { ... }\n *\n * // Or just await the result\n * const result = await agent.prompt(\"hello\");\n * ```\n */\nexport class AgentStream implements AsyncIterable<AgentEvent> {\n private events: EventStream<AgentEvent>;\n private resultPromise: Promise<AgentResult>;\n private resolveResult!: (r: AgentResult) => void;\n private rejectResult!: (e: Error) => void;\n private hasConsumer = false;\n\n constructor(generator: AsyncGenerator<AgentEvent, AgentResult>, onDone: () => void) {\n this.events = new EventStream<AgentEvent>();\n this.resultPromise = new Promise<AgentResult>((resolve, reject) => {\n this.resolveResult = resolve;\n this.rejectResult = reject;\n });\n this.pump(generator, onDone);\n }\n\n private async pump(\n generator: AsyncGenerator<AgentEvent, AgentResult>,\n onDone: () => void,\n ): Promise<void> {\n try {\n let next = await generator.next();\n while (!next.done) {\n this.events.push(next.value);\n next = await generator.next();\n }\n this.events.close();\n this.resolveResult(next.value);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.events.abort(error);\n this.rejectResult(error);\n } finally {\n onDone();\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<AgentEvent> {\n this.hasConsumer = true;\n return this.events[Symbol.asyncIterator]();\n }\n\n then<TResult1 = AgentResult, TResult2 = never>(\n onfulfilled?: ((value: AgentResult) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n this.drainEvents().catch(() => {});\n return this.resultPromise.then(onfulfilled, onrejected);\n }\n\n private async drainEvents(): Promise<void> {\n if (this.hasConsumer) return;\n this.hasConsumer = true;\n for await (const _ of this.events) {\n // consume silently\n }\n }\n}\n\n// ── Agent ───────────────────────────────────────────────────\n\nexport class Agent {\n private messages: Message[] = [];\n private _running = false;\n private options: AgentOptions;\n private steeringQueue: Message[] = [];\n private followUpQueue: Message[] = [];\n\n constructor(options: AgentOptions) {\n this.options = options;\n if (options.system) {\n this.messages.push({ role: \"system\", content: options.system });\n }\n if (options.priorMessages && options.priorMessages.length > 0) {\n this.messages.push(...options.priorMessages);\n }\n }\n\n /** Snapshot of the current message history. Used for session persistence. */\n getMessages(): Message[] {\n return [...this.messages];\n }\n\n /**\n * Swap the abort signal used for subsequent prompts. Call this after\n * `controller.abort()` so the next prompt() call gets a fresh, unaborted\n * signal — without losing message history.\n */\n setSignal(signal: AbortSignal | undefined): void {\n this.options = { ...this.options, signal };\n }\n\n get running(): boolean {\n return this._running;\n }\n\n /** Queue a steering message for injection after current tool execution completes. */\n steer(msg: Message): void {\n this.steeringQueue.push(msg);\n }\n\n /** Queue a follow-up message for injection when the agent would otherwise stop. */\n followUp(msg: Message): void {\n this.followUpQueue.push(msg);\n }\n\n prompt(content: string): AgentStream {\n if (this._running) {\n throw new Error(\"Agent is already running\");\n }\n this._running = true;\n\n this.messages.push({ role: \"user\", content });\n\n const optionsWithQueues: AgentOptions = {\n ...this.options,\n getSteeringMessages: async () => {\n const callerResult = (await this.options.getSteeringMessages?.()) ?? [];\n const queued = this.steeringQueue.splice(0);\n const all = [...(callerResult ?? []), ...queued];\n return all.length > 0 ? all : null;\n },\n getFollowUpMessages: async () => {\n const callerResult = (await this.options.getFollowUpMessages?.()) ?? [];\n const queued = this.followUpQueue.splice(0);\n const all = [...(callerResult ?? []), ...queued];\n return all.length > 0 ? all : null;\n },\n };\n\n const generator = agentLoop(this.messages, optionsWithQueues);\n return new AgentStream(generator, () => {\n this._running = false;\n });\n }\n}\n","import { ZodError, prettifyError } from \"zod\";\nimport {\n stream,\n EventStream,\n type Message,\n type ToolCall,\n type ToolResult,\n type ToolResultContent,\n type Usage,\n type ContentPart,\n type AssistantMessage,\n type StreamEvent,\n isHardBillingMessage,\n} from \"@prestyj/ai\";\nimport type {\n AgentEvent,\n AgentOptions,\n AgentResult,\n AgentTool,\n ToolContext,\n ToolExecuteResult,\n StructuredToolResult,\n} from \"./types.js\";\n\nconst DEFAULT_MAX_TURNS = 300;\n\n/**\n * Lightweight stream diagnostic callback. When set, the agent loop calls this\n * at every phase boundary with timing and state info. This lets the hosting\n * app (ezcoder, come-alive, etc.) log stall diagnostics without the agent\n * package needing fs/process dependencies.\n */\nexport type StreamDiagnosticFn = (phase: string, data?: Record<string, unknown>) => void;\n\n/** Global diagnostic hook — set by the hosting app before calling agentLoop. */\nlet _diagFn: StreamDiagnosticFn | null = null;\n\n/** Register a diagnostic callback for stream stall tracing. */\nexport function setStreamDiagnostic(fn: StreamDiagnosticFn | null): void {\n _diagFn = fn;\n}\n\nfunction diag(phase: string, data?: Record<string, unknown>): void {\n _diagFn?.(phase, data);\n}\n\n/**\n * Detect abort errors — user-initiated cancellation or AbortSignal.\n * These should be caught and handled gracefully, not re-thrown.\n */\nexport function isAbortError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (err.name === \"AbortError\") return true;\n const msg = err.message.toLowerCase();\n return msg.includes(\"aborted\") || msg.includes(\"abort\");\n}\n\n/**\n * Detect context window overflow errors from LLM providers.\n *\n * Patterns drawn from observed errors across Anthropic, OpenAI, OpenAI Codex,\n * Bedrock, Ollama, and OpenAI-compatible Chinese providers (GLM, Kimi, MiniMax).\n */\nexport function isContextOverflow(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n // 402 is always credit/payment exhaustion — never a context overflow. Guards\n // against e.g. OpenRouter's 402 \"requires more credits, or fewer max_tokens...\n // you requested up to N tokens\" being misread as overflow and triggering\n // futile compaction retries.\n const overflowStatus = (err as Error & { statusCode?: unknown }).statusCode;\n if (overflowStatus === 402) return false;\n if (isBillingError(err)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"prompt is too long\") ||\n msg.includes(\"prompt too long\") ||\n msg.includes(\"input is too long\") ||\n msg.includes(\"context_length_exceeded\") ||\n msg.includes(\"context_window_exceeded\") ||\n msg.includes(\"maximum context length\") ||\n msg.includes(\"exceeds model context window\") ||\n msg.includes(\"exceeds the context window\") ||\n msg.includes(\"content_too_large\") ||\n msg.includes(\"request_too_large\") ||\n msg.includes(\"reduce the length\") ||\n msg.includes(\"please shorten\") ||\n (msg.includes(\"token\") && msg.includes(\"exceed\"))\n );\n}\n\nexport interface ContextOverflowDetails {\n observedTokens?: number;\n observedLimit?: number;\n}\n\nfunction parseOverflowNumber(value: string): number {\n return Number(value.replace(/[,_\\s]/g, \"\"));\n}\n\n/** Extract provider-reported token counts from common context overflow messages. */\nexport function extractContextOverflowDetails(err: unknown): ContextOverflowDetails {\n if (!(err instanceof Error)) return {};\n const text = err.message;\n const patterns: Array<{ regex: RegExp; tokensGroup: number; limitGroup: number }> = [\n // Anthropic/OpenAI-compatible: \"203456 tokens > 200000 maximum\"\n {\n regex: /([\\d,_.\\s]+)\\s*tokens?\\s*>\\s*([\\d,_.\\s]+)\\s*(?:maximum|max|limit)?/i,\n tokensGroup: 1,\n limitGroup: 2,\n },\n // OpenAI: \"maximum context length is 128000 tokens ... resulted in 130000 tokens\"\n {\n regex:\n /maximum context length is\\s*([\\d,_.\\s]+)\\s*tokens?[\\s\\S]*?resulted in\\s*([\\d,_.\\s]+)\\s*tokens?/i,\n tokensGroup: 2,\n limitGroup: 1,\n },\n // Generic: \"130000 input tokens exceeds 128000 token limit\"\n {\n regex:\n /([\\d,_.\\s]+)\\s*(?:input\\s*)?tokens?[\\s\\S]{0,80}?exceeds?[\\s\\S]{0,80}?([\\d,_.\\s]+)\\s*(?:token\\s*)?(?:limit|maximum|max)/i,\n tokensGroup: 1,\n limitGroup: 2,\n },\n ];\n\n for (const pattern of patterns) {\n const match = text.match(pattern.regex);\n if (!match) continue;\n const observedTokens = parseOverflowNumber(match[pattern.tokensGroup] ?? \"\");\n const observedLimit = parseOverflowNumber(match[pattern.limitGroup] ?? \"\");\n return {\n ...(Number.isFinite(observedTokens) && observedTokens > 0 ? { observedTokens } : {}),\n ...(Number.isFinite(observedLimit) && observedLimit > 0 ? { observedLimit } : {}),\n };\n }\n\n return {};\n}\n\n/**\n * Detect billing/quota errors — these should NOT be retried.\n * GLM returns HTTP 429 with \"Insufficient balance\" for quota exhaustion.\n */\nexport function isBillingError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n // HTTP 402 (Payment Required) is always a hard credit/payment stop across our\n // provider set (DeepSeek, OpenRouter, ...). Never retriable.\n const statusCode = (err as Error & { statusCode?: unknown }).statusCode;\n if (statusCode === 402) return true;\n // Shared marker list (single source of truth in @prestyj/ai) so the\n // provider boundary and this classifier can't drift apart.\n return isHardBillingMessage(err.message);\n}\n\n/**\n * Detect subscription/plan usage-window exhaustion (e.g. an Anthropic OAuth\n * plan running out of usage). Unlike a transient per-minute 429, this does NOT\n * clear with a quick retry — the user must wait for the window to reset — so the\n * loop surfaces it immediately instead of retrying for minutes. Matches the\n * canonical message gg-ai stamps onto the provider error.\n */\nexport function isUsageLimitError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n return /usage limit reached/i.test(err.message);\n}\n\n/**\n * Read a provider-stated reset time off the error and convert it to a delay in\n * milliseconds from now. Providers like Gemini return a short `retryDelay` for a\n * transient per-minute throttle, which gg-ai stamps onto the ProviderError as\n * `resetsAt` (unix seconds). Returns undefined when absent or already elapsed.\n */\nexport function serverResetDelayMs(err: unknown): number | undefined {\n if (!(err instanceof Error)) return undefined;\n const resetsAt = (err as Error & { resetsAt?: unknown }).resetsAt;\n if (typeof resetsAt !== \"number\" || !Number.isFinite(resetsAt)) return undefined;\n const delayMs = resetsAt * 1000 - Date.now();\n return delayMs > 0 ? delayMs : undefined;\n}\n\n/**\n * Detect overloaded/rate-limit errors from LLM providers.\n * HTTP 429 (rate limit) or 529/503 (overloaded).\n * Excludes billing/quota errors which won't resolve with a retry.\n */\n/**\n * Detect tool pairing errors — orphaned tool_use or tool_result blocks.\n * These are 400 errors that can be recovered by repairing the message history.\n */\nexport function isToolPairingError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n return (\n (msg.includes(\"tool_use\") && msg.includes(\"tool_result\")) ||\n msg.includes(\"unexpected `tool_use_id`\") ||\n msg.includes(\"tool_use ids found without\") ||\n // Moonshot/OpenAI-compatible: \"tool call id <id> is not found\"\n (msg.includes(\"tool call id\") && msg.includes(\"is not found\"))\n );\n}\n\n/**\n * Detect Anthropic's thinking-block integrity errors. These 400s fire when a\n * signed `thinking`/`redacted_thinking` block in the latest assistant message\n * can't be validated — typically a partial/invalid signature from an\n * interrupted stream, or a block whose position shifted. Recoverable once by\n * stripping thinking blocks from the message history and re-sending.\n */\nexport function isThinkingBlockError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n if (!msg.includes(\"thinking\")) return false;\n return (\n msg.includes(\"cannot be modified\") ||\n msg.includes(\"must remain as they were\") ||\n (msg.includes(\"signature\") && msg.includes(\"invalid\")) ||\n // \"Expected `thinking` or `redacted_thinking`, but found `text`\"\n (msg.includes(\"expected\") && msg.includes(\"but found\"))\n );\n}\n\n/**\n * Distinguish rate-limit (HTTP 429), server-side overload (HTTP 529), and\n * transient provider 5xx/API failures. Returns null for errors that should not\n * enter the retry bucket. All kinds use the same backoff schedule, but the UI\n * shows different copy and the log line records the true cause.\n */\nexport function classifyOverload(\n err: unknown,\n): \"rate_limit\" | \"overloaded\" | \"provider_error\" | null {\n if (!(err instanceof Error)) return null;\n if (isBillingError(err)) return null;\n // Usage-window exhaustion is not retriable — keep it out of the backoff bucket.\n if (isUsageLimitError(err)) return null;\n const msg = err.message.toLowerCase();\n const errorWithStatus = err as Error & { statusCode?: unknown };\n const statusCode =\n typeof errorWithStatus.statusCode === \"number\" ? errorWithStatus.statusCode : undefined;\n // 402 is billing/credits — never retry, never treat as overload.\n if (statusCode === 402) return null;\n if (\n statusCode === 429 ||\n msg.includes(\"rate_limit\") ||\n msg.includes(\"rate limit\") ||\n msg.includes(\"too many requests\") ||\n msg.includes(\"429\")\n ) {\n return \"rate_limit\";\n }\n if (statusCode === 529 || msg.includes(\"overloaded\") || msg.includes(\"529\")) {\n return \"overloaded\";\n }\n if (\n statusCode === 500 ||\n statusCode === 502 ||\n statusCode === 503 ||\n statusCode === 504 ||\n msg.includes(\"api_error\") ||\n msg.includes(\"server_error\") ||\n msg.includes(\"internal server error\") ||\n msg.includes(\"bad gateway\") ||\n msg.includes(\"service unavailable\") ||\n msg.includes(\"gateway timeout\")\n ) {\n return \"provider_error\";\n }\n return null;\n}\n\nexport function isOverloaded(err: unknown): boolean {\n return classifyOverload(err) !== null;\n}\n\n/**\n * Detect malformed-stream errors — the SDK's SSE decoder threw a JSON parse\n * error mid-stream, typically because a chunk was truncated or corrupted by\n * an intermediary (CDN, proxy). Same class of transport failure as a stall:\n * replaying the request — and ideally flipping to non-streaming — recovers.\n */\nexport function isMalformedStream(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (err.name === \"SyntaxError\") return true;\n const cause = (err as { cause?: unknown }).cause;\n if (cause instanceof Error && cause.name === \"SyntaxError\") return true;\n const msg = err.message;\n // V8 JSON.parse error messages: \"Expected ... in JSON at position N\"\n // and \"Unexpected token ... in JSON at position N\"\n return /\\bin JSON at position \\d+/i.test(msg);\n}\n\n/**\n * Detect socket-level transport failures — the remote peer (or an\n * intermediary) closed the TCP connection mid-stream before the response\n * finished. Surfaces as `TypeError: terminated` from undici/fetch, or as\n * `ECONNRESET` / `socket hang up` / `UND_ERR_SOCKET` from the underlying\n * Node http layer. Undici nests the real cause one or more levels deep,\n * so we walk the `.cause` chain. Same recovery as a stall: replay the\n * request, optionally as non-streaming.\n */\nexport function isTransportFailure(err: unknown): boolean {\n const codes = new Set([\n \"ECONNRESET\",\n \"ECONNREFUSED\",\n \"ECONNABORTED\",\n \"ETIMEDOUT\",\n \"EPIPE\",\n \"EHOSTUNREACH\",\n \"ENETUNREACH\",\n \"ENOTFOUND\",\n \"UND_ERR_SOCKET\",\n \"UND_ERR_CONNECT_TIMEOUT\",\n \"UND_ERR_HEADERS_TIMEOUT\",\n \"UND_ERR_BODY_TIMEOUT\",\n \"UND_ERR_RESPONSE_STATUS_CODE\",\n \"UND_ERR_REQ_CONTENT_LENGTH_MISMATCH\",\n \"UND_ERR_RES_CONTENT_LENGTH_MISMATCH\",\n ]);\n const messages = [\n /^terminated$/i,\n /\\bother side closed\\b/i,\n /\\bsocket hang up\\b/i,\n /\\bfetch failed\\b/i,\n /\\bbody timeout error\\b/i,\n /\\bsse stream disconnected\\b/i,\n /\\bfailed to reconnect sse stream\\b/i,\n ];\n const seen = new Set<unknown>();\n let cur: unknown = err;\n while (cur && typeof cur === \"object\" && !seen.has(cur)) {\n seen.add(cur);\n const e = cur as { code?: unknown; message?: unknown; cause?: unknown };\n if (typeof e.code === \"string\" && codes.has(e.code)) return true;\n if (typeof e.message === \"string\") {\n for (const re of messages) if (re.test(e.message)) return true;\n }\n cur = e.cause;\n }\n return false;\n}\n\nfunction createAbortError(): Error {\n return new DOMException(\"Aborted\", \"AbortError\");\n}\n\nfunction abortablePromise<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return promise;\n if (signal.aborted) return Promise.reject(createAbortError());\n\n return new Promise<T>((resolve, reject) => {\n let settled = false;\n const cleanup = (): void => signal.removeEventListener(\"abort\", onAbort);\n const resolveOnce = (value: T): void => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(value);\n };\n const rejectOnce = (err: unknown): void => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(err instanceof Error ? err : new Error(String(err)));\n };\n const onAbort = (): void => rejectOnce(createAbortError());\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n promise.then(resolveOnce, rejectOnce);\n });\n}\n\n/**\n * Promise-returning sleep that rejects with AbortError if `signal` fires.\n * Used by retry backoffs so ESC/Ctrl+C cancel immediately instead of having\n * to wait out the full delay (up to 30s per overload retry × 10 retries).\n */\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) return Promise.reject(createAbortError());\n\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = (): void => {\n clearTimeout(timer);\n reject(createAbortError());\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction closeIterator<T>(iterator: AsyncIterator<T> | null): void {\n if (!iterator?.return) return;\n Promise.resolve(iterator.return()).catch(() => {});\n}\n\nexport async function* agentLoop(\n messages: Message[],\n options: AgentOptions,\n): AsyncGenerator<AgentEvent, AgentResult> {\n const maxTurns = options.maxTurns ?? DEFAULT_MAX_TURNS;\n const maxContinuations = options.maxContinuations ?? 5;\n const toolMap = new Map<string, AgentTool>((options.tools ?? []).map((t) => [t.name, t]));\n\n const totalUsage: Usage = { inputTokens: 0, outputTokens: 0 };\n let turn = 0;\n let firstTurn = true;\n let consecutivePauses = 0;\n let toolPairingRepaired = false;\n let thinkingBlocksStripped = false;\n let overloadRetries = 0;\n let emptyResponseRetries = 0;\n let stallRetries = 0;\n let overflowCompactionAttempts = 0;\n let toolResultTruncationAttempted = false;\n const invalidToolArgumentCounts = new Map<string, number>();\n // Non-streaming fallback mode. After repeated stream stalls, flip to a\n // plain non-streaming request/response -- often survives broken SSE\n // connections (transient CDN / proxy issues) that streaming retries cannot.\n let useNonStreamingFallback = false;\n const MAX_OVERLOAD_RETRIES = 10;\n const MAX_EMPTY_RESPONSE_RETRIES = 2;\n const MAX_STALL_RETRIES = 5;\n const MAX_OVERFLOW_COMPACTIONS = 2;\n // After this many streaming stalls in a row, switch to non-streaming mode\n // for the remaining stall retries. Keeps the first two retries fast (the\n // cheap \"transient glitch\" case) before paying for a full response round-trip.\n const STALL_RETRIES_BEFORE_NON_STREAMING = 2;\n const STALL_DELAY_MS = 1_000; // Brief pause before retry -- just enough to avoid tight loops\n const OVERLOAD_BASE_DELAY_MS = 2_000;\n const OVERLOAD_MAX_DELAY_MS = 30_000;\n const STREAM_FIRST_EVENT_TIMEOUT_MS = 45_000; // 45s to get first event (Opus thinks long)\n // 90s of true API silence between events once streaming starts. This measures\n // only time the *API* was quiet -- the timer is armed after we finish yielding\n // each event downstream, so slow UI/consumer render time is excluded (see the\n // resetIdleTimer() call after the yield, below). 30s here previously caused\n // false aborts on large `write`/`edit` tool-call streams when the Ink UI lagged\n // tens of seconds behind. 90s matches Claude Code's default idle watchdog.\n const STREAM_IDLE_TIMEOUT_MS = 90_000; // 90s of API silence between events\n // Anthropic models can pause 10-20s mid-stream while computing the next chunk\n // (e.g. generating tool call args for a large write). 10s was too aggressive\n // and caused false \"stream stalled\" errors, especially in plan mode.\n const STREAM_HARD_TIMEOUT_MS = 90_000; // 90s absolute cap before output starts\n // Once output events (text_delta) are actively streaming, extend the hard\n // timeout -- long responses (plan mode, detailed explanations) can legitimately\n // take 2-3+ minutes while events flow continuously.\n const STREAM_OUTPUT_HARD_TIMEOUT_MS = 300_000; // 5min hard cap once output is flowing\n // Reasoning models (MiMo) can pause 3-5 minutes between thinking and output\n // generation. Once we've seen thinking events, extend timeouts significantly.\n const STREAM_THINKING_IDLE_TIMEOUT_MS = 300_000; // 5min idle after thinking\n const STREAM_THINKING_HARD_TIMEOUT_MS = 600_000; // 10min hard cap with thinking\n // Non-streaming mode has no per-event idle -- the entire response arrives in\n // one HTTP round-trip. Use a single generous hard cap instead. This matches\n // Claude Code's v2.1.110/111 behaviour: cap non-streaming retries so API\n // unreachability doesn't cause multi-minute hangs, but not so aggressively\n // that slow-but-healthy backends get killed.\n const NON_STREAMING_HARD_TIMEOUT_MS = 300_000; // 5min for full non-streaming response\n // Runaway tool-call circuit breaker. When a model glitches mid-tool-call it\n // can emit tens of thousands of toolcall_delta events without ever closing,\n // burning the entire stall-retry budget (~25 min) on what is clearly a\n // non-recoverable model error. Cap accumulated arg chars and event count;\n // exceeding either is a hard, non-retriable failure. Thresholds are generous\n // enough to allow legitimate large file writes through `write`.\n const MAX_TOOLCALL_DELTA_CHARS = 1_000_000; // 1 MB of accumulated tool-call args\n const MAX_TOOLCALL_DELTA_EVENTS = 20_000; // 20k delta events in one stream\n\n try {\n while (turn < maxTurns) {\n options.signal?.throwIfAborted();\n turn++;\n\n // Estimate message payload size for diagnostics\n let msgChars = 0;\n for (const m of messages) {\n if (typeof m.content === \"string\") msgChars += m.content.length;\n else if (Array.isArray(m.content)) {\n for (const p of m.content) {\n if (\"text\" in p && typeof p.text === \"string\") msgChars += p.text.length;\n if (\"content\" in p && typeof p.content === \"string\") msgChars += p.content.length;\n }\n }\n }\n diag(\"turn_start\", {\n turn,\n messages: messages.length,\n chars: msgChars,\n provider: options.provider,\n model: options.model,\n });\n\n // ── Initial steering poll: catch messages queued before the first LLM call ──\n if (firstTurn && options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n }\n }\n firstTurn = false;\n\n // ── Mid-loop context transform (compaction / truncation) ──\n if (options.transformContext) {\n diag(\"transform_start\");\n const transformed = await options.transformContext(messages);\n if (transformed !== messages) {\n diag(\"transform_compacted\", {\n before: messages.length,\n after: transformed.length,\n });\n messages.length = 0;\n messages.push(...transformed);\n }\n diag(\"transform_end\");\n }\n\n // ── Repair tool pairing: ensure every tool_use has an adjacent tool_result ──\n repairToolPairingAdjacent(messages);\n\n // ── Call LLM with overflow recovery ──\n let response;\n // Per-attempt abort controller: allows idle timeout to abort the stream\n // without affecting the caller's signal. The caller's abort is forwarded.\n const streamController = new AbortController();\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\n let hardTimer: ReturnType<typeof setTimeout> | null = null;\n let idleTimedOut = false;\n\n // Stream event counters — declared here so timeout callbacks can access them\n let streamEventCount = 0;\n let lastEventTime = Date.now();\n let streamCallStart = Date.now();\n // Track event types for diagnostics — shows what arrived before a stall\n const eventTypeCounts: Record<string, number> = {};\n let lastEventType = \"\";\n // Runaway tool-call detection — accumulated across all toolcall_delta\n // events in this stream attempt. When tripped we abort the stream and\n // bail out without retrying (the model has glitched, retries won't help).\n let toolcallDeltaChars = 0;\n let toolcallDeltaCount = 0;\n let runawayDetected: { kind: \"chars\" | \"events\"; chars: number; events: number } | null =\n null;\n // Track consumer processing time — helps distinguish \"API stopped sending\"\n // from \"our consumer was slow to pull the next event\"\n let lastYieldEndTime = Date.now();\n let maxConsumerLagMs = 0;\n\n // Forward caller abort to the per-attempt controller\n const forwardAbort = () => streamController.abort();\n options.signal?.addEventListener(\"abort\", forwardAbort, { once: true });\n\n // Three-phase idle timeout:\n // - Before first event: STREAM_FIRST_EVENT_TIMEOUT_MS (45s) -- Opus can\n // take 30s+ to start on large contexts, that's not a stall.\n // - After output event (text_delta, server_toolcall): STREAM_IDLE_TIMEOUT_MS\n // (10s) -- once output is streaming, 10s of silence is dead. Retry fast.\n // - After thinking events only: STREAM_THINKING_IDLE_TIMEOUT_MS (5min) --\n // reasoning models (MiMo) can pause minutes between thinking and output.\n //\n // In non-streaming fallback mode the entire response arrives in a single\n // HTTP round-trip, so the idle timer is disabled -- only the hard timeout\n // applies. Synthesized events all arrive at once when the response returns.\n let hasReceivedEvent = false;\n let hasReceivedThinking = false;\n const resetIdleTimer = () => {\n if (useNonStreamingFallback) return; // no inter-event idle in non-streaming mode\n if (idleTimer) clearTimeout(idleTimer);\n const timeoutMs = hasReceivedEvent\n ? STREAM_IDLE_TIMEOUT_MS\n : hasReceivedThinking\n ? STREAM_THINKING_IDLE_TIMEOUT_MS\n : STREAM_FIRST_EVENT_TIMEOUT_MS;\n idleTimer = setTimeout(() => {\n diag(\"idle_timeout_fired\", {\n events: streamEventCount,\n sinceLastEventMs: Date.now() - lastEventTime,\n lastEventType,\n maxConsumerLagMs,\n phase: hasReceivedEvent\n ? \"mid_stream\"\n : hasReceivedThinking\n ? \"post_thinking\"\n : \"first_event\",\n eventTypes: eventTypeCounts,\n });\n idleTimedOut = true;\n streamController.abort();\n }, timeoutMs);\n };\n\n // Hard timeout: absolute cap per LLM call. Safety net for streams that\n // keep sending sparse events (e.g. keep-alive pings) but never complete.\n // Extended dynamically when thinking events arrive (see thinking_delta handler).\n // Non-streaming fallback uses a single larger cap since there's no stream\n // to observe -- just wait for the full response up to the cap.\n let hardTimeoutMs = useNonStreamingFallback\n ? NON_STREAMING_HARD_TIMEOUT_MS\n : STREAM_HARD_TIMEOUT_MS;\n hardTimer = setTimeout(() => {\n diag(\"hard_timeout_fired\", {\n events: typeof streamEventCount !== \"undefined\" ? streamEventCount : 0,\n nonStreaming: useNonStreamingFallback,\n });\n idleTimedOut = true;\n streamController.abort();\n }, hardTimeoutMs);\n let streamIterator: AsyncIterator<StreamEvent> | null = null;\n\n try {\n diag(\"stream_call\", { nonStreaming: useNonStreamingFallback });\n streamCallStart = Date.now();\n const result = stream({\n provider: options.provider,\n model: options.model,\n messages,\n tools: options.tools,\n serverTools: options.serverTools,\n webSearch: options.webSearch,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n thinking: options.thinking,\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n signal: streamController.signal,\n accountId: options.accountId,\n projectId: options.projectId,\n cacheRetention: options.cacheRetention,\n promptCacheKey: options.promptCacheKey,\n serviceTier: options.serviceTier,\n supportsImages: options.supportsImages,\n supportsVideo: options.supportsVideo,\n compaction: options.compaction,\n clearToolUses: options.clearToolUses,\n userAgent: options.userAgent,\n defaultHeaders: options.defaultHeaders,\n // Flip to non-streaming fallback after repeated stream stalls.\n ...(useNonStreamingFallback ? { streaming: false } : {}),\n });\n diag(\"stream_created\", { setupMs: Date.now() - streamCallStart });\n\n // Suppress unhandled rejection if the iterator path throws first\n result.response.catch(() => {});\n\n // Forward streaming deltas — reset idle timer on each event\n streamEventCount = 0;\n hasReceivedEvent = false;\n lastEventTime = Date.now();\n streamCallStart = Date.now();\n // Reset to streamCallStart so the first event's consumerLag reflects\n // network/provider latency, not the time spent before stream() returned.\n lastYieldEndTime = Date.now();\n resetIdleTimer();\n streamIterator = result[Symbol.asyncIterator]();\n while (true) {\n // Race each pull against our local abort signal. Some SDK streams can\n // ignore an aborted fetch before the first byte arrives; without this\n // the idle/hard timers fire but the harness remains stuck awaiting\n // `next()`, so Esc/Ctrl+C cannot release the UI.\n const next = await abortablePromise(streamIterator.next(), streamController.signal);\n if (next.done) break;\n const event = next.value;\n\n // Measure consumer lag: time between finishing previous yield and\n // receiving this event. For event #1 this still includes network/\n // provider latency; for subsequent events it isolates how long\n // React/UI rendering held up the next pull.\n const pullTime = Date.now();\n const consumerLag = pullTime - lastYieldEndTime;\n // Only track mid-stream lag — first event lag is dominated by\n // server-side TTFB and would mask real UI starvation issues.\n if (streamEventCount > 0 && consumerLag > maxConsumerLagMs) {\n maxConsumerLagMs = consumerLag;\n }\n\n streamEventCount++;\n eventTypeCounts[event.type] = (eventTypeCounts[event.type] ?? 0) + 1;\n lastEventType = event.type;\n\n // Flip to mid-stream timeout on confirmed output events — text\n // deltas, completed tool calls, and tool call deltas (large file\n // writes can stream toolcall_delta for minutes without any text_delta).\n // Reasoning models (MiMo) are handled separately below — they can\n // stream hundreds of thinking events then pause minutes before output.\n if (\n (event.type === \"text_delta\" ||\n event.type === \"server_toolcall\" ||\n event.type === \"toolcall_delta\") &&\n !hasReceivedEvent\n ) {\n hasReceivedEvent = true;\n // Extend hard timeout now that output is actively streaming.\n // Long responses (plan mode, detailed code) can exceed 90s while\n // events flow continuously — the idle timeout (10s) catches real stalls.\n if (hardTimer && hardTimeoutMs < STREAM_OUTPUT_HARD_TIMEOUT_MS) {\n clearTimeout(hardTimer);\n hardTimeoutMs = STREAM_OUTPUT_HARD_TIMEOUT_MS;\n hardTimer = setTimeout(() => {\n diag(\"hard_timeout_fired\", { events: streamEventCount });\n idleTimedOut = true;\n streamController.abort();\n }, hardTimeoutMs);\n }\n }\n // Track thinking events — extends idle timeout and hard timeout\n // so reasoning models aren't killed during thinking→output transition.\n if (event.type === \"thinking_delta\" && !hasReceivedThinking) {\n hasReceivedThinking = true;\n // Extend the hard timeout now that we know the model is reasoning\n if (hardTimer) clearTimeout(hardTimer);\n hardTimeoutMs = STREAM_THINKING_HARD_TIMEOUT_MS;\n hardTimer = setTimeout(() => {\n diag(\"hard_timeout_fired\", { events: streamEventCount });\n idleTimedOut = true;\n streamController.abort();\n }, hardTimeoutMs);\n }\n\n const now = Date.now();\n const gap = now - lastEventTime;\n // Log first event and any suspiciously long gaps\n if (streamEventCount === 1) {\n diag(\"first_event\", { type: event.type, ttfMs: now - streamCallStart });\n } else if (gap > 3000) {\n diag(\"slow_gap\", {\n type: event.type,\n gapMs: gap,\n eventNum: streamEventCount,\n sinceStartMs: now - streamCallStart,\n });\n }\n lastEventTime = now;\n // The event is in hand -- the API has proven liveness, so stop the idle\n // timer for the duration of downstream processing. We re-arm it after\n // the yield completes (see below) so the idle window measures only API\n // silence, never the time our consumer/UI spent rendering this event.\n if (idleTimer) {\n clearTimeout(idleTimer);\n idleTimer = null;\n }\n if (event.type === \"text_delta\") {\n yield { type: \"text_delta\" as const, text: event.text };\n } else if (event.type === \"thinking_delta\") {\n yield { type: \"thinking_delta\" as const, text: event.text };\n } else if (event.type === \"server_toolcall\") {\n yield {\n type: \"server_tool_call\" as const,\n id: event.id,\n name: event.name,\n input: event.input,\n };\n } else if (event.type === \"server_toolresult\") {\n yield {\n type: \"server_tool_result\" as const,\n toolUseId: event.toolUseId,\n resultType: event.resultType,\n data: event.data,\n };\n } else if (event.type === \"toolcall_delta\") {\n const chunkChars = event.argsJson?.length ?? 0;\n toolcallDeltaChars += chunkChars;\n toolcallDeltaCount++;\n if (\n !runawayDetected &&\n (toolcallDeltaChars > MAX_TOOLCALL_DELTA_CHARS ||\n toolcallDeltaCount > MAX_TOOLCALL_DELTA_EVENTS)\n ) {\n runawayDetected = {\n kind: toolcallDeltaChars > MAX_TOOLCALL_DELTA_CHARS ? \"chars\" : \"events\",\n chars: toolcallDeltaChars,\n events: toolcallDeltaCount,\n };\n diag(\"runaway_toolcall_detected\", {\n ...runawayDetected,\n provider: options.provider,\n model: options.model,\n });\n streamController.abort();\n }\n yield {\n type: \"toolcall_delta\" as const,\n chars: chunkChars,\n };\n }\n lastYieldEndTime = Date.now();\n // Re-arm the idle timer only now that we're done yielding -- the\n // countdown to the next event excludes the render time above.\n resetIdleTimer();\n }\n\n diag(\"stream_done\", {\n events: streamEventCount,\n totalMs: Date.now() - streamCallStart,\n maxConsumerLagMs,\n eventTypes: eventTypeCounts,\n });\n response = await abortablePromise(result.response, streamController.signal);\n } catch (err) {\n if (streamController.signal.aborted) closeIterator(streamIterator);\n const errMsg = err instanceof Error ? err.message : String(err);\n diag(\"stream_error\", {\n error: errMsg.slice(0, 200),\n events: streamEventCount,\n totalMs: Date.now() - streamCallStart,\n idleTimedOut,\n aborted: !!options.signal?.aborted,\n eventTypes: eventTypeCounts,\n provider: options.provider,\n model: options.model,\n });\n // Subscription/plan usage-window exhaustion (e.g. Anthropic OAuth plan\n // out of usage). Not a transient throttle — retrying just burns minutes\n // before failing, which looks like a hang. Surface immediately so the\n // host UI shows a clear \"usage finished\" message. The conversation in\n // `messages` is left intact so the user can resume once it resets.\n if (isUsageLimitError(err)) {\n diag(\"usage_limit_reached\", {\n provider: options.provider,\n model: options.model,\n });\n throw err;\n }\n // Context overflow: try a forced compaction before giving up.\n // The pre-turn transformContext check uses estimated tokens, which can\n // underestimate code-heavy content. When the API confirms overflow we\n // compact unconditionally and retry the turn, capped at\n // MAX_OVERFLOW_COMPACTIONS to avoid loops when compaction can't reduce\n // enough (e.g. single huge user message).\n if (isContextOverflow(err)) {\n const overflowDetails = extractContextOverflowDetails(err);\n diag(\"context_overflow_detected\", {\n ...overflowDetails,\n error: errMsg.slice(0, 500),\n messages: messages.length,\n });\n\n const overflowToolResultMaxChars = Math.min(\n options.maxToolResultChars ?? 100_000,\n 100_000,\n );\n if (!toolResultTruncationAttempted) {\n toolResultTruncationAttempted = true;\n const truncated = truncateOversizedToolResults(messages, overflowToolResultMaxChars);\n diag(\"overflow_tool_result_truncation\", {\n truncated,\n maxChars: overflowToolResultMaxChars,\n });\n if (truncated) {\n yield {\n type: \"retry\" as const,\n reason: \"overflow_compact\" as const,\n attempt: overflowCompactionAttempts + 1,\n maxAttempts: MAX_OVERFLOW_COMPACTIONS,\n delayMs: 0,\n ...overflowDetails,\n silent: true,\n };\n turn--;\n continue;\n }\n }\n\n if (options.transformContext && overflowCompactionAttempts < MAX_OVERFLOW_COMPACTIONS) {\n overflowCompactionAttempts++;\n diag(\"overflow_compact_start\", {\n attempt: overflowCompactionAttempts,\n maxAttempts: MAX_OVERFLOW_COMPACTIONS,\n messages: messages.length,\n ...overflowDetails,\n });\n try {\n const compacted = await options.transformContext(messages, { force: true });\n if (compacted !== messages && compacted.length < messages.length) {\n messages.length = 0;\n messages.push(...compacted);\n diag(\"overflow_compact_success\", {\n attempt: overflowCompactionAttempts,\n messages: messages.length,\n ...overflowDetails,\n });\n yield {\n type: \"retry\" as const,\n reason: \"overflow_compact\" as const,\n attempt: overflowCompactionAttempts,\n maxAttempts: MAX_OVERFLOW_COMPACTIONS,\n delayMs: 0,\n ...overflowDetails,\n };\n turn--;\n continue;\n }\n diag(\"overflow_compact_noop\", {\n attempt: overflowCompactionAttempts,\n before: messages.length,\n after: compacted.length,\n ...overflowDetails,\n });\n } catch (compactErr) {\n diag(\"overflow_compact_failed\", {\n error: compactErr instanceof Error ? compactErr.message : String(compactErr),\n ...overflowDetails,\n });\n }\n }\n yield { type: \"error\" as const, error: err instanceof Error ? err : new Error(errMsg) };\n throw err;\n }\n // Transient provider errors (5xx), overload, and rate-limit: exponential backoff.\n const overloadKind = classifyOverload(err);\n if (overloadRetries < MAX_OVERLOAD_RETRIES && overloadKind) {\n overloadRetries++;\n // Honor a server-stated reset time (e.g. Gemini's RetryInfo.retryDelay)\n // when present, so we wait exactly as long as the provider asked\n // instead of guessing with blind exponential backoff. Fall back to\n // exponential backoff otherwise.\n const serverDelayMs = serverResetDelayMs(err);\n const delayMs =\n serverDelayMs !== undefined\n ? Math.min(serverDelayMs, OVERLOAD_MAX_DELAY_MS)\n : Math.min(\n OVERLOAD_BASE_DELAY_MS * 2 ** (overloadRetries - 1),\n OVERLOAD_MAX_DELAY_MS,\n );\n diag(\"retry\", {\n reason: overloadKind,\n attempt: overloadRetries,\n maxAttempts: MAX_OVERLOAD_RETRIES,\n delayMs,\n });\n yield {\n type: \"retry\" as const,\n reason: overloadKind,\n attempt: overloadRetries,\n maxAttempts: MAX_OVERLOAD_RETRIES,\n delayMs,\n };\n await abortableSleep(delayMs, options.signal);\n turn--; // Don't count the failed turn\n continue;\n }\n // Stream stall: the API connection hung without closing.\n // Malformed stream: the SDK's SSE decoder hit truncated/corrupted JSON.\n // Both are transport failures — retry with exponential backoff and flip\n // to non-streaming mode after STALL_RETRIES_BEFORE_NON_STREAMING attempts,\n // since broken SSE often recovers when replayed as plain HTTP.\n // Runaway tool-call: the model never closed a tool-call block and\n // blew past the size/count caps. Retrying just reproduces the loop,\n // so surface a clear error and stop. Checked before the abort branch\n // since we ourselves aborted the stream to break the runaway.\n if (runawayDetected) {\n diag(\"runaway_toolcall_aborted\", {\n ...runawayDetected,\n provider: options.provider,\n model: options.model,\n });\n const detail =\n runawayDetected.kind === \"chars\"\n ? `${(runawayDetected.chars / 1024).toFixed(0)} KB of tool-call arguments`\n : `${runawayDetected.events} tool-call delta events`;\n yield {\n type: \"error\" as const,\n error: new Error(\n `The model glitched mid-tool-call and produced ${detail} without closing the call. ` +\n `This is usually an upstream model bug — try the same request again or switch models. ` +\n `Your conversation is preserved.`,\n ),\n };\n break;\n }\n const malformed = isMalformedStream(err);\n const socketDrop = isTransportFailure(err);\n const transportFailure =\n (idleTimedOut || malformed || socketDrop) && !options.signal?.aborted;\n if (transportFailure && stallRetries < MAX_STALL_RETRIES) {\n stallRetries++;\n const cause = malformed\n ? \"malformed_stream\"\n : socketDrop\n ? \"socket_drop\"\n : \"stream_stall\";\n if (!useNonStreamingFallback && stallRetries >= STALL_RETRIES_BEFORE_NON_STREAMING) {\n useNonStreamingFallback = true;\n diag(\"non_streaming_fallback_enabled\", {\n stallRetries,\n provider: options.provider,\n model: options.model,\n cause,\n });\n }\n const delayMs = Math.min(STALL_DELAY_MS * 2 ** (stallRetries - 1), 8_000);\n diag(\"retry\", {\n reason: cause,\n attempt: stallRetries,\n maxAttempts: MAX_STALL_RETRIES,\n delayMs,\n events: streamEventCount,\n nonStreaming: useNonStreamingFallback,\n });\n yield {\n type: \"retry\" as const,\n reason: \"stream_stall\" as const,\n attempt: stallRetries,\n maxAttempts: MAX_STALL_RETRIES,\n delayMs,\n silent: stallRetries <= 2,\n };\n await abortableSleep(delayMs, options.signal);\n turn--; // Don't count the failed turn\n continue;\n }\n // Stream stall retries exhausted — surface a clear error so the UI\n // can distinguish \"gave up after stalls\" from \"completed normally\".\n if (transportFailure) {\n diag(\"stall_exhausted\", {\n stallRetries: MAX_STALL_RETRIES,\n provider: options.provider,\n model: options.model,\n });\n yield {\n type: \"error\" as const,\n error: new Error(\n `The API provider's stream stalled ${MAX_STALL_RETRIES} times — the provider may be experiencing capacity issues. ` +\n `Your conversation is preserved. Send another message to retry.`,\n ),\n };\n break;\n }\n // Tool pairing 400: orphaned tool_result or tool_use in message history.\n // Run repair and retry once — if repair can't fix it, surface the error.\n if (isToolPairingError(err) && !toolPairingRepaired) {\n toolPairingRepaired = true;\n diag(\"tool_pairing_repair\", { error: errMsg.slice(0, 200) });\n repairToolPairingAdjacent(messages);\n turn--;\n continue;\n }\n // Thinking-block integrity 400: a signed thinking block in the latest\n // assistant message couldn't be validated (commonly a partial signature\n // from an interrupted stream). Strip thinking from history — preserving\n // the reasoning as text — and retry once.\n if (isThinkingBlockError(err) && !thinkingBlocksStripped) {\n thinkingBlocksStripped = true;\n diag(\"thinking_block_repair\", { error: errMsg.slice(0, 200) });\n stripThinkingBlocks(messages);\n turn--;\n continue;\n }\n // Abort errors (user cancellation) — exit loop cleanly instead of\n // crashing the process with an unhandled rejection.\n if (isAbortError(err) || options.signal?.aborted) {\n diag(\"aborted\", { turn, provider: options.provider, model: options.model });\n break;\n }\n // Unhandled error — log before throwing so the crash is traceable\n diag(\"unhandled_error\", {\n error: errMsg.slice(0, 500),\n turn,\n provider: options.provider,\n model: options.model,\n });\n throw err;\n } finally {\n if (idleTimer) clearTimeout(idleTimer);\n if (hardTimer) clearTimeout(hardTimer);\n options.signal?.removeEventListener(\"abort\", forwardAbort);\n }\n\n overloadRetries = 0;\n stallRetries = 0;\n\n // Detect empty/degenerate responses — the API occasionally returns 0 tokens\n // with no content, or \"thinks\" without producing actionable output.\n // Reasoning models (MiMo, DeepSeek) may report outputTokens > 0 from\n // thinking alone while producing no text or tool calls — still a dud.\n const contentArr = Array.isArray(response.message.content) ? response.message.content : null;\n const hasActionableContent =\n response.message.content !== \"\" &&\n contentArr !== null &&\n contentArr.some(\n (p) => p.type === \"text\" || p.type === \"tool_call\" || p.type === \"server_tool_call\",\n );\n if (!hasActionableContent) {\n if (emptyResponseRetries < MAX_EMPTY_RESPONSE_RETRIES) {\n emptyResponseRetries++;\n diag(\"retry\", {\n reason: \"empty_response\",\n attempt: emptyResponseRetries,\n maxAttempts: MAX_EMPTY_RESPONSE_RETRIES,\n provider: options.provider,\n model: options.model,\n contentTypes: contentArr?.map((p) => p.type).join(\",\") ?? \"empty\",\n });\n yield {\n type: \"retry\" as const,\n reason: \"empty_response\" as const,\n attempt: emptyResponseRetries,\n maxAttempts: MAX_EMPTY_RESPONSE_RETRIES,\n delayMs: 0,\n };\n turn--; // Don't count the failed turn — keep useNonStreamingFallback set\n // so the retry doesn't bounce back into a streaming connection that\n // will stall again with the same upstream problem.\n continue;\n }\n // Exhausted retries — fall through and let the agent finish\n }\n emptyResponseRetries = 0;\n\n // Only clear the non-streaming fallback after an actionable response —\n // an empty non-streaming reply means the upstream issue hasn't resolved,\n // so staying in non-streaming mode avoids retrying into another stall.\n useNonStreamingFallback = false;\n\n // Accumulate usage\n totalUsage.inputTokens += response.usage.inputTokens;\n totalUsage.outputTokens += response.usage.outputTokens;\n if (response.usage.cacheRead) {\n totalUsage.cacheRead = (totalUsage.cacheRead ?? 0) + response.usage.cacheRead;\n }\n if (response.usage.cacheWrite) {\n totalUsage.cacheWrite = (totalUsage.cacheWrite ?? 0) + response.usage.cacheWrite;\n }\n\n // Append assistant message to conversation\n messages.push(response.message);\n\n yield {\n type: \"turn_end\" as const,\n turn,\n stopReason: response.stopReason,\n usage: response.usage,\n };\n\n // Server-side tool hit iteration limit — re-send to continue.\n // Do NOT add an extra user message; the API detects the trailing\n // server_tool_use block and resumes automatically.\n if (response.stopReason === \"pause_turn\") {\n consecutivePauses++;\n if (consecutivePauses >= maxContinuations) {\n break; // Safety limit — fall through to agent_done below\n }\n continue;\n }\n consecutivePauses = 0;\n\n // Extract tool calls — separate client-executed from provider built-in (e.g. Moonshot $web_search)\n const allToolCalls = extractToolCalls(response.message.content);\n\n // If no tool calls to execute, check for steering messages before stopping.\n // Check content (not just stopReason) because some providers (e.g. GLM)\n // return finish_reason=\"stop\" even when tool calls are present.\n if (response.stopReason !== \"tool_use\" && allToolCalls.length === 0) {\n // Check for queued steering messages — if present, inject and continue\n // the loop instead of returning (follow-up pattern).\n if (options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n continue; // Next iteration will call LLM with injected messages\n }\n }\n // Follow-up: lower priority than steering — only when agent would otherwise stop.\n if (options.getFollowUpMessages) {\n const followUp = await options.getFollowUpMessages();\n if (followUp && followUp.length > 0) {\n for (const msg of followUp) {\n yield { type: \"follow_up_message\" as const, content: msg.content };\n messages.push(msg);\n }\n continue;\n }\n }\n yield {\n type: \"agent_done\" as const,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n return {\n message: response.message,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n }\n const toolCalls: ToolCall[] = [];\n const toolResults: ToolResult[] = [];\n\n for (const tc of allToolCalls) {\n if (tc.name.startsWith(\"$\")) {\n // Provider built-in tool (e.g. Moonshot $web_search) — not locally executed.\n // Still needs a tool_result for the message history round-trip.\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: JSON.stringify(tc.args),\n });\n } else {\n toolCalls.push(tc);\n }\n }\n\n let fatalToolArgumentError: Error | null = null;\n const markFatalToolArgumentError = (error: Error): void => {\n fatalToolArgumentError = error;\n };\n const executionOptions: ToolBatchExecutionOptions = {\n signal: options.signal,\n maxToolResultChars: options.maxToolResultChars,\n toolMap,\n invalidToolArgumentCounts,\n markFatalToolArgumentError,\n };\n const hasSequentialToolCall = toolCalls.some(\n (toolCall) => toolMap.get(toolCall.name)?.executionMode === \"sequential\",\n );\n const executionResult = hasSequentialToolCall\n ? yield* executeToolCallsSequential(toolCalls, toolResults, executionOptions)\n : yield* executeToolCallsParallel(toolCalls, toolResults, executionOptions);\n messages.push({ role: \"tool\", content: executionResult.toolResults });\n const toolsAborted = executionResult.aborted;\n\n if (fatalToolArgumentError) {\n yield { type: \"error\" as const, error: fatalToolArgumentError };\n break;\n }\n\n // Exit loop after cleaning up aborted tools\n if (toolsAborted) break;\n\n // ── Steering messages: inject user messages queued during tool execution ──\n // Polled after tools complete so the next LLM call sees them in context.\n if (options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n }\n }\n }\n } finally {\n // Sanitize orphaned server_tool_use blocks on abort.\n // When a stream is aborted mid-server-tool (e.g. web_search), the\n // assistant message containing the server_tool_use may already be in\n // the messages array, but the corresponding web_search_tool_result\n // never arrived. The API rejects the next request with a 400 if it\n // finds an unmatched server_tool_use, so we strip it here.\n sanitizeOrphanedServerTools(messages);\n }\n\n // Exceeded max turns — return last assistant message\n let lastAssistant: AssistantMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]!.role === \"assistant\") {\n lastAssistant = messages[i] as AssistantMessage;\n break;\n }\n }\n\n yield {\n type: \"agent_done\" as const,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n\n return {\n message: lastAssistant ?? { role: \"assistant\" as const, content: [] },\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n}\n\ninterface ToolExecutionRecord {\n toolCallId: string;\n content: ToolResultContent;\n isError: boolean;\n}\n\ninterface ToolBatchExecutionOptions {\n signal?: AbortSignal;\n maxToolResultChars?: number;\n toolMap: Map<string, AgentTool>;\n invalidToolArgumentCounts: Map<string, number>;\n markFatalToolArgumentError: (error: Error) => void;\n}\n\ninterface ToolBatchExecutionResult {\n toolResults: ToolResult[];\n aborted: boolean;\n}\n\ninterface ToolEventState {\n finalized: boolean;\n}\n\nfunction pushToolEvent(\n eventStream: EventStream<AgentEvent>,\n state: ToolEventState,\n event: AgentEvent,\n): void {\n if (!state.finalized) eventStream.push(event);\n}\n\nasync function executeSingleToolCall(\n toolCall: ToolCall,\n options: ToolBatchExecutionOptions,\n pushEvent: (event: AgentEvent) => void,\n): Promise<ToolExecutionRecord> {\n const startTime = Date.now();\n\n pushEvent({\n type: \"tool_call_start\" as const,\n toolCallId: toolCall.id,\n name: toolCall.name,\n args: toolCall.args,\n });\n\n let resultContent: ToolResultContent;\n let details: unknown;\n let isError = false;\n\n const tool = options.toolMap.get(toolCall.name);\n if (!tool) {\n resultContent = `Unknown tool: ${toolCall.name}`;\n isError = true;\n } else {\n try {\n const parsed = tool.parameters.parse(toolCall.args);\n const ctx: ToolContext = {\n signal: options.signal ?? AbortSignal.timeout(300_000),\n toolCallId: toolCall.id,\n onUpdate: (update: unknown) => {\n pushEvent({\n type: \"tool_call_update\" as const,\n toolCallId: toolCall.id,\n update,\n });\n },\n };\n const raw = await abortablePromise(\n Promise.resolve().then(() => tool.execute(parsed, ctx)),\n ctx.signal,\n );\n const normalized = normalizeToolResult(raw);\n resultContent = normalized.content;\n details = normalized.details;\n for (const key of options.invalidToolArgumentCounts.keys()) {\n if (key.startsWith(`${toolCall.name}:`)) options.invalidToolArgumentCounts.delete(key);\n }\n } catch (err) {\n isError = true;\n if (err instanceof ZodError) {\n // Zod v4's default `.message` is a JSON dump of `.issues`, which\n // the model can't act on. Prettify into \"field X: expected Y,\n // received Z\" lines so the next call comes back with valid args.\n const prettyError = prettifyError(err);\n const failureKey = `${toolCall.name}:${prettyError}`;\n const failureCount = (options.invalidToolArgumentCounts.get(failureKey) ?? 0) + 1;\n options.invalidToolArgumentCounts.set(failureKey, failureCount);\n resultContent =\n `Invalid arguments for tool \\`${toolCall.name}\\`:\\n` +\n prettyError +\n \"\\nRe-issue the call with each field as the correct type.\";\n if (failureCount >= 3) {\n options.markFatalToolArgumentError(\n new Error(\n `The model repeatedly issued invalid arguments for tool \\`${toolCall.name}\\`. ` +\n `This is usually an upstream model/tool-calling bug. Your conversation is preserved; ` +\n `send another message or switch models to continue.`,\n ),\n );\n }\n } else {\n resultContent = err instanceof Error ? err.message : String(err);\n }\n }\n }\n\n const durationMs = Date.now() - startTime;\n\n pushEvent({\n type: \"tool_call_end\" as const,\n toolCallId: toolCall.id,\n result: toolResultPreview(resultContent),\n details,\n isError,\n durationMs,\n });\n\n return { toolCallId: toolCall.id, content: resultContent, isError };\n}\n\nasync function* executeToolCallsSequential(\n toolCalls: ToolCall[],\n initialToolResults: ToolResult[],\n options: ToolBatchExecutionOptions,\n): AsyncGenerator<AgentEvent, ToolBatchExecutionResult> {\n const eventStream = new EventStream<AgentEvent>();\n const state: ToolEventState = { finalized: false };\n const resultsById = new Map<string, ToolExecutionRecord>();\n const abortHandler = () => eventStream.abort(new Error(\"aborted\"));\n options.signal?.addEventListener(\"abort\", abortHandler, { once: true });\n\n void (async () => {\n try {\n for (const toolCall of toolCalls) {\n if (options.signal?.aborted) break;\n const record = await executeSingleToolCall(toolCall, options, (event) =>\n pushToolEvent(eventStream, state, event),\n );\n resultsById.set(record.toolCallId, record);\n }\n if (!state.finalized) eventStream.close();\n } catch (err) {\n if (!state.finalized) eventStream.abort(err instanceof Error ? err : new Error(String(err)));\n }\n })();\n\n let aborted = false;\n try {\n for await (const event of eventStream) {\n yield event;\n }\n } catch (err) {\n if (isAbortError(err) || options.signal?.aborted) {\n aborted = true;\n } else {\n throw err;\n }\n } finally {\n options.signal?.removeEventListener(\"abort\", abortHandler);\n state.finalized = true;\n }\n\n const toolResults = buildToolResults(initialToolResults, toolCalls, resultsById);\n capToolResults(toolResults, options.maxToolResultChars);\n return { toolResults, aborted };\n}\n\nasync function* executeToolCallsParallel(\n toolCalls: ToolCall[],\n initialToolResults: ToolResult[],\n options: ToolBatchExecutionOptions,\n): AsyncGenerator<AgentEvent, ToolBatchExecutionResult> {\n const eventStream = new EventStream<AgentEvent>();\n const state: ToolEventState = { finalized: false };\n const resultsById = new Map<string, ToolExecutionRecord>();\n const abortHandler = () => eventStream.abort(new Error(\"aborted\"));\n options.signal?.addEventListener(\"abort\", abortHandler, { once: true });\n\n Promise.all(\n toolCalls.map(async (toolCall) => {\n const record = await executeSingleToolCall(toolCall, options, (event) =>\n pushToolEvent(eventStream, state, event),\n );\n resultsById.set(record.toolCallId, record);\n }),\n )\n .then(() => {\n if (!state.finalized) eventStream.close();\n })\n .catch((err) => {\n if (!state.finalized) eventStream.abort(err instanceof Error ? err : new Error(String(err)));\n });\n\n let aborted = false;\n try {\n for await (const event of eventStream) {\n yield event;\n }\n } catch (err) {\n if (isAbortError(err) || options.signal?.aborted) {\n aborted = true;\n } else {\n throw err;\n }\n } finally {\n options.signal?.removeEventListener(\"abort\", abortHandler);\n state.finalized = true;\n }\n\n const toolResults = buildToolResults(initialToolResults, toolCalls, resultsById);\n capToolResults(toolResults, options.maxToolResultChars);\n return { toolResults, aborted };\n}\n\nfunction buildToolResults(\n initialToolResults: ToolResult[],\n toolCalls: ToolCall[],\n resultsById: Map<string, ToolExecutionRecord>,\n): ToolResult[] {\n const toolResults = [...initialToolResults];\n for (const toolCall of toolCalls) {\n const result = resultsById.get(toolCall.id);\n if (result) {\n toolResults.push({\n type: \"tool_result\",\n toolCallId: toolCall.id,\n content: result.content,\n isError: result.isError || undefined,\n });\n } else {\n toolResults.push({\n type: \"tool_result\",\n toolCallId: toolCall.id,\n content: \"Tool execution was aborted.\",\n isError: true,\n });\n }\n }\n return toolResults;\n}\n\nfunction capToolResults(toolResults: ToolResult[], maxToolResultChars: number | undefined): void {\n if (!maxToolResultChars) return;\n const hardMax = 400_000; // absolute ceiling regardless of context window\n const max = Math.min(maxToolResultChars, hardMax);\n for (const toolResult of toolResults) {\n if (typeof toolResult.content !== \"string\" || toolResult.content.length <= max) continue;\n // Keep 70% head + 30% tail to preserve errors/diagnostics at the end.\n const headChars = Math.floor(max * 0.7);\n const tailChars = max - headChars;\n const head = toolResult.content.slice(0, headChars);\n const tail = toolResult.content.slice(-tailChars);\n const omitted = toolResult.content.length - headChars - tailChars;\n toolResult.content = head + `\\n\\n[... ${omitted} characters omitted ...]\\n\\n` + tail;\n }\n}\n\nfunction normalizeToolResult(raw: ToolExecuteResult): StructuredToolResult {\n return typeof raw === \"string\" ? { content: raw } : raw;\n}\n\n/** Flatten tool result content to a plain-text preview for the tool_call_end event.\n * Image blocks become a \"[image]\" placeholder so the UI has something to render. */\nfunction toolResultPreview(content: ToolResultContent): string {\n if (typeof content === \"string\") return content;\n return content\n .map((block) => (block.type === \"text\" ? block.text : `[image ${block.mediaType}]`))\n .join(\"\\n\");\n}\n\nfunction truncateToolResultText(text: string, maxChars: number): string {\n if (text.length <= maxChars) return text;\n const tailChars = Math.min(Math.floor(maxChars * 0.3), 20_000);\n const headChars = Math.max(maxChars - tailChars, 0);\n const omitted = text.length - headChars - tailChars;\n return `${text.slice(0, headChars)}\\n\\n[... ${omitted} characters omitted after context overflow ...]\\n\\n${text.slice(-tailChars)}`;\n}\n\nfunction truncateOversizedToolResults(messages: Message[], maxChars: number): boolean {\n if (maxChars <= 0) return false;\n let changed = false;\n for (const msg of messages) {\n if (msg.role !== \"tool\" || !Array.isArray(msg.content)) continue;\n const results = msg.content as ToolResult[];\n for (const result of results) {\n if (typeof result.content === \"string\") {\n const truncated = truncateToolResultText(result.content, maxChars);\n if (truncated !== result.content) {\n result.content = truncated;\n changed = true;\n }\n } else {\n for (const block of result.content) {\n if (block.type !== \"text\") continue;\n const truncated = truncateToolResultText(block.text, maxChars);\n if (truncated !== block.text) {\n block.text = truncated;\n changed = true;\n }\n }\n }\n }\n }\n return changed;\n}\n\nfunction extractToolCalls(content: string | ContentPart[]): ToolCall[] {\n if (typeof content === \"string\") return [];\n return content.filter((part): part is ToolCall => part.type === \"tool_call\");\n}\n\n/**\n * Remove orphaned server_tool_use blocks from the last assistant message.\n * When a stream is aborted mid-server-tool (e.g. web_search), the assistant\n * message may contain a server_tool_call without a matching server_tool_result.\n * The API rejects the next request if these are unmatched.\n */\nfunction sanitizeOrphanedServerTools(messages: Message[]): void {\n // Find the last assistant message\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role !== \"assistant\") continue;\n if (typeof msg.content === \"string\" || !Array.isArray(msg.content)) break;\n\n // Collect server_tool_call ids and matched server_tool_result ids\n const serverToolIds = new Set<string>();\n const resultToolIds = new Set<string>();\n for (const part of msg.content) {\n if (part.type === \"server_tool_call\") serverToolIds.add(part.id);\n if (part.type === \"server_tool_result\") resultToolIds.add(part.toolUseId);\n }\n\n // Find unmatched server_tool_call blocks\n const orphanedIds = new Set<string>();\n for (const id of serverToolIds) {\n if (!resultToolIds.has(id)) orphanedIds.add(id);\n }\n\n if (orphanedIds.size === 0) break;\n\n // Strip orphaned server_tool_call blocks from the content\n const filtered = msg.content.filter(\n (part) => !(part.type === \"server_tool_call\" && orphanedIds.has(part.id)),\n );\n\n if (filtered.length === 0) {\n // Nothing left — remove the entire message\n messages.splice(i, 1);\n } else {\n (msg as { content: ContentPart[] }).content = filtered;\n }\n break;\n }\n}\n\n/**\n * Ensure every assistant message with tool_call blocks is immediately followed\n * by a tool message with matching tool_result entries. This prevents Anthropic\n * API 400 errors (\"tool_use ids found without tool_result blocks immediately\n * after\") that can occur after compaction, session restore, or abort recovery.\n *\n * Repairs in-place by inserting synthetic tool_result messages where needed.\n */\nfunction repairToolPairingAdjacent(messages: Message[]): void {\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]!;\n if (msg.role !== \"assistant\") continue;\n if (typeof msg.content === \"string\" || !Array.isArray(msg.content)) continue;\n\n const toolCallIds = (msg.content as ContentPart[])\n .filter((p) => p.type === \"tool_call\")\n .map((p) => (p as ContentPart & { type: \"tool_call\"; id: string }).id);\n if (toolCallIds.length === 0) continue;\n\n const next = messages[i + 1];\n if (next?.role === \"tool\" && Array.isArray(next.content)) {\n // Tool message exists — check for missing results\n const existingIds = new Set((next.content as ToolResult[]).map((r) => r.toolCallId));\n const missing = toolCallIds.filter((id) => !existingIds.has(id));\n if (missing.length > 0) {\n for (const id of missing) {\n (next.content as ToolResult[]).push({\n type: \"tool_result\",\n toolCallId: id,\n content: \"Tool execution was interrupted.\",\n isError: true,\n });\n }\n }\n } else {\n // No tool message follows — insert a synthetic one\n messages.splice(i + 1, 0, {\n role: \"tool\" as const,\n content: toolCallIds.map((id) => ({\n type: \"tool_result\" as const,\n toolCallId: id,\n content: \"Tool execution was interrupted.\",\n isError: true,\n })),\n });\n }\n }\n\n // Reverse repair: strip tool_result entries whose tool_use_id has no matching\n // tool_call in the preceding assistant message. This can happen when compaction\n // or stall recovery removes an assistant message but leaves its tool_result behind.\n const toolCallIdSet = new Set<string>();\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]!;\n if (msg.role === \"assistant\" && Array.isArray(msg.content)) {\n for (const p of msg.content as ContentPart[]) {\n if (p.type === \"tool_call\") toolCallIdSet.add((p as ToolCall).id);\n }\n }\n if (msg.role === \"tool\" && Array.isArray(msg.content)) {\n const results = msg.content as ToolResult[];\n const filtered = results.filter((r) => toolCallIdSet.has(r.toolCallId));\n if (filtered.length === 0) {\n // Entire tool message is orphaned — remove it\n messages.splice(i, 1);\n i--;\n } else if (filtered.length < results.length) {\n (msg as { content: ToolResult[] }).content = filtered;\n }\n }\n }\n}\n\n/**\n * Strip thinking / redacted_thinking content from every assistant message in\n * place. Last-resort recovery when Anthropic rejects the request for a\n * thinking-block integrity violation (e.g. a corrupt signature from an\n * interrupted stream). Reasoning text is preserved as a plain text block so no\n * conversational context is lost; tool_call/tool_result pairing is untouched.\n */\nfunction stripThinkingBlocks(messages: Message[]): void {\n for (const msg of messages) {\n if (msg.role !== \"assistant\" || !Array.isArray(msg.content)) continue;\n const next: ContentPart[] = [];\n for (const part of msg.content as ContentPart[]) {\n if (part.type === \"thinking\") {\n if (part.text) next.push({ type: \"text\", text: part.text });\n continue;\n }\n if (part.type === \"raw\") {\n const t = (part.data as { type?: string }).type;\n if (t === \"thinking\" || t === \"redacted_thinking\") continue;\n }\n next.push(part);\n }\n (msg as { content: ContentPart[] }).content = next;\n }\n}\n"],"mappings":"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","names":["import_ai"]}