{"version":3,"sources":["../src/index.ts","../src/agent.ts","../src/agent-loop.ts","../src/local-backend.ts","../src/output-ceiling.ts"],"sourcesContent":["// Core\nexport { Agent, AgentStream } from \"./agent.js\";\nexport {\n  agentLoop,\n  cancelledBeforeStartText,\n  indeterminateOutcomeText,\n  isAbortError,\n  isContextOverflow,\n  isBillingError,\n  isUsageLimitError,\n  setStreamDiagnostic,\n} from \"./agent-loop.js\";\nexport type { StreamDiagnosticFn } from \"./agent-loop.js\";\nexport { isLocalBackendUrl } from \"./local-backend.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  AgentTurnTiming,\n  AgentTurnEndEvent,\n  AgentDoneEvent,\n  AgentErrorEvent,\n  AgentEvent,\n  TransformContextOptions,\n  AgentOptions,\n  AgentResult,\n} from \"./types.js\";\n","import { EventStream, type Message } from \"@kenkaiiii/gg-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  GGAIError,\n  type Message,\n  type ToolCall,\n  type ToolResult,\n  type ToolResultContent,\n  type Usage,\n  type ContentPart,\n  type AssistantMessage,\n  isHardBillingMessage,\n  redactValue,\n  sliceHead,\n  sliceTail,\n} from \"@kenkaiiii/gg-ai\";\nimport type {\n  AgentEvent,\n  AgentOptions,\n  AgentResult,\n  AgentTool,\n  ToolContext,\n  ToolExecuteResult,\n  StructuredToolResult,\n} from \"./types.js\";\nimport { isLocalBackendUrl } from \"./local-backend.js\";\nimport {\n  clampOutputTokens,\n  outputRouteKey,\n  parseOutputTokenCeiling,\n  rememberOutputCeiling,\n} from \"./output-ceiling.js\";\n\nconst DEFAULT_MAX_TURNS = 300;\n/** Per-tool cancellation ceiling; a tool may raise it via `timeoutMs`. */\nconst DEFAULT_TOOL_TIMEOUT_MS = 300_000;\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 (ggcoder, 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 * Recursively delete keys whose value is `null`. Strict tool schemas make\n * providers emit explicit nulls for optional fields; Zod `.optional()` only\n * accepts an absent key, not `null`. Used as a fallback re-parse so genuine\n * nulls (`.nullable()` fields, MCP passthrough) are never touched.\n */\nfunction stripNullArguments(value: unknown): unknown {\n  if (Array.isArray(value)) return value.map(stripNullArguments);\n  if (value !== null && typeof value === \"object\") {\n    const out: Record<string, unknown> = {};\n    for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {\n      if (entry !== null) out[key] = stripNullArguments(entry);\n    }\n    return out;\n  }\n  return value;\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\n  // Explicit overflow wording from the provider always wins.\n  if (\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  ) {\n    return true;\n  }\n\n  // Throughput limits are not overflow. A tokens-per-minute 429 (\"20000\n  // tokens/min exceeded\") satisfies the loose token+exceed heuristic below,\n  // but compacting in response throws away context AND still fails — the quota\n  // is per unit time, not per request. The loop must back off instead.\n  const rateLimited =\n    overflowStatus === 429 ||\n    msg.includes(\"rate limit\") ||\n    msg.includes(\"rate_limit\") ||\n    msg.includes(\"too many requests\");\n  const perUnitTime =\n    msg.includes(\"per min\") ||\n    msg.includes(\"/min\") ||\n    msg.includes(\"per minute\") ||\n    msg.includes(\"per hour\") ||\n    msg.includes(\"per day\") ||\n    msg.includes(\"tpm\") ||\n    msg.includes(\"rpm\");\n  if (rateLimited && perUnitTime) return false;\n\n  // Loose fallback for providers that only say e.g. \"token limit exceeded\".\n  return msg.includes(\"token\") && msg.includes(\"exceed\");\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 @kenkaiiii/gg-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    statusCode === 507 ||\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    msg.includes(\"exceeded request buffer limit while retrying upstream\")\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 * Timeouts that arrive with no errno and no undici code.\n *\n * Both the Anthropic and OpenAI SDKs throw `APIConnectionTimeoutError`, whose\n * only distinguishing feature is the message \"Request timed out.\" — it sets no\n * `code`, no `status`, and leaves `name` at the default \"Error\". Matching has\n * to go on the message, so the patterns are deliberately request-scoped:\n * a bare /timeout/ would also swallow a tool that timed out or a config error\n * mentioning a timeout option, neither of which should replay the turn.\n *\n * `AbortSignal.timeout()` is the other source. It rejects with a DOMException\n * whose `code` is the numeric legacy constant (23) rather than a string, so it\n * is identifiable only by `name === \"TimeoutError\"`.\n */\nconst TIMEOUT_NAMES = new Set([\"TimeoutError\", \"ConnectTimeoutError\", \"HeadersTimeoutError\"]);\nconst TIMEOUT_MESSAGES = [\n  /^request timed out\\.?$/i,\n  /\\brequest to [\\w .-]+ timed out\\b/i,\n  /\\b(?:connection|socket|headers|stream) timed out\\b/i,\n];\n\nfunction isBareTimeout(e: { name?: unknown; message?: unknown }): boolean {\n  if (typeof e.name === \"string\" && TIMEOUT_NAMES.has(e.name)) return true;\n  if (typeof e.message !== \"string\") return false;\n  return TIMEOUT_MESSAGES.some((re) => re.test(e.message as string));\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 {\n      code?: unknown;\n      message?: unknown;\n      cause?: unknown;\n      name?: unknown;\n      status?: unknown;\n    };\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    // A 4xx is a permanent client error: the request is malformed, unauthorised\n    // or too large, and replaying it five times with backoff costs the user time\n    // and money without any chance of succeeding. Timeout *shape* must not\n    // override an explicit client-error status. 5xx and status-less timeouts\n    // stay on the retry path.\n    const clientError = typeof e.status === \"number\" && e.status >= 400 && e.status < 500;\n    if (!clientError && isBareTimeout(e)) return true;\n    cur = e.cause;\n  }\n  return false;\n}\n\n/**\n * Continuation injected when the host grants extra turns instead of letting the\n * run stop mid-task.\n *\n * Deliberately carries NO copy of the original request. An earlier version\n * echoed up to 600 chars of it, which was pure waste: the text was read out of\n * the very `messages` array being sent, so the model already had it verbatim.\n * Worse, after a compaction the first user message is the compaction summary,\n * so the \"original request\" echo would have quoted the summary back instead.\n * The instruction below is the only part that is not already in context.\n */\nfunction turnBudgetContinuationPrompt(): string {\n  return (\n    \"[You reached the turn limit for this segment but the work is not finished, \" +\n    \"so you have been granted more turns. Before continuing, state in one or two \" +\n    \"sentences what is already done and what remains, then keep going from there \" +\n    \"\\u2014 do not restart work that is already complete.]\"\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) {\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  // Raised in place by a granted turn-budget extension. The while-condition and\n  // the mid-task cut-off check both read this, never the base `maxTurns`.\n  let effectiveMaxTurns = maxTurns;\n  const maxTurnExtensions = Math.max(0, options.maxTurnExtensions ?? 2);\n  let turnExtensions = 0;\n  const maxContinuations = options.maxContinuations ?? 5;\n  // Rebuilt each turn: hosts may push tools onto the live `options.tools`\n  // array mid-run (background MCP connect, tool_search promotion) — the\n  // provider already sees them next turn via the shared array reference, so\n  // execution must resolve against the same up-to-date set.\n  let toolMap = new Map<string, AgentTool>((options.tools ?? []).map((t) => [t.name, t]));\n\n  const totalUsage: Usage = { inputTokens: 0, outputTokens: 0 };\n  let latestProviderUsage: Usage | undefined;\n  let usageAnchorIndex: number | undefined;\n  let turn = 0;\n  // Set when a turn executes tools and completes but the turn budget is now\n  // exhausted — the loop is about to stop mid-task. Drives the terminal\n  // `max_turns` signal below so callers can distinguish a cut-off from a clean\n  // finish (a silent stop otherwise looks like a truncated/empty result).\n  let hitMaxTurns = false;\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 runawayToolcallRetries = 0;\n  let overflowCompactionAttempts = 0;\n  let toolResultTruncationAttempted = false;\n  const invalidToolArgumentCounts = new Map<string, number>();\n  // A recoverable tool-argument fatal (empty args -- a provider stream\n  // glitch, see executeSingleToolCall) gets exactly one bounded auto-continue\n  // per agent run before it's surfaced as a real error. This mirrors what\n  // manually sending another message already fixes in practice, so the user\n  // doesn't have to do it by hand for a one-off upstream hiccup.\n  let toolArgumentAutoContinueUsed = false;\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_RUNAWAY_TOOLCALL_RETRIES = 2;\n  const RUNAWAY_TOOLCALL_RETRY_DELAY_MS = 1_000;\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  // Minimum streamed text worth preserving across a transport-failure retry.\n  // Below this, replaying the turn is cheaper than the extra history messages.\n  const MIN_PARTIAL_PRESERVE_CHARS = 200;\n  const PARTIAL_CONTINUATION_PROMPT =\n    \"[Your previous response was cut off by a connection failure. The text \" +\n    \"above is what was already delivered to the user. Continue exactly from \" +\n    \"where it stopped — do not repeat or restart it.]\";\n  // Bounded auto-continue after the model hits its output-token limit\n  // (stopReason \"max_tokens\" with no tool calls). The assistant partial is\n  // already in history, so the continuation resumes exactly where the output\n  // was clipped — no replay, no double-billing.\n  const MAX_OUTPUT_CONTINUATIONS = 2;\n  const MAX_TOKENS_CONTINUATION_PROMPT =\n    \"[Your previous response hit the output-token limit and was cut off. The \" +\n    \"text above is what was already delivered to the user. Continue exactly \" +\n    \"from where it stopped — do not repeat or restart it.]\";\n  let maxTokensContinuations = 0;\n  // Non-streaming fallback usage, aggregated per session (see \"stream_call\").\n  let providerCalls = 0;\n  let nonStreamingCalls = 0;\n  let warnedNonStreaming = false;\n  // A rejected output budget is worth exactly one retry: the ceiling the\n  // provider named is applied to the replay, so a second failure means the\n  // limit was not the problem and retrying again just burns the same tokens.\n  const MAX_OUTPUT_CEILING_RETRIES = 1;\n  let outputCeilingRetries = 0;\n  const ceilingKey = outputRouteKey({\n    provider: options.provider,\n    model: options.model,\n    baseUrl: options.baseUrl,\n  });\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  // Some providers reason silently server-side and emit no reasoning deltas, so\n  // their pre-output phase looks like dead air and never earns the dynamic\n  // thinking timeout extension below. This is always true for Sakana Fugu and\n  // for first-party OpenAI reasoning requests (the UI can show Thinking while\n  // Chat Completions exposes no reasoning_content). Give those calls a\n  // reasoning-sized budget before the first visible event. Without it, slower\n  // accounts or network paths repeatedly trip the 45s first-event / 90s hard\n  // caps even though the model is still working. Once output starts flowing,\n  // the normal mid-stream timeout takes over.\n  const usesSilentReasoningBudget =\n    options.provider === \"sakana\" || (options.provider === \"openai\" && options.thinking != null);\n  // A local backend (llama.cpp, vLLM, Ollama, LM Studio) can prefill a large\n  // prompt for minutes before its first token. Aborting there guarantees a\n  // retry that prefills from cold again, so the first-event watchdog is off for\n  // loopback hosts entirely — the 90s inter-event timer still arms as soon as\n  // the first event lands, and the caller's abort signal is untouched.\n  const localBackend = isLocalBackendUrl(options.baseUrl);\n  const firstEventTimeoutMs = localBackend\n    ? Number.POSITIVE_INFINITY\n    : usesSilentReasoningBudget\n      ? STREAM_THINKING_IDLE_TIMEOUT_MS // 5min before first visible token\n      : STREAM_FIRST_EVENT_TIMEOUT_MS; // 45s\n  const initialHardTimeoutMs =\n    localBackend || usesSilentReasoningBudget\n      ? STREAM_THINKING_HARD_TIMEOUT_MS // 10min absolute cap before output\n      : STREAM_HARD_TIMEOUT_MS; // 90s\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  // Cap accumulated arg chars and event count so one bad stream cannot hang the\n  // run indefinitely. The loop automatically replays the untouched turn twice;\n  // only repeated failures surface to the user.\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  let logicalTurnStartedAt = 0;\n  let firstProviderEventAt: number | undefined;\n  let providerDurationMs = 0;\n\n  try {\n    while (turn < effectiveMaxTurns) {\n      options.signal?.throwIfAborted();\n      turn++;\n      if (logicalTurnStartedAt === 0) logicalTurnStartedAt = Date.now();\n      toolMap = new Map((options.tools ?? []).map((t) => [t.name, t]));\n\n      // Estimate message payload size for diagnostics.\n      // Gated behind _diagFn — the char-counting loop is O(n) over the\n      // full message history and runs every turn. Skip it entirely when\n      // no diagnostic callback is registered (production default).\n      if (_diagFn) {\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          thinking: options.thinking ?? \"off\",\n          firstEventTimeoutMs,\n          initialHardTimeoutMs,\n          localBackend,\n        });\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 pendingMessages =\n          usageAnchorIndex === undefined ? [] : messages.slice(usageAnchorIndex + 1);\n        const transformed = await options.transformContext(messages, {\n          usage: latestProviderUsage,\n          pendingMessages,\n        });\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          latestProviderUsage = undefined;\n          usageAnchorIndex = undefined;\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      let providerAttemptStartedAt: number | undefined;\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      // Text streamed this attempt — preserved across transport-failure retries\n      // instead of being discarded and re-billed (see the retry branch below).\n      let attemptText = \"\";\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            : firstEventTimeoutMs;\n        // An infinite budget means \"no watchdog\" — never arm a timer for it.\n        if (!Number.isFinite(timeoutMs)) return;\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        : initialHardTimeoutMs;\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        providerCalls++;\n        if (useNonStreamingFallback) nonStreamingCalls++;\n        // The fallback is silent by design, so a session can keep dropping into\n        // it without anyone noticing. Each entry costs two stalled attempts\n        // first (STALL_RETRIES_BEFORE_NON_STREAMING), and a non-streamed turn\n        // that fails late is replayed in full instead of resuming from partial\n        // output — those tokens get paid for twice, and nothing renders until\n        // the whole reply lands. Three entries is no longer bad luck.\n        //\n        // Counts entries, not share: the flag is cleared after every actionable\n        // response (see below), so a healthy majority of calls is streaming\n        // even in a session that is falling back constantly.\n        if (!warnedNonStreaming && nonStreamingCalls >= 3) {\n          warnedNonStreaming = true;\n          diag(\"non_streaming_session\", {\n            nonStreamingCalls,\n            providerCalls,\n            provider: options.provider,\n            model: options.model,\n            impact:\n              \"streaming is disabled for this session after repeated stalls: failed turns are \" +\n              \"re-billed in full instead of resuming from partial output, and replies appear only \" +\n              \"when complete\",\n          });\n        }\n        streamCallStart = Date.now();\n        providerAttemptStartedAt = streamCallStart;\n        // Re-resolve auth per turn. A refresh performed by any process sharing\n        // auth.json invalidates the access token captured when this run began,\n        // so a pinned key silently dies partway through a long run. A resolver\n        // failure is not fatal here: fall back to the captured credential and\n        // let the provider report the real auth error.\n        let liveApiKey = options.apiKey;\n        let liveAccountId = options.accountId;\n        let liveProjectId = options.projectId;\n        if (options.resolveCredentials) {\n          try {\n            const fresh = await options.resolveCredentials();\n            liveApiKey = fresh.apiKey;\n            if (fresh.accountId !== undefined) liveAccountId = fresh.accountId;\n            if (fresh.projectId !== undefined) liveProjectId = fresh.projectId;\n          } catch (credErr) {\n            diag(\"credential_refresh_failed\", {\n              error: (credErr instanceof Error ? credErr.message : String(credErr)).slice(0, 200),\n            });\n          }\n        }\n        const result = stream({\n          provider: options.provider,\n          model: options.model,\n          messages,\n          tools: options.tools,\n          serverTools: options.serverTools,\n          toolChoice: options.toolChoice,\n          webSearch: options.webSearch,\n          // Clamped to whatever ceiling this route has already rejected us for\n          // (identity when nothing has been learned).\n          maxTokens: clampOutputTokens(ceilingKey, options.maxTokens),\n          temperature: options.temperature,\n          thinking: options.thinking,\n          apiKey: liveApiKey,\n          baseUrl: options.baseUrl,\n          signal: streamController.signal,\n          accountId: liveAccountId,\n          transportSessionId: options.transportSessionId,\n          projectId: liveProjectId,\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          if (firstProviderEventAt === undefined) firstProviderEventAt = pullTime;\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            attemptText += event.text;\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        if (firstProviderEventAt === undefined) firstProviderEventAt = Date.now();\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        // The provider named an output-token ceiling. Remember it for this\n        // provider+route+model so every later turn is clamped up front, and\n        // replay this turn once against the limit it just told us.\n        const statedCeiling = parseOutputTokenCeiling(err);\n        if (statedCeiling !== null) {\n          rememberOutputCeiling(ceilingKey, statedCeiling);\n          diag(\"output_ceiling_learned\", {\n            ceiling: statedCeiling,\n            requested: options.maxTokens,\n            provider: options.provider,\n            model: options.model,\n          });\n          if (outputCeilingRetries < MAX_OUTPUT_CEILING_RETRIES) {\n            outputCeilingRetries++;\n            yield {\n              type: \"retry\" as const,\n              reason: \"provider_error\" as const,\n              attempt: outputCeilingRetries,\n              maxAttempts: MAX_OUTPUT_CEILING_RETRIES,\n              delayMs: 0,\n              silent: true,\n            };\n            turn--; // The rejected request never reached the model.\n            continue;\n          }\n        }\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 pendingMessages =\n                usageAnchorIndex === undefined ? [] : messages.slice(usageAnchorIndex + 1);\n              const compacted = await options.transformContext(messages, {\n                force: true,\n                usage: latestProviderUsage,\n                pendingMessages,\n              });\n              if (compacted !== messages && compacted.length < messages.length) {\n                messages.length = 0;\n                messages.push(...compacted);\n                latestProviderUsage = undefined;\n                usageAnchorIndex = undefined;\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 blew\n        // past the size/count caps. The partial call was never added to message\n        // history, so replay the untouched turn automatically — exactly what a\n        // manual \"continue\" fixed, without forcing the user to intervene.\n        if (runawayDetected) {\n          diag(\"runaway_toolcall_aborted\", {\n            ...runawayDetected,\n            provider: options.provider,\n            model: options.model,\n          });\n          if (runawayToolcallRetries < MAX_RUNAWAY_TOOLCALL_RETRIES) {\n            runawayToolcallRetries++;\n            const delayMs = RUNAWAY_TOOLCALL_RETRY_DELAY_MS * runawayToolcallRetries;\n            diag(\"retry\", {\n              reason: \"runaway_toolcall\",\n              attempt: runawayToolcallRetries,\n              maxAttempts: MAX_RUNAWAY_TOOLCALL_RETRIES,\n              delayMs,\n              ...runawayDetected,\n            });\n            yield {\n              type: \"retry\" as const,\n              reason: \"runaway_toolcall\" as const,\n              attempt: runawayToolcallRetries,\n              maxAttempts: MAX_RUNAWAY_TOOLCALL_RETRIES,\n              delayMs,\n              silent: true,\n            };\n            await abortableSleep(delayMs, options.signal);\n            turn--; // The aborted provider attempt does not consume a turn.\n            continue;\n          }\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 repeatedly failed to close a tool call after ${MAX_RUNAWAY_TOOLCALL_RETRIES} automatic retries ` +\n                `(${detail}). Switch models and retry; 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          // Preserve partial output: everything streamed before the drop is\n          // already paid for (output tokens) and already shown to the user.\n          // Keep it as a completed assistant message + continuation instruction\n          // instead of replaying the whole turn from scratch (a replay re-bills\n          // 100% of the pre-drop output). Skipped when a\n          // tool call was mid-stream: partial tool-call JSON is unusable, and\n          // the model must re-issue the call intact on the replay.\n          let preservedChars = 0;\n          if (attemptText.length >= MIN_PARTIAL_PRESERVE_CHARS && toolcallDeltaCount === 0) {\n            messages.push({\n              role: \"assistant\" as const,\n              content: [{ type: \"text\" as const, text: attemptText }],\n            });\n            messages.push({\n              role: \"user\" as const,\n              content: PARTIAL_CONTINUATION_PROMPT,\n              provenance: {\n                source: \"runtime\" as const,\n                kind: \"continuation\" as const,\n                visibility: \"hidden\" as const,\n              },\n            });\n            preservedChars = attemptText.length;\n          }\n          diag(\"retry\", {\n            reason: cause,\n            attempt: stallRetries,\n            maxAttempts: MAX_STALL_RETRIES,\n            delayMs,\n            events: streamEventCount,\n            nonStreaming: useNonStreamingFallback,\n            preservedChars,\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            ...(preservedChars > 0 ? { preservedChars } : {}),\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          const cause = malformed\n            ? \"malformed_stream\"\n            : socketDrop\n              ? \"socket_drop\"\n              : \"stream_stall\";\n          diag(\"stall_exhausted\", {\n            stallRetries: MAX_STALL_RETRIES,\n            provider: options.provider,\n            model: options.model,\n            cause,\n            nonStreaming: useNonStreamingFallback,\n            events: streamEventCount,\n            eventTypes: eventTypeCounts,\n            lastEventType,\n            sinceLastEventMs: Date.now() - lastEventTime,\n            attemptDurationMs: Date.now() - streamCallStart,\n            maxConsumerLagMs,\n          });\n          yield {\n            type: \"error\" as const,\n            error: new GGAIError(\n              `The connection to the API provider stopped responding after ${MAX_STALL_RETRIES} automatic retries. ` +\n                `Your conversation is preserved.`,\n              {\n                source: \"network\",\n                hint: \"Retry once. If it keeps happening on this device, disable any VPN or proxy and allow GG Coder through firewall or antivirus web protection.\",\n                cause: err,\n              },\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 (providerAttemptStartedAt !== undefined) {\n          providerDurationMs += Date.now() - providerAttemptStartedAt;\n        }\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      runawayToolcallRetries = 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, but flag\n        // it so the terminal branch warns instead of ending silently.\n      }\n      const emptyExhausted = !hasActionableContent;\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.reasoningTokens) {\n        totalUsage.reasoningTokens =\n          (totalUsage.reasoningTokens ?? 0) + response.usage.reasoningTokens;\n      }\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 and anchor the provider's authoritative usage\n      // at that exact history position. Later tool/user messages stay pending\n      // until the next provider request observes them.\n      // EXCEPTION: an empty message (retries exhausted) is NOT appended — a\n      // contentless assistant turn poisons the history and every subsequent\n      // request in the session replays it and comes back empty again.\n      if (!emptyExhausted) {\n        messages.push(response.message);\n        latestProviderUsage = response.usage;\n        usageAnchorIndex = messages.length - 1;\n      }\n\n      const completedAt = Date.now();\n      const outputTokensPerSecond =\n        providerDurationMs > 0 && response.usage.outputTokens > 0\n          ? response.usage.outputTokens / (providerDurationMs / 1_000)\n          : undefined;\n      const timing = {\n        startedAt: logicalTurnStartedAt,\n        ...(firstProviderEventAt !== undefined\n          ? {\n              firstProviderEventAt,\n              ttftMs: Math.max(0, firstProviderEventAt - logicalTurnStartedAt),\n            }\n          : {}),\n        completedAt,\n        providerDurationMs,\n        ...(outputTokensPerSecond !== undefined ? { outputTokensPerSecond } : {}),\n      };\n      logicalTurnStartedAt = 0;\n      firstProviderEventAt = undefined;\n      providerDurationMs = 0;\n\n      yield {\n        type: \"turn_end\" as const,\n        turn,\n        stopReason: response.stopReason,\n        usage: response.usage,\n        timing,\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      // emptyExhausted is terminal regardless of stopReason: a contentless\n      // response has no tool calls to execute, and falling into the tool path\n      // would push an unpaired empty tool message into history.\n      if (emptyExhausted || (response.stopReason !== \"tool_use\" && allToolCalls.length === 0)) {\n        // Honest terminal states: a max_tokens / refusal / error stop with no\n        // tool calls is NOT a clean completion. For max_tokens, auto-continue\n        // a bounded number of times; otherwise warn and preserve the\n        // conversation (hosts render the incomplete-output warning).\n        if (emptyExhausted) {\n          // Provider returned no content after all retries — tell the host so\n          // the user sees a failure instead of a prompt that silently ends.\n          diag(\"empty_response_exhausted\", {\n            provider: options.provider,\n            model: options.model,\n            stopReason: response.stopReason,\n          });\n          yield { type: \"truncated\" as const, reason: \"empty_response\" as const, continued: false };\n        } else if (response.stopReason === \"max_tokens\") {\n          if (maxTokensContinuations < MAX_OUTPUT_CONTINUATIONS) {\n            maxTokensContinuations++;\n            diag(\"max_tokens_continuation\", {\n              attempt: maxTokensContinuations,\n              maxAttempts: MAX_OUTPUT_CONTINUATIONS,\n              provider: options.provider,\n              model: options.model,\n            });\n            yield { type: \"truncated\" as const, reason: \"max_tokens\" as const, continued: true };\n            messages.push({\n              role: \"user\" as const,\n              content: MAX_TOKENS_CONTINUATION_PROMPT,\n              provenance: {\n                source: \"runtime\" as const,\n                kind: \"continuation\" as const,\n                visibility: \"hidden\" as const,\n              },\n            });\n            continue;\n          }\n          yield { type: \"truncated\" as const, reason: \"max_tokens\" as const, continued: false };\n        } else if (response.stopReason === \"refusal\" || response.stopReason === \"error\") {\n          yield {\n            type: \"truncated\" as const,\n            reason:\n              response.stopReason === \"refusal\"\n                ? (\"refusal\" as const)\n                : (\"provider_error\" as const),\n            continued: false,\n          };\n        }\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      let fatalToolArgumentRecoverable = false;\n      let fatalToolArgumentToolName = \"\";\n      const markFatalToolArgumentError = (\n        error: Error,\n        recoverable: boolean,\n        toolName: string,\n      ): void => {\n        fatalToolArgumentError = error;\n        fatalToolArgumentRecoverable = recoverable;\n        fatalToolArgumentToolName = toolName;\n      };\n      const executionOptions: ToolBatchExecutionOptions = {\n        signal: options.signal,\n        maxToolResultChars: options.maxToolResultChars,\n        maxTurnToolResultChars: options.maxTurnToolResultChars,\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* executeToolCallsMixed(toolCalls, toolResults, executionOptions)\n        : yield* executeToolCallsParallel(toolCalls, toolResults, executionOptions);\n      messages.push({ role: \"tool\", content: executionResult.toolResults });\n      // The step is complete and durable-able: assistant message + every tool\n      // result are in `messages`, and the tools' side effects have already hit\n      // the filesystem. Hosts flush here so a crash before the next provider\n      // call cannot lose work that already happened.\n      yield { type: \"checkpoint\" as const, turn };\n      const toolsAborted = executionResult.aborted;\n\n      if (fatalToolArgumentError) {\n        if (fatalToolArgumentRecoverable && !toolArgumentAutoContinueUsed) {\n          // One-shot auto-continue: clear this tool's strike count so the\n          // model gets a fresh 3-attempt budget, tell the caller (UI) what\n          // happened, and fall through to the next turn instead of stopping --\n          // exactly what manually sending another message already does.\n          toolArgumentAutoContinueUsed = true;\n          for (const key of invalidToolArgumentCounts.keys()) {\n            if (key.startsWith(`${fatalToolArgumentToolName}:`))\n              invalidToolArgumentCounts.delete(key);\n          }\n          yield {\n            type: \"retry\" as const,\n            reason: \"tool_argument_glitch\" as const,\n            attempt: 1,\n            maxAttempts: 1,\n            delayMs: 0,\n            silent: false,\n          };\n        } else {\n          yield { type: \"error\" as const, error: fatalToolArgumentError };\n          break;\n        }\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      // This turn ran tools and wants to continue, but the budget is spent —\n      // the while-condition will now end the loop mid-task. Offer the host a\n      // bounded extension first (same shape as the max_tokens continuation\n      // above); only flag the hard cut-off if it declines or the cap is spent.\n      if (turn >= effectiveMaxTurns) {\n        let extended = false;\n        if (options.onTurnBudgetExhausted && turnExtensions < maxTurnExtensions) {\n          const extension = turnExtensions + 1;\n          let granted = false;\n          try {\n            granted = await options.onTurnBudgetExhausted({\n              turn,\n              maxTurns: effectiveMaxTurns,\n              extension,\n            });\n          } catch {\n            granted = false;\n          }\n          if (granted) {\n            turnExtensions = extension;\n            effectiveMaxTurns += maxTurns;\n            extended = true;\n            diag(\"turn_budget_extended\", {\n              turn,\n              grantedTurns: effectiveMaxTurns,\n              extension,\n              provider: options.provider,\n              model: options.model,\n            });\n            yield {\n              type: \"turn_budget_extended\" as const,\n              turn,\n              grantedTurns: effectiveMaxTurns,\n              extension,\n            };\n            messages.push({\n              role: \"user\" as const,\n              content: turnBudgetContinuationPrompt(),\n              provenance: {\n                source: \"runtime\" as const,\n                kind: \"continuation\" as const,\n                visibility: \"hidden\" as const,\n              },\n            });\n          }\n        }\n        if (!extended) {\n          hitMaxTurns = true;\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  // Hard turn-budget cut-off — surface a terminal signal BEFORE agent_done so\n  // the caller knows the run stopped mid-task and the output may be incomplete.\n  if (hitMaxTurns) {\n    diag(\"max_turns_reached\", {\n      turn,\n      maxTurns: effectiveMaxTurns,\n      extensions: turnExtensions,\n      provider: options.provider,\n      model: options.model,\n    });\n    yield {\n      type: \"max_turns\" as const,\n      totalTurns: turn,\n      maxTurns: effectiveMaxTurns,\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  maxTurnToolResultChars?: number;\n  toolMap: Map<string, AgentTool>;\n  invalidToolArgumentCounts: Map<string, number>;\n  /**\n   * `recoverable` flags the case where the failing call's raw args were a\n   * completely empty object -- the signature of a provider stream that cut\n   * off before emitting any `input_json_delta` for the tool call, rather\n   * than the model genuinely misunderstanding the schema. The agent loop\n   * gives recoverable failures one bounded auto-continue (exactly what\n   * manually sending another message already does) before treating them\n   * as fatal.\n   */\n  markFatalToolArgumentError: (error: Error, recoverable: boolean, toolName: string) => 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  let invalidArgAttempt: number | undefined;\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      // Strict (\"structured outputs\") schemas list every property as required\n      // with nullable optionals, so providers emit explicit `null` for fields\n      // the model meant to omit — Zod's `.optional()` accepts an absent key but\n      // rejects `null`. Parse verbatim first so legitimate nulls survive\n      // (`.nullable()` fields, MCP rawInputSchema passthrough); only when that\n      // fails, retry once with nulls stripped, keeping the original error if\n      // both attempts fail.\n      let parsed: unknown;\n      try {\n        parsed = tool.parameters.parse(toolCall.args);\n      } catch (originalError) {\n        if (tool.rawInputSchema) throw originalError;\n        try {\n          parsed = tool.parameters.parse(stripNullArguments(toolCall.args));\n        } catch {\n          throw originalError;\n        }\n      }\n      // Per-tool timeout: combine the caller's signal with a 5-minute default\n      // so no single tool can block the agent loop indefinitely.\n      // When the caller has no signal, AbortSignal.timeout is used alone.\n      // AbortSignal.any() merges them — either firing aborts the tool.\n      // A tool with a longer internal budget declares `timeoutMs`; without\n      // that, this default preempts the tool's own timeout and replaces its\n      // specific error with a generic cancellation.\n      const callerSignal = options.signal;\n      const toolTimeout = AbortSignal.timeout(tool.timeoutMs ?? DEFAULT_TOOL_TIMEOUT_MS);\n      const ctx: ToolContext = {\n        signal: callerSignal ? AbortSignal.any([callerSignal, toolTimeout]) : toolTimeout,\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 = redactValue(normalized.content);\n      details = redactValue(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        invalidArgAttempt = 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          // Empty raw args (no fields at all) is the signature of a provider\n          // stream that closed the tool_use block before ever emitting an\n          // input_json_delta -- an upstream glitch the model had no way to\n          // avoid, not a genuine misunderstanding of the schema. That case is\n          // `recoverable`: the agent loop gets one bounded auto-continue\n          // before giving up, matching what manually sending another message\n          // already fixes in practice.\n          const recoverable = Object.keys(toolCall.args ?? {}).length === 0;\n          options.markFatalToolArgumentError(\n            new GGAIError(\n              `The model repeatedly issued invalid arguments for tool \\`${toolCall.name}\\`. ` +\n                `This is usually an upstream model/tool-calling bug` +\n                (recoverable ? \" (the provider's stream returned empty tool-call arguments)\" : \"\") +\n                `. Your conversation is preserved; send another message or switch models to continue.`,\n              {\n                source: \"provider\",\n                hint:\n                  \"This is the model/provider's fault, not a ggcoder bug. \" +\n                  (recoverable\n                    ? \"ggcoder already retried automatically once; if it recurs, send another message or switch models.\"\n                    : \"Send another message or switch models to continue.\"),\n              },\n            ),\n            recoverable,\n            toolCall.name,\n          );\n        }\n      } else {\n        resultContent = redactValue(err instanceof Error ? err.message : String(err));\n      }\n    }\n  }\n\n  // All tool output crosses both an event boundary and the provider-context\n  // boundary below. Sanitize every branch, including unknown/validation errors.\n  resultContent = redactValue(resultContent);\n  details = redactValue(details);\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    ...(invalidArgAttempt === undefined ? {} : { invalidArgAttempt }),\n  });\n\n  return { toolCallId: toolCall.id, content: resultContent, isError };\n}\n\n/**\n * Mixed-mode execution: when a batch contains both parallel-safe and\n * sequential tools, group consecutive parallel-safe tools into batches\n * that run concurrently, and execute sequential tools one-at-a-time in\n * their original position. This preserves ordering semantics (a read\n * before a write sees pre-write content) while avoiding the latency\n * penalty of serializing independent read-only tools.\n *\n * Example: [grep, grep, write, grep] →\n *   Phase 1: grep + grep concurrently\n *   Phase 2: write (sequential)\n *   Phase 3: grep (sequential — alone in its batch)\n */\nasync function* executeToolCallsMixed(\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  // Calls actually handed to a tool. On abort this is what separates \"nothing\n  // ran, retry freely\" from \"it may have already happened\".\n  const dispatchedIds = new Set<string>();\n  const abortHandler = () => eventStream.abort(new Error(\"aborted\"));\n  options.signal?.addEventListener(\"abort\", abortHandler, { once: true });\n\n  // Partition tool calls into phases: each phase is either a group of\n  // parallel-safe tools (run concurrently) or a single sequential tool.\n  const phases: { parallel: ToolCall[]; sequential: ToolCall | null }[] = [];\n  let currentParallel: ToolCall[] = [];\n  for (const toolCall of toolCalls) {\n    const isSequential = options.toolMap.get(toolCall.name)?.executionMode === \"sequential\";\n    if (isSequential) {\n      // Flush accumulated parallel tools before the sequential one\n      if (currentParallel.length > 0) {\n        phases.push({ parallel: currentParallel, sequential: null });\n        currentParallel = [];\n      }\n      phases.push({ parallel: [], sequential: toolCall });\n    } else {\n      currentParallel.push(toolCall);\n    }\n  }\n  // Flush trailing parallel tools\n  if (currentParallel.length > 0) {\n    phases.push({ parallel: currentParallel, sequential: null });\n  }\n\n  void (async () => {\n    try {\n      for (const phase of phases) {\n        if (options.signal?.aborted) break;\n        if (phase.sequential) {\n          // Single sequential tool\n          dispatchedIds.add(phase.sequential.id);\n          const record = await executeSingleToolCall(phase.sequential, options, (event) =>\n            pushToolEvent(eventStream, state, event),\n          );\n          resultsById.set(record.toolCallId, record);\n        } else if (phase.parallel.length === 1) {\n          // Single parallel tool — no need for Promise.all overhead\n          dispatchedIds.add(phase.parallel[0]!.id);\n          const record = await executeSingleToolCall(phase.parallel[0]!, options, (event) =>\n            pushToolEvent(eventStream, state, event),\n          );\n          resultsById.set(record.toolCallId, record);\n        } else {\n          // Multiple parallel tools — run concurrently\n          await Promise.all(\n            phase.parallel.map(async (toolCall) => {\n              dispatchedIds.add(toolCall.id);\n              const record = await executeSingleToolCall(toolCall, options, (event) =>\n                pushToolEvent(eventStream, state, event),\n              );\n              resultsById.set(record.toolCallId, record);\n            }),\n          );\n        }\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, dispatchedIds);\n  capToolResults(toolResults, options.maxToolResultChars);\n  capTurnToolResults(toolResults, options.maxTurnToolResultChars);\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  // Calls actually handed to a tool. On abort this is what separates \"nothing\n  // ran, retry freely\" from \"it may have already happened\".\n  const dispatchedIds = new Set<string>();\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      dispatchedIds.add(toolCall.id);\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, dispatchedIds);\n  capToolResults(toolResults, options.maxToolResultChars);\n  capTurnToolResults(toolResults, options.maxTurnToolResultChars);\n  return { toolResults, aborted };\n}\n\n/**\n * A tool call that never reached its tool. Nothing ran, so nothing changed.\n */\nexport function cancelledBeforeStartText(name: string): string {\n  return `\\`${name}\\` was cancelled before it started, so it had no effect. Safe to retry.`;\n}\n\n/**\n * A tool call that started running and was cut off before reporting back.\n *\n * The distinction from {@link cancelledBeforeStartText} is the whole point: a\n * dispatched `git push`, deploy or MCP call may well have COMPLETED before the\n * abort landed. Telling the model it was \"interrupted\" reads as \"it did not\n * happen\", so the model repeats the side effect — or reports to the user that\n * something never ran when it did.\n */\nexport function indeterminateOutcomeText(name: string): string {\n  return (\n    `\\`${name}\\` started running and was cut off before it reported back, so its ` +\n    `outcome is UNKNOWN — it may have completed. Check the real state (re-read the ` +\n    `file, re-run a status command) before retrying it, and do not tell the user it ` +\n    `did not happen.`\n  );\n}\n\nfunction buildToolResults(\n  initialToolResults: ToolResult[],\n  toolCalls: ToolCall[],\n  resultsById: Map<string, ToolExecutionRecord>,\n  /** Calls handed to their tool. Absent = we could not tell, so assume dispatched. */\n  dispatchedIds?: ReadonlySet<string>,\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      // No record: either the abort landed before this call was dispatched\n      // (nothing ran) or after (effects unknown). Only the dispatch ledger\n      // can tell those apart, and the two demand opposite behaviour.\n      const dispatched = dispatchedIds?.has(toolCall.id) ?? true;\n      toolResults.push({\n        type: \"tool_result\",\n        toolCallId: toolCall.id,\n        content: dispatched\n          ? indeterminateOutcomeText(toolCall.name)\n          : cancelledBeforeStartText(toolCall.name),\n        isError: true,\n      });\n    }\n  }\n  return toolResults;\n}\n\nexport function capToolResults(\n  toolResults: ToolResult[],\n  maxToolResultChars: number | undefined,\n): 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    const originalChars = toolResult.content.length;\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    // Surrogate-safe: a raw char slice can cut an emoji in half and leave a\n    // lone surrogate, which makes the whole provider request body invalid JSON.\n    const head = sliceHead(toolResult.content, headChars);\n    const tail = sliceTail(toolResult.content, tailChars);\n    const omitted = originalChars - head.length - tail.length;\n    toolResult.content = head + `\\n\\n[... ${omitted} characters omitted ...]\\n\\n` + tail;\n    // Mark the divergence: the model + persistent transcript now hold this\n    // trimmed content, but the tool_call_end event already carried the full one.\n    toolResult.capped = {\n      originalChars,\n      keptChars: toolResult.content.length,\n      scope: \"per-result\",\n    };\n  }\n}\n\n/**\n * Aggregate per-turn budget across every tool result in one assistant turn.\n * A single result is bounded by per-tool truncation and `maxToolResultChars`,\n * but a wide parallel fan-out (8+ reads/bash calls) can still inject 100k+\n * uncached tokens in one turn. Water-filling: small results keep their full\n * size; only the largest results share what remains of the budget.\n */\nexport function capTurnToolResults(\n  toolResults: ToolResult[],\n  maxTurnToolResultChars: number | undefined,\n): void {\n  if (!maxTurnToolResultChars) return;\n  const textResults = toolResults.filter(\n    (toolResult): toolResult is ToolResult & { content: string } =>\n      typeof toolResult.content === \"string\",\n  );\n  const total = textResults.reduce((sum, toolResult) => sum + toolResult.content.length, 0);\n  if (total <= maxTurnToolResultChars) return;\n\n  // Water-filling allocation: process results smallest-first; each takes\n  // min(own size, fair share of what's left), releasing unused budget to the\n  // larger results behind it.\n  const bySize = [...textResults].sort((a, b) => a.content.length - b.content.length);\n  let remaining = maxTurnToolResultChars;\n  let left = bySize.length;\n  for (const toolResult of bySize) {\n    const fairShare = Math.floor(remaining / left);\n    left--;\n    if (toolResult.content.length <= fairShare) {\n      remaining -= toolResult.content.length;\n      continue;\n    }\n    remaining -= fairShare;\n    const originalChars = toolResult.content.length;\n    // Keep 70% head + 30% tail so errors/diagnostics at the end survive.\n    const headChars = Math.floor(fairShare * 0.7);\n    const tailChars = fairShare - headChars;\n    const omitted = originalChars - fairShare;\n    toolResult.content =\n      sliceHead(toolResult.content, headChars) +\n      `\\n\\n[... ${omitted} characters trimmed: this turn's combined tool results exceeded the ` +\n      `per-turn budget. Re-run this call alone with narrower filters or offset/limit if you ` +\n      `need the omitted content ...]\\n\\n` +\n      sliceTail(toolResult.content, tailChars);\n    // Mark the divergence (per-turn budget). Preserve an existing per-result\n    // marker's originalChars so the full pre-any-trim size stays visible.\n    toolResult.capped = {\n      originalChars: toolResult.capped?.originalChars ?? originalChars,\n      keptChars: toolResult.content.length,\n      scope: \"per-turn\",\n    };\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 head = sliceHead(text, headChars);\n  const tail = sliceTail(text, tailChars);\n  const omitted = text.length - head.length - tail.length;\n  return `${head}\\n\\n[... ${omitted} characters omitted after context overflow ...]\\n\\n${tail}`;\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 orphanCalls = (msg.content as ContentPart[])\n      .filter((p) => p.type === \"tool_call\")\n      .map((p) => p as ContentPart & { type: \"tool_call\"; id: string; name: string });\n    if (orphanCalls.length === 0) continue;\n\n    // A result is missing here after compaction, session restore or abort\n    // recovery — all of which discard whether the tool ever ran. Unknown is the\n    // only honest answer, and it is the safe one: it stops the model repeating\n    // a side effect that may already have landed.\n    const repaired = (call: { id: string; name: string }): ToolResult => ({\n      type: \"tool_result\",\n      toolCallId: call.id,\n      content: indeterminateOutcomeText(call.name),\n      isError: true,\n    });\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      for (const call of orphanCalls) {\n        if (!existingIds.has(call.id)) (next.content as ToolResult[]).push(repaired(call));\n      }\n    } else {\n      // No tool message follows — insert a synthetic one\n      messages.splice(i + 1, 0, { role: \"tool\" as const, content: orphanCalls.map(repaired) });\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","/**\n * A local inference server (llama.cpp, vLLM, Ollama, LM Studio) can spend\n * minutes prefilling a large prompt before it emits its first token. The\n * first-event watchdog that protects hosted streams turns that into an abort\n * → retry → cold-prefill loop that never converges, so it is disabled for\n * loopback backends.\n */\nexport function isLocalBackendUrl(baseUrl?: string): boolean {\n  if (!baseUrl) return false;\n  let host: string;\n  try {\n    host = new URL(baseUrl).hostname.toLowerCase();\n  } catch {\n    return false;\n  }\n\n  // URL normalises IPv6 hosts to bracketed form.\n  if (host === \"[::1]\" || host === \"::1\") return true;\n  if (host === \"localhost\" || host.endsWith(\".localhost\")) return true;\n  if (host === \"0.0.0.0\") return true;\n  if (host.endsWith(\".local\")) return true;\n\n  // 127.0.0.0/8\n  const ipv4 = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(host);\n  if (ipv4) {\n    const octets = ipv4.slice(1).map(Number);\n    if (octets.some((n) => n > 255)) return false;\n    return octets[0] === 127;\n  }\n\n  return false;\n}\n","/**\n * Learned output-token ceilings.\n *\n * A model's real `max_tokens` limit is not knowable from configuration: it\n * varies by provider, by route (a gateway can cap lower than the origin), by\n * model, and it changes under us. So the only reliable source is the provider\n * saying no — and when it does, that answer is worth keeping, because the\n * alternative is failing the same way on every subsequent turn of the session.\n *\n * In-memory and per-process by design: a stale ceiling that outlived a quota or\n * plan change should cost one rejection, not a config file the user has to find\n * and delete.\n */\n\nconst TTL_MS = 24 * 60 * 60 * 1000;\n\n/** Below this, a \"ceiling\" is more likely a parse accident than a real limit. */\nconst MIN_PLAUSIBLE_CEILING = 256;\nconst MAX_PLAUSIBLE_CEILING = 10_000_000;\n\nconst ceilings = new Map<string, { limit: number; expiresAt: number }>();\n\n/** Provider + route + model. The route matters: gateways cap independently. */\nexport function outputRouteKey(route: {\n  provider: string;\n  model: string;\n  baseUrl?: string;\n}): string {\n  return `${route.provider}\\u0000${route.baseUrl ?? \"default\"}\\u0000${route.model}`;\n}\n\n/**\n * Extract an accepted output-token ceiling from a provider rejection.\n *\n * Deliberately narrow. Every pattern requires the message to be about output\n * budget (`max_tokens` / completion / output tokens), because context-window\n * errors quote numbers too and clamping the OUTPUT budget in response to an\n * oversized INPUT would silently truncate every later reply for no reason.\n */\nexport function parseOutputTokenCeiling(err: unknown): number | null {\n  if (!(err instanceof Error)) return null;\n  const msg = err.message;\n  if (!/max_tokens|max output tokens|output tokens|completion tokens/i.test(msg)) return null;\n\n  // Payment failures talk about max_tokens too — OpenRouter's 402 reads\n  // \"requires more credits, or fewer max_tokens: you requested up to N tokens\".\n  // Learning a ceiling from that would clamp every later turn for a problem\n  // that a top-up fixes, and the number quoted is what we ASKED for, not a\n  // limit the provider will accept.\n  if ((err as Error & { statusCode?: unknown }).statusCode === 402) return null;\n  if (/credit|billing|payment|insufficient|balance|quota/i.test(msg)) return null;\n\n  const patterns = [\n    // Anthropic: \"max_tokens: 100000 > 64000, which is the maximum allowed…\"\n    /max_tokens:\\s*\\d+\\s*>\\s*(\\d+)/i,\n    // OpenAI: \"…this model supports at most 16384 completion tokens\"\n    /(?:at most|maximum of|limit of)\\s+([\\d,_]+)\\s*(?:output|completion)?\\s*tokens/i,\n    // Generic: \"max output tokens is 8192\" / \"max_tokens must be <= 4096\"\n    /(?:max_tokens|max output tokens)\\b[^\\d]{0,30}?([\\d,_]+)/i,\n  ];\n\n  for (const pattern of patterns) {\n    const raw = msg.match(pattern)?.[1];\n    if (raw === undefined) continue;\n    const limit = Number(raw.replace(/[,_]/g, \"\"));\n    if (\n      Number.isFinite(limit) &&\n      limit >= MIN_PLAUSIBLE_CEILING &&\n      limit <= MAX_PLAUSIBLE_CEILING\n    ) {\n      return limit;\n    }\n  }\n  return null;\n}\n\n/** Record a ceiling the provider stated. Lower wins: it is the one that held. */\nexport function rememberOutputCeiling(key: string, limit: number): void {\n  const known = outputTokenCeiling(key);\n  ceilings.set(key, {\n    limit: known === undefined ? limit : Math.min(known, limit),\n    expiresAt: Date.now() + TTL_MS,\n  });\n}\n\n/** The learned ceiling for a route, or undefined when none is known or fresh. */\nexport function outputTokenCeiling(key: string): number | undefined {\n  const entry = ceilings.get(key);\n  if (!entry) return undefined;\n  if (entry.expiresAt <= Date.now()) {\n    ceilings.delete(key);\n    return undefined;\n  }\n  return entry.limit;\n}\n\n/**\n * Clamp a requested output budget to what this route is known to accept.\n * Passes the request through untouched when nothing has been learned, so an\n * unproven route behaves exactly as before.\n */\nexport function clampOutputTokens(key: string, requested: number | undefined): number | undefined {\n  const ceiling = outputTokenCeiling(key);\n  if (ceiling === undefined) return requested;\n  return requested === undefined ? ceiling : Math.min(requested, ceiling);\n}\n\nexport function resetOutputCeilingsForTests(): void {\n  ceilings.clear();\n}\n"],"mappings":"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","names":["import_gg_ai"]}