190proof 1.0.111 → 1.0.113

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../index.ts","../interfaces.ts","../logger.ts","../utils.ts"],"sourcesContent":["import {\n ClaudeModel,\n GPTModel,\n OpenAIPayload,\n OpenAIMessage,\n OpenAIConfig,\n AnthropicAIPayload,\n AnthropicAIMessage,\n GenericMessage,\n AnthropicAIConfig,\n GenericPayload,\n GroqPayload,\n GroqModel,\n OpenRouterPayload,\n OpenRouterModel,\n ParsedResponseMessage,\n FunctionCall,\n AnthropicContentBlock,\n OpenAIContentBlock,\n GoogleAIPayload,\n GeminiModel,\n GoogleAIPart,\n File,\n GoogleAIMessage,\n AnyModel,\n Provider,\n} from \"./interfaces\";\nimport logger, { Identifier } from \"./logger\";\nimport {\n BedrockRuntimeClient,\n InvokeModelCommand,\n} from \"@aws-sdk/client-bedrock-runtime\";\nimport axios from \"axios\";\nimport { isHeicImage, timeout } from \"./utils\";\n\nconst sharp = require(\"sharp\");\nconst decode = require(\"heic-decode\");\n\nexport {\n ClaudeModel,\n GPTModel,\n GroqModel,\n GeminiModel,\n OpenRouterModel,\n OpenAIConfig,\n FunctionDefinition,\n FunctionCall,\n GenericMessage,\n GenericPayload,\n ToolResult,\n ParsedResponseMessage,\n OpenRouterProviderPreferences,\n AnyModel,\n Provider,\n} from \"./interfaces\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// SHARED UTILITIES\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * `AbortSignal.any` exists at runtime (Node 18.17+/20.3+) but isn't in the\n * pinned @types/node lib; centralize the cast so call sites stay typed. Used to\n * merge a caller's cancellation signal with an adapter's internal timeout\n * controller without clobbering either.\n */\nfunction anySignal(signals: AbortSignal[]): AbortSignal {\n return (AbortSignal as unknown as { any(s: AbortSignal[]): AbortSignal }).any(\n signals,\n );\n}\n\n/**\n * Run an axios-based provider call under a wall-clock deadline. Axios's\n * `timeout` option is a socket *idle* timer — providers that dribble\n * keep-alive bytes while a long generation runs (OpenRouter does this\n * explicitly) reset it forever, so a stuck upstream holds the request open\n * until the caller's walltime kills the whole turn (2026-07-26: a 9.7-minute\n * OpenRouter call with requestTimeoutMs=120s \"set\"). AbortSignal.timeout\n * bounds elapsed time instead; the idle `timeout` stays as a faster trigger\n * for fully dead sockets.\n */\nasync function withRequestDeadline<T>(\n apiName: string,\n requestTimeoutMs: number,\n signal: AbortSignal | undefined,\n fn: (mergedSignal: AbortSignal) => Promise<T>,\n): Promise<T> {\n const deadline = AbortSignal.timeout(requestTimeoutMs);\n try {\n return await fn(signal ? anySignal([signal, deadline]) : deadline);\n } catch (error) {\n // Axios surfaces any abort as a bare \"canceled\" — restore the real reason\n // so retry logs and model-facing errors say what actually happened.\n if (deadline.aborted && !signal?.aborted) {\n throw new Error(\n `${apiName} request exceeded hard deadline of ${requestTimeoutMs}ms`,\n );\n }\n throw error;\n }\n}\n\n/**\n * Generic retry wrapper for API calls with exponential backoff.\n */\nasync function withRetries<T>(\n identifier: Identifier,\n apiName: string,\n fn: () => Promise<T>,\n options: {\n retries?: number;\n baseDelayMs?: number;\n onError?: (error: any, attempt: number) => void;\n signal?: AbortSignal;\n } = {},\n): Promise<T> {\n const { retries = 5, baseDelayMs = 125, onError } = options;\n\n logger.log(identifier, `Calling ${apiName} API with retries`);\n\n let lastError: any;\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n return await fn();\n } catch (error: any) {\n lastError = error;\n\n // Caller cancelled — reject immediately, never retry. Keyed on\n // signal.aborted (not error.name/code) because some adapters re-wrap the\n // underlying abort error and lose its name (e.g. the Google adapter).\n if (options.signal?.aborted) throw error;\n\n if (onError) {\n onError(error, attempt);\n } else {\n logger.error(\n identifier,\n `Retry #${attempt} error: ${error.message}`,\n error.response?.data || error,\n );\n }\n\n await timeout(baseDelayMs * attempt);\n }\n }\n\n // Fold the underlying cause into .message so it survives callers that read\n // error.message (and drop error.cause) — otherwise the raw reason (timeout,\n // provider 4xx body, etc.) never reaches the agent's model-facing error. Prefer\n // the provider's response body, which is richer than axios's \"Request failed\n // with status code N\".\n const detail =\n lastError?.response?.data?.error?.message ||\n lastError?.message ||\n String(lastError);\n const error = new Error(\n `Failed to call ${apiName} API after ${retries} attempts: ${detail}`,\n ) as any;\n error.cause = lastError;\n throw error;\n}\n\nfunction parseStreamedResponse(\n identifier: Identifier,\n paragraph: string,\n toolCallAccumulators: { id?: string; name: string; arguments: string }[],\n allowedFunctionNames: Set<string> | null,\n reasoning?: string,\n): ParsedResponseMessage {\n const functionCalls: FunctionCall[] = [];\n\n for (let i = 0; i < toolCallAccumulators.length; i++) {\n const acc = toolCallAccumulators[i];\n if (!acc.name || !acc.arguments) continue;\n\n if (allowedFunctionNames && !allowedFunctionNames.has(acc.name)) {\n throw new Error(\n `Stream error: received function call with unknown name: ${acc.name}`,\n );\n }\n\n try {\n functionCalls.push({\n id: acc.id || `call_${i}`,\n name: acc.name,\n arguments: JSON.parse(acc.arguments),\n });\n } catch (error) {\n logger.error(\n identifier,\n \"Error parsing function call arguments:\",\n acc.arguments,\n );\n throw error;\n }\n }\n\n if (!paragraph && !functionCalls.length) {\n logger.error(\n identifier,\n \"Stream error: received message without content or function_call:\",\n JSON.stringify({ paragraph, toolCallAccumulators }),\n );\n throw new Error(\n \"Stream error: received message without content or function_call\",\n );\n }\n\n return {\n role: \"assistant\",\n content: paragraph || null,\n function_call: functionCalls[0] || null,\n function_calls: functionCalls,\n files: [],\n reasoning: reasoning || undefined,\n usage: null,\n };\n}\n\nfunction truncatePayload(payload: OpenAIPayload): string {\n return JSON.stringify(\n {\n ...payload,\n messages: payload.messages.map((message) => {\n const truncatedMessage = { ...message };\n if (typeof truncatedMessage.content === \"string\") {\n truncatedMessage.content = truncatedMessage.content.slice(0, 100);\n } else if (Array.isArray(truncatedMessage.content)) {\n truncatedMessage.content = truncatedMessage.content.map((block) => {\n if (block.type === \"image_url\") {\n return {\n ...block,\n image_url: { url: block.image_url.url.slice(0, 100) },\n };\n }\n return block;\n });\n }\n return truncatedMessage;\n }),\n },\n null,\n 2,\n );\n}\n\nasync function getNormalizedBase64PNG(\n url: string,\n mime: string,\n): Promise<string> {\n const response = await axios.get(url, { responseType: \"arraybuffer\" });\n\n let imageBuffer = Buffer.from(response.data);\n let sharpOptions = {};\n\n if (isHeicImage(url, mime)) {\n const imageData = await decode({ buffer: imageBuffer });\n imageBuffer = Buffer.from(imageData.data);\n sharpOptions = {\n raw: {\n width: imageData.width,\n height: imageData.height,\n channels: 4,\n },\n };\n }\n\n // Limits size of image to < 5MB Anthropic limit\n const resizedBuffer = await sharp(imageBuffer, sharpOptions)\n .withMetadata()\n .resize(1024, 1024, { fit: \"inside\", withoutEnlargement: true })\n .png()\n .toBuffer();\n\n return resizedBuffer.toString(\"base64\");\n}\n\nconst ALLOWED_IMAGE_MIME_TYPES = [\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\",\n];\n\n// ─────────────────────────────────────────────────────────────────────────────\n// OPENAI\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface OpenAIRequestConfig {\n endpoint: string;\n headers: Record<string, string>;\n}\n\nfunction buildOpenAIRequestConfig(\n identifier: Identifier,\n model: string,\n config: OpenAIConfig | undefined,\n): OpenAIRequestConfig {\n if (!config) {\n config = {\n service: \"openai\",\n apiKey: process.env.OPENAI_API_KEY as string,\n baseUrl: \"\",\n };\n }\n\n if (config.service === \"azure\") {\n logger.log(identifier, \"Using Azure OpenAI service:\", model);\n\n if (!config.modelConfigMap) {\n throw new Error(\n \"OpenAI config modelConfigMap is required when using Azure OpenAI service.\",\n );\n }\n\n const azureConfig = config.modelConfigMap[model as GPTModel];\n if (!azureConfig?.endpoint) {\n throw new Error(\"Azure OpenAI endpoint is required in modelConfigMap.\");\n }\n\n const endpoint = `${azureConfig.endpoint}/openai/deployments/${azureConfig.deployment}/chat/completions?api-version=${azureConfig.apiVersion}`;\n logger.log(identifier, \"Using endpoint:\", endpoint);\n\n return {\n endpoint,\n headers: {\n \"Content-Type\": \"application/json\",\n \"api-key\": azureConfig.apiKey,\n },\n };\n }\n\n // Default: OpenAI (or any OpenAI-compatible server via config.baseUrl)\n logger.log(identifier, \"Using OpenAI service:\", model);\n if (config.orgId) {\n logger.log(identifier, \"Using orgId:\", config.orgId);\n }\n\n const base = (config.baseUrl?.trim() || \"https://api.openai.com/v1\").replace(\n /\\/$/,\n \"\",\n );\n return {\n endpoint: `${base}/chat/completions`,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${config.apiKey}`,\n ...(config.orgId ? { \"OpenAI-Organization\": config.orgId } : {}),\n },\n };\n}\n\n/**\n * Keep only OpenAI-compat `reasoning.*` blocks when echoing reasoning_details.\n * A cross-provider fallback replays reasoningDetails captured from Anthropic\n * (`thinking`/`redacted_thinking`), which don't belong in reasoning_details.\n * Returns undefined when nothing native-shaped remains.\n */\nfunction filterOpenAICompatReasoningDetails(details: any): any[] | undefined {\n if (!Array.isArray(details)) return details || undefined;\n const blocks = details.filter(\n (block: any) =>\n typeof block?.type === \"string\" && block.type.startsWith(\"reasoning.\"),\n );\n return blocks.length ? blocks : undefined;\n}\n\nasync function prepareOpenAIPayload(\n identifier: Identifier,\n payload: GenericPayload,\n): Promise<OpenAIPayload> {\n const preparedPayload: OpenAIPayload = {\n model: payload.model as GPTModel,\n messages: [],\n tools: payload.functions?.map((fn) => ({\n type: \"function\",\n function: fn,\n })),\n tool_choice: payload.function_call\n ? typeof payload.function_call === \"string\"\n ? payload.function_call\n : { type: \"function\", function: payload.function_call }\n : undefined,\n };\n\n for (const message of payload.messages) {\n // role:\"tool\" → one OpenAI tool message per result (parallel calls expand).\n if (message.role === \"tool\") {\n for (const tr of message.toolResults || []) {\n preparedPayload.messages.push({\n role: \"tool\",\n tool_call_id: tr.toolCallId,\n content: tr.content,\n });\n }\n continue;\n }\n\n const contentBlocks: OpenAIContentBlock[] = [];\n\n if (message.content) {\n contentBlocks.push({ type: \"text\", text: message.content });\n }\n\n for (const file of message.files || []) {\n if (ALLOWED_IMAGE_MIME_TYPES.includes(file.mimeType)) {\n if (file.url) {\n contentBlocks.push({\n type: \"image_url\",\n image_url: { url: file.url },\n });\n contentBlocks.push({ type: \"text\", text: `Image (${file.url})` });\n } else if (file.data) {\n contentBlocks.push({\n type: \"image_url\",\n image_url: { url: `data:${file.mimeType};base64,${file.data}` },\n });\n }\n } else if (file.url) {\n // Non-image file with URL - add text reference\n contentBlocks.push({\n type: \"text\",\n text: `File (${file.url})`,\n });\n }\n }\n\n const outMessage: OpenAIMessage = {\n role: message.role,\n // OpenAI wants null (not []) content on a tool-call-only assistant turn.\n content: contentBlocks.length ? contentBlocks : null,\n };\n if (message.functionCalls?.length) {\n outMessage.tool_calls = message.functionCalls.map((fc, i) => ({\n id: fc.id ?? `call_${i}`,\n type: \"function\" as const,\n function: {\n name: fc.name,\n arguments: JSON.stringify(fc.arguments),\n },\n }));\n }\n // Reasoning passthrough — only when the caller supplied it (never injected).\n if (message.reasoning) outMessage.reasoning = message.reasoning;\n const reasoningDetails = filterOpenAICompatReasoningDetails(\n message.reasoningDetails,\n );\n if (reasoningDetails) outMessage.reasoning_details = reasoningDetails;\n preparedPayload.messages.push(outMessage);\n }\n\n return preparedPayload;\n}\n\nasync function callOpenAIStream(\n id: Identifier,\n openAiPayload: OpenAIPayload,\n openAiConfig: OpenAIConfig | undefined,\n chunkTimeoutMs: number,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const functionNames: Set<string> | null = openAiPayload.tools\n ? new Set(openAiPayload.tools.map((fn) => fn.function.name as string))\n : null;\n\n const { endpoint, headers } = buildOpenAIRequestConfig(\n id,\n openAiPayload.model,\n openAiConfig,\n );\n\n const controller = new AbortController();\n // Overall per-attempt deadline (separate from the per-chunk stall timeout\n // below): aborts the same controller if the whole stream runs past the\n // budget. unref'd so it never holds the event loop; cleared on the success\n // path, and a no-op abort on a finished stream otherwise.\n const overallTimeout = setTimeout(() => {\n logger.error(id, `Request timeout after ${requestTimeoutMs}ms`);\n controller.abort();\n }, requestTimeoutMs);\n if (typeof overallTimeout === \"object\" && \"unref\" in overallTimeout) {\n overallTimeout.unref();\n }\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ ...openAiPayload, stream: true }),\n // Merge (don't overwrite) the internal timeout controller with the caller's\n // cancellation signal so both an internal timeout and an external abort stop\n // the stream.\n signal: signal ? anySignal([controller.signal, signal]) : controller.signal,\n });\n\n if (!response.body) {\n throw new Error(\"Stream error: no response body\");\n }\n\n let paragraph = \"\";\n let reasoning = \"\";\n const toolCallAccumulators: { id?: string; name: string; arguments: string }[] =\n [];\n\n const reader = response.body.getReader();\n let partialChunk = \"\";\n let chunkIndex = -1;\n\n const createAbortTimeout = () =>\n setTimeout(() => {\n logger.error(id, `Stream timeout after ${chunkTimeoutMs}ms`);\n controller.abort();\n }, chunkTimeoutMs);\n\n while (true) {\n chunkIndex++;\n const abortTimeout = createAbortTimeout();\n const { done, value } = await reader.read();\n clearTimeout(abortTimeout);\n\n if (done) {\n logger.error(\n id,\n `Stream ended prematurely after ${chunkIndex + 1} chunks`,\n );\n throw new Error(\"Stream error: ended prematurely\");\n }\n\n let chunk = new TextDecoder().decode(value);\n if (partialChunk) {\n chunk = partialChunk + chunk;\n partialChunk = \"\";\n }\n\n const jsonStrings = chunk.split(/^data: /gm);\n\n for (const jsonString of jsonStrings) {\n if (!jsonString) continue;\n\n if (jsonString.includes(\"[DONE]\")) {\n clearTimeout(overallTimeout);\n return parseStreamedResponse(\n id,\n paragraph,\n toolCallAccumulators,\n functionNames,\n reasoning,\n );\n }\n\n let json;\n try {\n json = JSON.parse(jsonString.trim());\n } catch {\n partialChunk = jsonString;\n continue;\n }\n\n if (!json.choices?.length) {\n if (json.error) {\n logger.error(id, \"Stream error from OpenAI:\", json.error);\n const error = new Error(\"Stream error: OpenAI error\") as any;\n error.data = json.error;\n error.requestBody = truncatePayload(openAiPayload);\n throw error;\n }\n if (chunkIndex !== 0) {\n logger.error(id, \"Stream error: no choices in JSON:\", json);\n }\n continue;\n }\n\n const toolCalls = json.choices[0]?.delta?.tool_calls;\n if (toolCalls) {\n for (const toolCall of toolCalls) {\n const idx = toolCall.index ?? 0;\n while (toolCallAccumulators.length <= idx) {\n toolCallAccumulators.push({ name: \"\", arguments: \"\" });\n }\n // The id arrives on the first fragment of each call.\n if (toolCall.id) toolCallAccumulators[idx].id = toolCall.id;\n if (toolCall.function?.name)\n toolCallAccumulators[idx].name += toolCall.function.name;\n if (toolCall.function?.arguments)\n toolCallAccumulators[idx].arguments += toolCall.function.arguments;\n }\n }\n\n const text = json.choices[0]?.delta?.content;\n if (text) paragraph += text;\n\n // Reasoning models (OpenRouter/OAI-compatible) stream a parallel\n // `reasoning` channel; accumulate it so callers can round-trip it.\n const reasoningDelta = json.choices[0]?.delta?.reasoning;\n if (reasoningDelta) reasoning += reasoningDelta;\n }\n }\n}\n\nasync function callOpenAI(\n id: Identifier,\n openAiPayload: OpenAIPayload,\n openAiConfig: OpenAIConfig | undefined,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const { endpoint, headers } = buildOpenAIRequestConfig(\n id,\n openAiPayload.model,\n openAiConfig,\n );\n\n // Per-attempt deadline covering the request + body read (fetch has no built-in\n // timeout). Cleared once the body is read; an abort surfaces as a retryable error.\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), requestTimeoutMs);\n let data: any;\n try {\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ ...openAiPayload, stream: false }),\n // Merge the internal timeout controller with the caller's cancellation signal.\n signal: signal ? anySignal([controller.signal, signal]) : controller.signal,\n });\n\n if (!response.ok) {\n const errorData = await response.json();\n logger.error(id, \"OpenAI API error:\", errorData);\n throw new Error(`OpenAI API Error: ${errorData.error.message}`);\n }\n\n data = await response.json();\n } finally {\n clearTimeout(timer);\n }\n\n if (!data.choices?.length) {\n if (data.error) {\n logger.error(id, \"OpenAI error:\", data.error);\n throw new Error(`OpenAI error: ${data.error.message}`);\n }\n throw new Error(\"OpenAI error: No choices returned.\");\n }\n\n const choice = data.choices[0];\n\n // Check for tool_calls (modern API) first, fall back to function_call (legacy)\n const toolCalls = choice.message?.tool_calls;\n const functionCalls: FunctionCall[] = [];\n\n if (toolCalls?.length) {\n for (let i = 0; i < toolCalls.length; i++) {\n const tc = toolCalls[i];\n functionCalls.push({\n id: tc.id ?? `call_${i}`,\n name: tc.function.name,\n arguments: JSON.parse(tc.function.arguments),\n });\n }\n } else if (choice.function_call) {\n functionCalls.push({\n id: \"call_0\",\n name: choice.function_call.name,\n arguments: JSON.parse(choice.function_call.arguments),\n });\n }\n\n // An empty 200 (no content, no tool call) is not a usable answer — throw so\n // withRetries retries and callWithRetries can fall back. (Mirrors the\n // streaming path's guard in parseStreamedResponse.)\n if (!choice.message?.content && !functionCalls.length) {\n logger.error(\n id,\n \"OpenAI: received message without content or function_call:\",\n JSON.stringify(data),\n );\n throw new Error(\n \"OpenAI: received message without content or function_call\",\n );\n }\n\n return {\n role: \"assistant\",\n content: choice.message.content || null,\n function_call: functionCalls[0] || null,\n function_calls: functionCalls,\n files: [],\n reasoning: choice.message?.reasoning ?? undefined,\n reasoningDetails: choice.message?.reasoning_details ?? undefined,\n usage: data.usage\n ? {\n prompt_tokens: data.usage.prompt_tokens,\n completion_tokens: data.usage.completion_tokens,\n total_tokens: data.usage.total_tokens,\n cached_tokens: data.usage.prompt_tokens_details?.cached_tokens ?? 0,\n }\n : null,\n };\n}\n\nasync function callOpenAiWithRetries(\n id: Identifier,\n openAiPayload: OpenAIPayload,\n openAiConfig?: OpenAIConfig,\n retries: number = 5,\n chunkTimeoutMs: number = 15_000,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n logger.log(\n id,\n \"Calling OpenAI API with retries:\",\n openAiConfig?.service,\n openAiPayload.model,\n );\n\n const modelStr = openAiPayload.model as string;\n const useStreaming =\n modelStr !== GPTModel.O1_MINI &&\n modelStr !== GPTModel.O1_PREVIEW &&\n !modelStr.startsWith(\"o1\");\n\n return withRetries(\n id,\n \"OpenAI\",\n async () => {\n if (useStreaming) {\n return callOpenAIStream(\n id,\n openAiPayload,\n openAiConfig,\n chunkTimeoutMs,\n requestTimeoutMs,\n signal,\n );\n } else {\n return callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs, signal);\n }\n },\n {\n retries,\n signal,\n baseDelayMs: 250,\n onError: (error, attempt) => {\n logger.error(\n id,\n `Retry #${attempt} error: ${error.message}`,\n error.response?.data || error.data || error,\n );\n\n // Remove images on content policy violation\n if (error.data?.code === \"content_policy_violation\") {\n logger.log(id, \"Removing images due to content policy violation\");\n openAiPayload.messages.forEach((message: OpenAIMessage) => {\n if (Array.isArray(message.content)) {\n message.content = message.content.filter(\n (content) => content.type === \"text\",\n );\n }\n });\n }\n },\n },\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ANTHROPIC\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction jigAnthropicMessages(\n messages: AnthropicAIMessage[],\n): AnthropicAIMessage[] {\n const hasToolBlock = (content: AnthropicAIMessage[\"content\"]) =>\n Array.isArray(content) &&\n content.some((b) => b.type === \"tool_use\" || b.type === \"tool_result\");\n\n let jiggedMessages = messages.slice();\n\n // Ensure first message is from user\n if (jiggedMessages[0]?.role !== \"user\") {\n jiggedMessages = [\n { role: \"user\" as const, content: \"...\" },\n ...jiggedMessages,\n ];\n }\n\n // Group consecutive messages with the same role\n jiggedMessages = jiggedMessages.reduce((acc, message) => {\n if (acc.length === 0) return [message];\n\n const lastMessage = acc[acc.length - 1];\n if (lastMessage.role === message.role) {\n const lastContent = Array.isArray(lastMessage.content)\n ? lastMessage.content\n : [{ type: \"text\" as const, text: lastMessage.content }];\n const newContent = Array.isArray(message.content)\n ? message.content\n : [{ type: \"text\" as const, text: message.content }];\n\n // Never inject a text separator into a turn carrying tool_use/tool_result\n // blocks — it would sit between a tool_use and its result and break\n // Anthropic's pairing requirement.\n const separator: AnthropicContentBlock[] =\n hasToolBlock(lastMessage.content) || hasToolBlock(message.content)\n ? []\n : [{ type: \"text\", text: \"\\n\\n---\\n\\n\" }];\n\n lastMessage.content = [...lastContent, ...separator, ...newContent];\n return acc;\n }\n\n // Convert string content to text content block\n if (typeof message.content === \"string\") {\n message.content = [{ type: \"text\", text: message.content }];\n }\n\n return [...acc, message];\n }, [] as AnthropicAIMessage[]);\n\n // Ensure last message is from user — but never append a placeholder after an\n // unanswered tool_use turn (a text-only user can't satisfy it).\n const last = jiggedMessages[jiggedMessages.length - 1];\n if (last?.role === \"assistant\" && !hasToolBlock(last.content)) {\n jiggedMessages.push({ role: \"user\", content: \"...\" });\n }\n\n return jiggedMessages;\n}\n\nasync function prepareAnthropicPayload(\n _identifier: Identifier,\n payload: GenericPayload,\n): Promise<AnthropicAIPayload> {\n const preparedPayload: AnthropicAIPayload = {\n model: payload.model as ClaudeModel,\n messages: [],\n functions: payload.functions,\n temperature: payload.temperature,\n // Map the generic function_call to Anthropic tool_choice (\"none\" forces a\n // text-only turn). Only meaningful alongside tools — callAnthropic sends\n // it only when tools are present (tool_choice without tools 400s).\n tool_choice: payload.function_call\n ? typeof payload.function_call === \"string\"\n ? { type: payload.function_call }\n : { type: \"tool\", name: payload.function_call.name }\n : undefined,\n };\n\n for (const message of payload.messages) {\n if (message.role === \"system\") {\n preparedPayload.system = message.content;\n continue;\n }\n\n // role:\"tool\" → a user message carrying tool_result blocks (parallel\n // results share one message, matching Anthropic's expected shape).\n if (message.role === \"tool\") {\n preparedPayload.messages.push({\n role: \"user\",\n content: (message.toolResults || []).map((tr) => ({\n type: \"tool_result\" as const,\n tool_use_id: tr.toolCallId,\n content: tr.content,\n })),\n });\n continue;\n }\n\n const contentBlocks: AnthropicContentBlock[] = [];\n\n if (message.content) {\n contentBlocks.push({ type: \"text\", text: message.content });\n }\n\n for (const file of message.files || []) {\n if (ALLOWED_IMAGE_MIME_TYPES.includes(file.mimeType)) {\n if (file.url) {\n if (message.role == \"user\") {\n // anthropic assistant turns can't have images\n contentBlocks.push({\n type: \"image\",\n source: {\n type: \"base64\",\n media_type: \"image/png\",\n data: await getNormalizedBase64PNG(file.url, file.mimeType),\n },\n });\n }\n contentBlocks.push({ type: \"text\", text: `Image (${file.url})` });\n } else if (file.data) {\n if (message.role == \"user\") {\n // anthropic assistant turns can't have images\n contentBlocks.push({\n type: \"image\",\n source: {\n type: \"base64\",\n media_type: file.mimeType as any,\n data: file.data,\n },\n });\n }\n }\n } else if (file.url) {\n // Non-image file with URL - add text reference\n contentBlocks.push({\n type: \"text\",\n text: `File (${file.url})`,\n });\n }\n }\n\n // Thinking blocks (if the caller echoes them) must lead an assistant turn,\n // before text; tool_use blocks come last. Only Anthropic's own block shapes\n // survive: a cross-provider fallback replays reasoningDetails captured from\n // another provider (e.g. OpenRouter `reasoning.text`), and Anthropic 400s\n // on the unknown input tag.\n const leadingBlocks: AnthropicContentBlock[] =\n message.role === \"assistant\" && Array.isArray(message.reasoningDetails)\n ? message.reasoningDetails.filter(\n (block: any) =>\n block?.type === \"thinking\" ||\n block?.type === \"redacted_thinking\",\n )\n : [];\n const toolUseBlocks: AnthropicContentBlock[] = (\n message.functionCalls || []\n ).map((fc, i) => ({\n type: \"tool_use\" as const,\n id: fc.id ?? `call_${i}`,\n name: fc.name,\n input: fc.arguments,\n }));\n\n preparedPayload.messages.push({\n role: message.role,\n content: [...leadingBlocks, ...contentBlocks, ...toolUseBlocks],\n });\n }\n\n return preparedPayload;\n}\n\nasync function callAnthropic(\n id: Identifier,\n payload: AnthropicAIPayload,\n config?: AnthropicAIConfig,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const anthropicMessages = jigAnthropicMessages(payload.messages);\n const tools = payload.functions?.map((f) => ({\n ...f,\n input_schema: f.parameters,\n parameters: undefined,\n }));\n\n let data;\n\n if (config?.service === \"bedrock\") {\n const AWS_REGION = \"us-east-1\";\n const MODEL_ID = \"anthropic.claude-3-haiku-20240307-v1:0\";\n\n const client = new BedrockRuntimeClient({ region: AWS_REGION });\n const bedrockPayload = {\n anthropic_version: \"bedrock-2023-05-31\",\n max_tokens: 4096,\n messages: anthropicMessages,\n tools,\n };\n\n const response = await client.send(\n new InvokeModelCommand({\n contentType: \"application/json\",\n body: JSON.stringify(bedrockPayload),\n modelId: MODEL_ID,\n }),\n { abortSignal: signal },\n );\n\n const decodedResponseBody = new TextDecoder().decode(response.body);\n data = JSON.parse(decodedResponseBody);\n } else {\n // Default: Anthropic API\n // Prompt caching: mark a breakpoint on the last tool only. Tool schemas\n // are fully static and identical across users, so that span gets real\n // cache reads; the system prompt is left uncached because callers embed\n // per-user / per-minute content in it, and a breakpoint after a volatile\n // span pays 1.25x cache writes with near-zero reads. Anthropic ignores\n // breakpoints below the model's minimum cacheable length, so small tool\n // sets are a safe no-op.\n const cachedTools = tools?.length\n ? [\n ...tools.slice(0, -1),\n { ...tools[tools.length - 1], cache_control: { type: \"ephemeral\" } },\n ]\n : tools;\n const response = await withRequestDeadline(\n \"Anthropic\",\n requestTimeoutMs,\n signal,\n (mergedSignal) =>\n axios.post(\n \"https://api.anthropic.com/v1/messages\",\n {\n model: payload.model,\n messages: anthropicMessages,\n tools: cachedTools,\n // tool_choice requires tools in the request; drop it otherwise.\n tool_choice: cachedTools?.length ? payload.tool_choice : undefined,\n temperature: payload.temperature,\n system: payload.system,\n max_tokens: 4096,\n },\n {\n headers: {\n \"content-type\": \"application/json\",\n \"x-api-key\": process.env.ANTHROPIC_API_KEY as string,\n \"anthropic-version\": \"2023-06-01\",\n \"anthropic-beta\": \"tools-2024-04-04\",\n },\n timeout: requestTimeoutMs,\n signal: mergedSignal,\n },\n ),\n );\n data = response.data;\n }\n\n const answers = data.content;\n if (!answers?.[0]) {\n logger.error(id, \"Missing answer in Anthropic API response:\", data);\n throw new Error(\"Missing answer in Anthropic API\");\n }\n\n let textResponse = \"\";\n const functionCalls: FunctionCall[] = [];\n // Native API thinking blocks (`{type:\"thinking\",thinking,signature}` /\n // `redacted_thinking`), kept raw so callers can echo them back verbatim —\n // their signatures are validated by Anthropic on the next turn.\n const reasoningBlocks: any[] = [];\n\n for (const answer of answers) {\n if (!answer.type) {\n logger.error(id, \"Missing answer type in Anthropic API response:\", data);\n throw new Error(\"Missing answer type in Anthropic API\");\n }\n\n if (answer.type === \"text\") {\n let text = answer.text\n .replace(/<thinking>.*?<\\/thinking>/gs, \"\")\n .replace(/<answer>|<\\/answer>/gs, \"\")\n .trim();\n\n if (!text) {\n text = answer.text.replace(\n /<thinking>|<\\/thinking>|<answer>|<\\/answer>/gs,\n \"\",\n );\n logger.log(id, \"No text in answer, returning text within tags:\", text);\n }\n\n textResponse = textResponse ? `${textResponse}\\n\\n${text}` : text;\n } else if (answer.type === \"tool_use\") {\n functionCalls.push({\n id: answer.id,\n name: answer.name,\n arguments: answer.input,\n });\n } else if (\n answer.type === \"thinking\" ||\n answer.type === \"redacted_thinking\"\n ) {\n reasoningBlocks.push(answer);\n }\n }\n\n if (!textResponse && !functionCalls.length) {\n logger.error(\n id,\n \"Missing text & functions in Anthropic API response:\",\n data,\n );\n throw new Error(\"Missing text & functions in Anthropic API response\");\n }\n\n // Anthropic's input_tokens EXCLUDES cache reads/writes; fold them back in\n // so prompt_tokens means \"all input tokens\" like OpenAI, where\n // cached_tokens is a subset of prompt_tokens.\n let usage: ParsedResponseMessage[\"usage\"] = null;\n if (data.usage) {\n const cacheRead = data.usage.cache_read_input_tokens ?? 0;\n const cacheWrite = data.usage.cache_creation_input_tokens ?? 0;\n const promptTokens = data.usage.input_tokens + cacheRead + cacheWrite;\n usage = {\n prompt_tokens: promptTokens,\n completion_tokens: data.usage.output_tokens,\n total_tokens: promptTokens + data.usage.output_tokens,\n cached_tokens: cacheRead,\n };\n }\n\n return {\n role: \"assistant\",\n content: textResponse,\n function_call: functionCalls[0] || null,\n function_calls: functionCalls,\n files: [],\n reasoningDetails: reasoningBlocks.length ? reasoningBlocks : undefined,\n usage,\n };\n}\n\nasync function callAnthropicWithRetries(\n id: Identifier,\n payload: AnthropicAIPayload,\n config?: AnthropicAIConfig,\n retries: number = 5,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n return withRetries(\n id,\n \"Anthropic\",\n () => callAnthropic(id, payload, config, requestTimeoutMs, signal),\n {\n retries,\n signal,\n },\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// GOOGLE AI\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction jigGoogleMessages(messages: GoogleAIMessage[]): GoogleAIMessage[] {\n const hasFunctionPart = (parts: GoogleAIPart[]) =>\n parts.some((p) => \"functionCall\" in p || \"functionResponse\" in p);\n\n let jiggedMessages = messages.slice();\n\n // Ensure first message is from user\n if (jiggedMessages[0]?.role === \"model\") {\n jiggedMessages = [\n { role: \"user\" as const, parts: [{ text: \"...\" }] },\n ...jiggedMessages,\n ];\n }\n\n // Group consecutive messages with the same role\n jiggedMessages = jiggedMessages.reduce((acc, message) => {\n if (acc.length === 0) return [message];\n\n const lastMessage = acc[acc.length - 1];\n if (lastMessage.role === message.role) {\n lastMessage.parts = [...lastMessage.parts, ...message.parts];\n return acc;\n }\n\n return [...acc, message];\n }, [] as GoogleAIMessage[]);\n\n // Ensure last message is from user — but don't append a placeholder after a\n // model turn that ends in a functionCall (it would orphan the call into\n // history and send \"...\" as the message).\n const last = jiggedMessages[jiggedMessages.length - 1];\n if (last?.role === \"model\" && !hasFunctionPart(last.parts)) {\n jiggedMessages.push({ role: \"user\", parts: [{ text: \"...\" }] });\n }\n\n return jiggedMessages;\n}\n\nasync function prepareGoogleAIPayload(\n _identifier: Identifier,\n payload: GenericPayload,\n): Promise<GoogleAIPayload> {\n const preparedPayload: GoogleAIPayload = {\n model: payload.model as GeminiModel,\n messages: [],\n tools: payload.functions\n ? {\n functionDeclarations: payload.functions.map((fn) => ({\n name: fn.name,\n parameters: {\n description: fn.description,\n ...fn.parameters,\n },\n })),\n }\n : undefined,\n // Map the generic function_call to Gemini's functionCallingConfig (\"none\"\n // → mode NONE forces a text-only turn). Only meaningful alongside tools.\n toolConfig:\n payload.functions && payload.function_call\n ? {\n functionCallingConfig: {\n mode:\n typeof payload.function_call === \"string\"\n ? payload.function_call === \"none\"\n ? \"NONE\"\n : \"AUTO\"\n : \"ANY\",\n },\n }\n : undefined,\n };\n\n // id -> tool name, to backfill functionResponse.name when a caller omits it.\n const toolNameById = new Map<string, string>();\n for (const m of payload.messages) {\n for (const fc of m.functionCalls || []) {\n if (fc.id) toolNameById.set(fc.id, fc.name);\n }\n }\n\n for (const message of payload.messages) {\n if (message.role === \"system\") {\n preparedPayload.systemInstruction = message.content;\n continue;\n }\n\n // role:\"tool\" → a user turn carrying functionResponse parts.\n if (message.role === \"tool\") {\n preparedPayload.messages.push({\n role: \"user\",\n parts: (message.toolResults || []).map((tr) => ({\n functionResponse: {\n id: tr.toolCallId,\n name: tr.name ?? toolNameById.get(tr.toolCallId) ?? \"\",\n response: { output: tr.content },\n },\n })),\n });\n continue;\n }\n\n const parts: GoogleAIPart[] = [];\n\n if (message.content) {\n parts.push({ text: message.content });\n }\n\n for (const file of message.files || []) {\n if (ALLOWED_IMAGE_MIME_TYPES.includes(file.mimeType)) {\n if (file.url) {\n parts.push({\n fileData: {\n mimeType: file.mimeType,\n fileUri: file.url,\n },\n });\n parts.push({ text: `Image (${file.url})` });\n } else if (file.data) {\n parts.push({\n inlineData: {\n mimeType: file.mimeType,\n data: file.data,\n },\n });\n }\n } else if (file.url) {\n // Non-image file with URL - add text reference\n parts.push({\n text: `File (${file.url})`,\n });\n }\n }\n\n for (const fc of message.functionCalls || []) {\n parts.push({\n functionCall: {\n id: fc.id,\n name: fc.name,\n args: fc.arguments,\n },\n // Gemini requires its thoughtSignature echoed back on the call part.\n ...(fc.thoughtSignature\n ? { thoughtSignature: fc.thoughtSignature }\n : {}),\n });\n }\n\n preparedPayload.messages.push({\n role: message.role === \"assistant\" ? \"model\" : message.role,\n parts,\n });\n }\n\n return preparedPayload;\n}\n\nasync function callGoogleAI(\n id: Identifier,\n payload: GoogleAIPayload,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const contents = jigGoogleMessages(payload.messages);\n\n // Call the REST generateContent endpoint directly rather than via @google/genai:\n // the pinned SDK (0.6.1) silently strips Gemini's per-call `thoughtSignature`,\n // which Gemini REQUIRES echoed back on multi-turn tool calls (a missing one\n // 400s the request). Going over the wire ourselves preserves it both ways.\n const requestBody: any = {\n contents,\n generationConfig: { responseModalities: [\"TEXT\"] },\n };\n if (payload.tools) requestBody.tools = [payload.tools];\n if (payload.tools && payload.toolConfig) {\n requestBody.toolConfig = payload.toolConfig;\n }\n if (payload.systemInstruction) {\n requestBody.systemInstruction = {\n parts: [{ text: payload.systemInstruction }],\n };\n }\n\n let response: any;\n try {\n const httpResponse = await withRequestDeadline(\n \"Google AI\",\n requestTimeoutMs,\n signal,\n (mergedSignal) =>\n axios.post(\n `https://generativelanguage.googleapis.com/v1beta/models/${payload.model}:generateContent`,\n requestBody,\n {\n headers: {\n \"content-type\": \"application/json\",\n \"x-goog-api-key\": process.env.GEMINI_API_KEY as string,\n },\n timeout: requestTimeoutMs,\n signal: mergedSignal,\n },\n ),\n );\n response = httpResponse.data;\n } catch (err: any) {\n // Re-shape the API error so callGoogleAIWithRetries' circuit breaker can read\n // message / status / promptFeedback off it.\n const apiError = err?.response?.data?.error;\n const wrapped = new Error(\n apiError?.message || err?.message || \"Google AI API request failed\",\n ) as any;\n wrapped.status = apiError?.status ?? err?.response?.status;\n wrapped.code = apiError?.code;\n wrapped.details = apiError?.details;\n wrapped.promptFeedback = err?.response?.data?.promptFeedback;\n throw wrapped;\n }\n\n let text = \"\";\n const files: File[] = [];\n const reasoningParts: any[] = [];\n // Built from content.parts (not response.functionCalls) so we can keep each\n // call's thoughtSignature, which the accessor drops. Gemini may omit ids —\n // synthesize positional ones so the caller can pair each with a\n // `ToolResult.toolCallId` next turn; the thoughtSignature MUST be echoed back\n // on round-trip (else Gemini 400s \"missing a thought_signature\").\n const functionCalls: FunctionCall[] = [];\n\n for (const part of response.candidates?.[0]?.content?.parts || []) {\n // Thinking parts (thought:true) carry chain-of-thought, not the answer.\n if ((part as any).thought) {\n reasoningParts.push(part);\n continue;\n }\n if (part.functionCall) {\n functionCalls.push({\n id: part.functionCall.id ?? `call_${functionCalls.length}`,\n name: part.functionCall.name ?? \"\",\n arguments: part.functionCall.args ?? {},\n thoughtSignature: (part as any).thoughtSignature,\n });\n continue;\n }\n if (part.text) text += part.text;\n if (part.inlineData?.data) {\n files.push({ mimeType: \"image/png\", data: part.inlineData.data });\n }\n }\n\n if (!text && !functionCalls.length && !files.length) {\n const candidate = response.candidates?.[0];\n const finishReason = candidate?.finishReason;\n\n logger.error(id, \"Missing text & functions in Google AI API response:\", {\n finishReason,\n safetyRatings: candidate?.safetyRatings,\n usageMetadata: response.usageMetadata,\n modelVersion: response.modelVersion,\n candidateContent: candidate?.content,\n promptFeedback: response.promptFeedback,\n });\n\n let errorMessage = \"Missing text & functions in Google AI API response\";\n if (finishReason) {\n const reasonDescriptions: Record<string, string> = {\n MALFORMED_FUNCTION_CALL:\n \"(Google could not generate valid function call arguments)\",\n SAFETY: \"(blocked by safety filters)\",\n RECITATION: \"(blocked due to recitation)\",\n MAX_TOKENS: \"(response truncated due to max tokens)\",\n };\n errorMessage += `: finishReason=${finishReason} ${reasonDescriptions[finishReason] || \"\"}`;\n }\n\n const error = new Error(errorMessage) as any;\n error.finishReason = finishReason;\n error.safetyRatings = candidate?.safetyRatings;\n error.usageMetadata = response.usageMetadata;\n error.promptFeedback = response.promptFeedback;\n throw error;\n }\n\n return {\n role: \"assistant\",\n content: text || null,\n files,\n function_call: functionCalls[0] || null,\n function_calls: functionCalls,\n reasoningDetails: reasoningParts.length ? reasoningParts : undefined,\n usage: response.usageMetadata\n ? {\n prompt_tokens: response.usageMetadata.promptTokenCount ?? 0,\n completion_tokens: response.usageMetadata.candidatesTokenCount ?? 0,\n total_tokens: response.usageMetadata.totalTokenCount ?? 0,\n cached_tokens: response.usageMetadata.cachedContentTokenCount ?? 0,\n }\n : null,\n };\n}\n\n/**\n * Content violation finish reasons that should trigger circuit breaker behavior.\n * These errors won't resolve with simple retries - the content itself is the problem.\n */\nconst CONTENT_VIOLATION_REASONS = new Set([\"PROHIBITED_CONTENT\", \"SAFETY\"]);\n\n/**\n * Removes inline image data from Google AI messages, preserving text content.\n * Used as a fallback when content violations are detected.\n */\nfunction removeImagesFromGooglePayload(payload: GoogleAIPayload): boolean {\n let removedImages = false;\n\n for (const message of payload.messages) {\n message.parts = message.parts.filter((part) => {\n if (\"inlineData\" in part || \"fileData\" in part) {\n removedImages = true;\n return false;\n }\n return true;\n });\n\n // Ensure message still has content after removing images\n if (message.parts.length === 0) {\n message.parts = [{ text: \"(image removed due to content policy)\" }];\n }\n }\n\n return removedImages;\n}\n\nasync function callGoogleAIWithRetries(\n id: Identifier,\n payload: GoogleAIPayload,\n retries: number = 5,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n let hasTriedWithoutImages = false;\n\n return withRetries(id, \"Google AI\", () => callGoogleAI(id, payload, requestTimeoutMs, signal), {\n retries,\n signal,\n onError: (error, attempt) => {\n const errorDetails: Record<string, any> = {\n message: error.message,\n finishReason: error.finishReason,\n modelVersion: error.modelVersion,\n };\n\n if (error.safetyRatings) errorDetails.safetyRatings = error.safetyRatings;\n if (error.usageMetadata) errorDetails.usageMetadata = error.usageMetadata;\n if (error.promptFeedback)\n errorDetails.promptFeedback = error.promptFeedback;\n if (error.status) errorDetails.httpStatus = error.status;\n if (error.code) errorDetails.errorCode = error.code;\n if (error.details) errorDetails.errorDetails = error.details;\n\n const fileUris = payload.messages\n .flatMap((m) => m.parts)\n .filter((p) => \"fileData\" in p)\n .map((p) => (p as any).fileData.fileUri);\n if (fileUris.length) errorDetails.fileUris = fileUris;\n\n logger.error(\n id,\n `Retry #${attempt} error: ${error.message}`,\n errorDetails,\n );\n\n // Circuit breaker: Google's fetcher couldn't pull our image URL(s). We pass\n // images as fileData.fileUri, but arbitrary (non-Files-API) URLs are only\n // best-effort for Gemini, so this 400 is episodic and retrying the same URL\n // almost never recovers within a request. Fail fast so the caller's\n // fallbackModel (whose adapter inlines the image bytes) takes over instead of\n // burning all retries first. Unlike the content-violation path we do NOT strip\n // images — the fallback model should still see them.\n if (\n typeof error?.message === \"string\" &&\n error.message.includes(\"Cannot fetch content from the provided URL\")\n ) {\n logger.error(\n id,\n \"Circuit breaker: Google could not fetch image URL(s); failing over (no more Google retries)\",\n );\n const fetchError = new Error(\n \"Google AI could not fetch the provided image URL(s).\",\n ) as any;\n fetchError.cause = error;\n fetchError.googleFetchFailure = true;\n throw fetchError;\n }\n\n // Circuit breaker: detect content violations and try removing images\n // Check both finishReason (candidate-level) and promptFeedback.blockReason (prompt-level)\n const violationReason =\n (CONTENT_VIOLATION_REASONS.has(error.finishReason) &&\n error.finishReason) ||\n (CONTENT_VIOLATION_REASONS.has(error.promptFeedback?.blockReason) &&\n error.promptFeedback?.blockReason);\n\n if (violationReason) {\n if (!hasTriedWithoutImages) {\n const removedImages = removeImagesFromGooglePayload(payload);\n if (removedImages) {\n logger.log(\n id,\n `Circuit breaker triggered: removing images due to ${violationReason}`,\n );\n hasTriedWithoutImages = true;\n return; // Continue to next retry with images removed\n }\n }\n\n // If we already tried without images or there were no images, fail fast\n logger.error(\n id,\n `Circuit breaker: failing fast due to ${violationReason} (no more fallbacks)`,\n );\n const circuitBreakerError = new Error(\n `Google AI content violation: ${violationReason}. Request cannot succeed with current content.`,\n ) as any;\n circuitBreakerError.finishReason = error.finishReason;\n circuitBreakerError.safetyRatings = error.safetyRatings;\n circuitBreakerError.usageMetadata = error.usageMetadata;\n circuitBreakerError.circuitBreaker = true;\n throw circuitBreakerError;\n }\n },\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// GROQ\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction normalizeMessageContent(\n content: AnthropicAIMessage[\"content\"],\n): string {\n return Array.isArray(content)\n ? content\n .map((c) => (c.type === \"text\" ? c.text : `[${c.type}]`))\n .join(\"\\n\")\n : content;\n}\n\n/**\n * Serialize generic messages for OpenAI-compatible chat APIs (Groq, OpenRouter).\n * Mirrors the OpenAI adapter but keeps content as a plain string. Tool calls\n * become assistant `tool_calls`, and a `role:\"tool\"` message expands to one\n * `{role:\"tool\", tool_call_id, content}` per result. Reasoning is passed\n * through only when the caller supplied it.\n */\nfunction prepareOpenAICompatMessages(\n messages: GenericMessage[],\n): OpenAIMessage[] {\n const out: OpenAIMessage[] = [];\n for (const message of messages) {\n if (message.role === \"tool\") {\n for (const tr of message.toolResults || []) {\n out.push({\n role: \"tool\",\n tool_call_id: tr.toolCallId,\n content: tr.content,\n });\n }\n continue;\n }\n\n const outMessage: OpenAIMessage = {\n role: message.role,\n content: normalizeMessageContent(message.content),\n };\n if (message.functionCalls?.length) {\n outMessage.tool_calls = message.functionCalls.map((fc, i) => ({\n id: fc.id ?? `call_${i}`,\n type: \"function\" as const,\n function: {\n name: fc.name,\n arguments: JSON.stringify(fc.arguments),\n },\n }));\n // OpenAI-compatible APIs want null content on a tool-call-only turn.\n if (!message.content) outMessage.content = null;\n }\n if (message.reasoning) outMessage.reasoning = message.reasoning;\n const reasoningDetails = filterOpenAICompatReasoningDetails(\n message.reasoningDetails,\n );\n if (reasoningDetails) outMessage.reasoning_details = reasoningDetails;\n out.push(outMessage);\n }\n return out;\n}\n\nfunction prepareGroqPayload(payload: GenericPayload): GroqPayload {\n return {\n model: payload.model as GroqModel,\n messages: prepareOpenAICompatMessages(payload.messages),\n tools: payload.functions?.map((fn) => ({\n type: \"function\",\n function: fn,\n })),\n tool_choice: payload.function_call\n ? typeof payload.function_call === \"string\"\n ? payload.function_call\n : { type: \"function\", function: payload.function_call }\n : undefined,\n temperature: payload.temperature,\n };\n}\n\nasync function callGroq(\n id: Identifier,\n payload: GroqPayload,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const response = await withRequestDeadline(\n \"Groq\",\n requestTimeoutMs,\n signal,\n (mergedSignal) =>\n axios.post(\n \"https://api.groq.com/openai/v1/chat/completions\",\n payload,\n {\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${process.env.GROQ_API_KEY}`,\n },\n timeout: requestTimeoutMs,\n signal: mergedSignal,\n },\n ),\n );\n\n // Like OpenRouter, Groq can return an error-shaped HTTP 200 with no `choices`\n // key; surface it instead of throwing a cryptic `choices[0]` TypeError.\n if (response.data.error) {\n logger.error(id, \"Groq error:\", response.data.error);\n throw new Error(`Groq error: ${response.data.error.message}`);\n }\n\n const answer = response.data.choices?.[0]?.message;\n if (!answer) {\n logger.error(id, \"Missing answer in Groq API response:\", response.data);\n throw new Error(\"Missing answer in Groq API\");\n }\n\n const functionCalls: FunctionCall[] = [];\n if (answer.tool_calls?.length) {\n for (let i = 0; i < answer.tool_calls.length; i++) {\n const tc = answer.tool_calls[i];\n functionCalls.push({\n id: tc.id ?? `call_${i}`,\n name: tc.function.name,\n arguments: JSON.parse(tc.function.arguments),\n });\n }\n }\n\n // An empty 200 (no content, no tool call) is not a usable answer — throw so\n // withRetries retries and callWithRetries can fall back. (Mirrors the\n // streaming path's guard in parseStreamedResponse.)\n if (!answer.content && !functionCalls.length) {\n logger.error(\n id,\n \"Groq: received message without content or function_call:\",\n JSON.stringify(response.data),\n );\n throw new Error(\n \"Groq: received message without content or function_call\",\n );\n }\n\n return {\n role: \"assistant\",\n content: answer.content || null,\n function_call: functionCalls[0] || null,\n function_calls: functionCalls,\n files: [],\n reasoning: answer.reasoning ?? undefined,\n usage: response.data.usage\n ? {\n prompt_tokens: response.data.usage.prompt_tokens,\n completion_tokens: response.data.usage.completion_tokens,\n total_tokens: response.data.usage.total_tokens,\n cached_tokens:\n response.data.usage.prompt_tokens_details?.cached_tokens ?? 0,\n }\n : null,\n };\n}\n\nasync function callGroqWithRetries(\n id: Identifier,\n payload: GroqPayload,\n retries: number = 5,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n return withRetries(id, \"Groq\", () => callGroq(id, payload, requestTimeoutMs, signal), {\n retries,\n signal,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// OPENROUTER\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction prepareOpenRouterPayload(payload: GenericPayload): OpenRouterPayload {\n return {\n model: payload.model as OpenRouterModel,\n messages: prepareOpenAICompatMessages(payload.messages),\n tools: payload.functions?.map((fn) => ({\n type: \"function\",\n function: fn,\n })),\n tool_choice: payload.function_call\n ? typeof payload.function_call === \"string\"\n ? payload.function_call\n : { type: \"function\", function: payload.function_call }\n : undefined,\n temperature: payload.temperature,\n provider: payload.provider,\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// DeepSeek \"DSML\" tool-call recovery\n// ─────────────────────────────────────────────────────────────────────────────\n// DeepSeek models (e.g. deepseek-v4-flash) on OpenRouter intermittently emit\n// their native tool-call markup as plain assistant *content* instead of\n// populating the response's `tool_calls`. The markup (\"DSML\") looks like:\n//\n// <|DSML|tool_calls>\n// <|DSML|invoke name=\"use_skills\">\n// <|DSML|parameter name=\"skills\" string=\"false\">[\"search\"]</|DSML|parameter>\n// </|DSML|invoke>\n// </|DSML|tool_calls>\n//\n// with either one or two fullwidth vertical bars (| = U+FF5C) around DSML. The\n// `string` attribute says whether the value is a literal string (\"true\") or a\n// JSON value to parse (\"false\"). We recover these into structured FunctionCalls\n// so the turn executes normally instead of leaking raw markup to the caller.\n//\n// Regex tags use `|+` (one-or-more fullwidth vertical bars) so the single-\n// and double-bar variants both match.\nconst DSML_ENVELOPE_RE = /<|+DSML|+tool_calls>/;\nconst DSML_DELIMITER_RE = /<\\/?|+DSML|+/;\nconst DSML_INVOKE_RE =\n /<|+DSML|+invoke\\s+name=\"([^\"]+)\"\\s*>([\\s\\S]*?)<\\/|+DSML|+invoke>/g;\nconst DSML_PARAM_RE =\n /<|+DSML|+parameter\\s+name=\"([^\"]+)\"(?:\\s+string=\"(true|false)\")?\\s*>([\\s\\S]*?)<\\/|+DSML|+parameter>/g;\n// Any DSML tag (open or close), used to excise the whole markup span from\n// surrounding prose once the calls have been extracted.\nconst DSML_ANY_TAG_RE = /<\\/?|+DSML|+[^>]*>/g;\n\nfunction parseDsmlToolCalls(content: string): {\n calls: FunctionCall[];\n remainingContent: string | null;\n} {\n const calls: FunctionCall[] = [];\n\n DSML_INVOKE_RE.lastIndex = 0;\n let invokeMatch: RegExpExecArray | null;\n while ((invokeMatch = DSML_INVOKE_RE.exec(content)) !== null) {\n const name = invokeMatch[1];\n const inner = invokeMatch[2];\n const args: Record<string, any> = {};\n let ok = true;\n\n DSML_PARAM_RE.lastIndex = 0;\n let paramMatch: RegExpExecArray | null;\n while ((paramMatch = DSML_PARAM_RE.exec(inner)) !== null) {\n const [, paramName, stringAttr, rawValue] = paramMatch;\n if (stringAttr === \"false\") {\n // value is a JSON literal (array / number / object / bool / quoted string)\n try {\n args[paramName] = JSON.parse(rawValue);\n } catch {\n ok = false; // malformed typed arg → don't emit a wrong-typed call\n break;\n }\n } else {\n // string=\"true\" (or attribute absent) → literal string value\n args[paramName] = rawValue;\n }\n }\n\n if (ok && name) {\n calls.push({ id: `call_${calls.length}`, name, arguments: args });\n }\n }\n\n if (!calls.length) {\n return { calls, remainingContent: content };\n }\n\n // Excise the whole DSML span (first tag through last tag, including the\n // already-captured parameter values between them) so any surrounding prose\n // survives but the raw markup never reaches the caller.\n DSML_ANY_TAG_RE.lastIndex = 0;\n let first = -1;\n let last = -1;\n let tag: RegExpExecArray | null;\n while ((tag = DSML_ANY_TAG_RE.exec(content)) !== null) {\n if (first === -1) first = tag.index;\n last = tag.index + tag[0].length;\n }\n const remaining =\n first === -1\n ? content\n : (content.slice(0, first) + content.slice(last)).trim();\n return { calls, remainingContent: remaining.length ? remaining : null };\n}\n\n// Independent timeout budgets for the two OpenRouter transports. Streaming is\n// bounded by elapsed total + a per-useful-chunk stall timeout, so it can afford\n// a generous total: a healthy long generation keeps producing useful chunks,\n// while a hung one dies within one stall window. Non-streaming has no\n// progress signal at all, so its total must stay tight.\nexport const OPENROUTER_STREAM_TIMEOUT_MS = 600_000;\nexport const OPENROUTER_NONSTREAM_TIMEOUT_MS = 180_000;\n\nfunction openRouterEndpoint(): string {\n // Override point for tests (deadline/stream behavior needs a local server).\n return `${process.env.OPENROUTER_BASE_URL || \"https://openrouter.ai\"}/api/v1/chat/completions`;\n}\n\n/**\n * Shared tail of both OpenRouter transports: assemble the ParsedResponseMessage\n * from the raw pieces, recover DSML tool calls, and reject unusable (empty /\n * truncated-markup) completions so withRetries retries and callWithRetries can\n * fall back.\n */\nfunction finalizeOpenRouterMessage(\n id: Identifier,\n raw: {\n content: string | null;\n toolCalls: { id?: string; name: string; argumentsJson: string }[];\n reasoning?: string;\n reasoningDetails?: any;\n provider?: string;\n usage?: {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n prompt_tokens_details?: { cached_tokens?: number };\n } | null;\n /** Whole response (or a summary of the stream) for the failure log. */\n forLog: () => string;\n },\n): ParsedResponseMessage {\n const functionCalls: FunctionCall[] = [];\n for (let i = 0; i < raw.toolCalls.length; i++) {\n const tc = raw.toolCalls[i];\n if (!tc.name) continue;\n functionCalls.push({\n id: tc.id ?? `call_${i}`,\n name: tc.name,\n // Streamed no-arg calls can close with an empty fragment; treat as {}.\n arguments: tc.argumentsJson.trim() ? JSON.parse(tc.argumentsJson) : {},\n });\n }\n\n // DeepSeek sometimes emits its native \"DSML\" tool-call markup as plain content\n // instead of populating tool_calls. Recover it into structured calls so the\n // turn executes normally instead of leaking raw markup to the caller.\n let content = raw.content;\n if (!functionCalls.length && content && DSML_ENVELOPE_RE.test(content)) {\n const { calls, remainingContent } = parseDsmlToolCalls(content);\n if (calls.length) {\n functionCalls.push(...calls);\n content = remainingContent;\n }\n }\n\n // Not a usable answer — an empty completion (reasoning models e.g. deepseek\n // can route all output to the discarded `reasoning` channel), OR a DSML\n // envelope we couldn't parse into a call (truncated/malformed). Throw so\n // withRetries retries this model and, on exhaustion, callWithRetries falls\n // back to fallbackModel.\n const hasUnparsedDsml = !!content && DSML_DELIMITER_RE.test(content);\n if (!functionCalls.length && (!content || hasUnparsedDsml)) {\n logger.error(id, \"OpenRouter: empty or unparseable completion:\", raw.forLog());\n throw new Error(\n \"OpenRouter: received message without usable content or function_call\",\n );\n }\n\n return {\n role: \"assistant\",\n content: content || null,\n function_call: functionCalls[0] || null,\n function_calls: functionCalls,\n files: [],\n reasoning: raw.reasoning || undefined,\n reasoningDetails: raw.reasoningDetails ?? undefined,\n // The upstream provider OpenRouter routed to (e.g. \"Baidu\") — finer-grained\n // than the \"openrouter\" stamp callWithRetries would apply.\n provider: raw.provider ?? undefined,\n usage: raw.usage\n ? {\n prompt_tokens: raw.usage.prompt_tokens,\n completion_tokens: raw.usage.completion_tokens,\n total_tokens: raw.usage.total_tokens,\n cached_tokens: raw.usage.prompt_tokens_details?.cached_tokens ?? 0,\n }\n : null,\n };\n}\n\n/**\n * Streaming transport (the default). Two timers, both required:\n *\n * - `streamTimeoutMs` bounds the whole attempt (connect + generation). It is\n * deliberately independent of the non-streaming `requestTimeoutMs`: with a\n * progress signal available, a long healthy generation shouldn't be killed\n * by a deadline sized for opaque requests (2026-07-27: 9–12k-token deepseek\n * completions at healthy tps were being executed at the 120s hard deadline\n * just before finishing, then retried from scratch).\n * - `chunkTimeoutMs` is a stall detector: it resets ONLY on a \"useful\" chunk —\n * one advancing content, reasoning, reasoning_details, tool-call fragments,\n * finish_reason, or usage. SSE comments (OpenRouter dribbles\n * \": OPENROUTER PROCESSING\" as keep-alive), role-only deltas, and other\n * heartbeat noise do NOT reset it, so a provider that keeps the socket warm\n * while generating nothing dies within one window instead of holding the\n * turn to the total deadline. The window also covers connect + time to first\n * token.\n */\nasync function callOpenRouterStream(\n id: Identifier,\n payload: OpenRouterPayload,\n streamTimeoutMs: number = OPENROUTER_STREAM_TIMEOUT_MS,\n chunkTimeoutMs: number = 15_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const controller = new AbortController();\n // Why the reason is tracked out-of-band: fetch/reader surface any abort as a\n // bare AbortError, so without this the retry log would say \"This operation\n // was aborted\" no matter which timer fired.\n let abortReason: string | null = null;\n const abortWith = (reason: string) => {\n abortReason = reason;\n controller.abort();\n };\n\n const unref = (t: ReturnType<typeof setTimeout>) => {\n if (typeof t === \"object\" && \"unref\" in t) t.unref();\n return t;\n };\n const totalTimer = unref(\n setTimeout(\n () =>\n abortWith(\n `OpenRouter stream exceeded total deadline of ${streamTimeoutMs}ms`,\n ),\n streamTimeoutMs,\n ),\n );\n let stallTimer: ReturnType<typeof setTimeout> | undefined;\n const armStallTimer = () => {\n clearTimeout(stallTimer);\n stallTimer = unref(\n setTimeout(\n () =>\n abortWith(\n `OpenRouter stream stalled: no useful chunk for ${chunkTimeoutMs}ms`,\n ),\n chunkTimeoutMs,\n ),\n );\n };\n\n let paragraph = \"\";\n let reasoning = \"\";\n const reasoningDetails: any[] = [];\n const toolCalls: { id?: string; name: string; argumentsJson: string }[] = [];\n let provider: string | undefined;\n let usage: any = null;\n let finishReason: string | null = null;\n let sawDone = false;\n let dataChunks = 0;\n\n try {\n armStallTimer(); // covers connect + time to first token\n const response = await fetch(openRouterEndpoint(), {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,\n },\n body: JSON.stringify({ ...payload, stream: true, usage: { include: true } }),\n signal: signal ? anySignal([controller.signal, signal]) : controller.signal,\n });\n\n if (!response.ok) {\n let data: any;\n try {\n data = await response.json();\n } catch {\n data = undefined;\n }\n logger.error(id, `OpenRouter stream HTTP ${response.status}:`, data);\n const error = new Error(\n `OpenRouter error: ${data?.error?.message || `HTTP ${response.status}`}`,\n ) as any;\n error.response = { status: response.status, data };\n throw error;\n }\n // Some responses to a streamed request arrive as a plain JSON body anyway\n // (error-in-200 payloads, proxies/providers that ignore `stream`). Parse\n // those as a non-streaming body instead of scanning them for SSE lines.\n if (response.headers.get(\"content-type\")?.includes(\"application/json\")) {\n return parseOpenRouterBody(id, await response.json());\n }\n if (!response.body) {\n throw new Error(\"OpenRouter stream error: no response body\");\n }\n\n const reader = response.body.getReader();\n // One decoder in stream mode for the whole body: multi-byte UTF-8\n // sequences (CJK output!) split across TCP chunks must not be decoded\n // per-chunk or they turn into replacement characters.\n const decoder = new TextDecoder();\n let lineBuffer = \"\";\n\n outer: while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n lineBuffer += decoder.decode(value, { stream: true });\n\n let newlineIdx: number;\n while ((newlineIdx = lineBuffer.indexOf(\"\\n\")) !== -1) {\n let line = lineBuffer.slice(0, newlineIdx);\n lineBuffer = lineBuffer.slice(newlineIdx + 1);\n if (line.endsWith(\"\\r\")) line = line.slice(0, -1);\n if (!line) continue; // SSE event separator\n if (line.startsWith(\":\")) continue; // SSE comment — keep-alive, NOT useful\n if (!line.startsWith(\"data:\")) continue; // ignore event:/id:/retry: fields\n const dataStr = line.slice(5).trimStart();\n if (dataStr === \"[DONE]\") {\n sawDone = true;\n break outer;\n }\n\n let json: any;\n try {\n json = JSON.parse(dataStr);\n } catch {\n // SSE frames one complete JSON object per data line and the line\n // buffer already reassembles split TCP chunks, so this is a\n // malformed event, not a partial one — skip it rather than corrupt\n // the accumulation.\n logger.error(\n id,\n \"OpenRouter stream: unparseable data line:\",\n dataStr.slice(0, 200),\n );\n continue;\n }\n dataChunks++;\n\n // Same error-in-200 wrapping as the non-streaming body, delivered as\n // an SSE event (rate limits, moderation, provider failures).\n if (json.error) {\n logger.error(id, \"OpenRouter stream error event:\", json.error);\n const error = new Error(\n `OpenRouter error: ${json.error.message}`,\n ) as any;\n error.data = json.error;\n throw error;\n }\n\n if (json.provider) provider = json.provider;\n let useful = false;\n if (json.usage) {\n usage = json.usage;\n useful = true;\n }\n const choice = json.choices?.[0];\n if (choice) {\n const delta = choice.delta ?? {};\n if (delta.content) {\n paragraph += delta.content;\n useful = true;\n }\n if (delta.reasoning) {\n reasoning += delta.reasoning;\n useful = true;\n }\n if (Array.isArray(delta.reasoning_details) && delta.reasoning_details.length) {\n reasoningDetails.push(...delta.reasoning_details);\n useful = true;\n }\n if (Array.isArray(delta.tool_calls)) {\n for (const toolCall of delta.tool_calls) {\n const idx = toolCall.index ?? 0;\n while (toolCalls.length <= idx) {\n toolCalls.push({ name: \"\", argumentsJson: \"\" });\n }\n if (toolCall.id) toolCalls[idx].id = toolCall.id;\n if (toolCall.function?.name)\n toolCalls[idx].name += toolCall.function.name;\n if (toolCall.function?.arguments)\n toolCalls[idx].argumentsJson += toolCall.function.arguments;\n useful = true;\n }\n }\n if (choice.finish_reason) {\n finishReason = choice.finish_reason;\n useful = true;\n }\n }\n if (useful) armStallTimer();\n }\n }\n\n // After [DONE] the server should close, but don't rely on it — release the\n // socket instead of holding it until GC.\n if (sawDone) reader.cancel().catch(() => {});\n\n // A clean close without [DONE] is acceptable only when the provider said\n // it finished; otherwise the connection died mid-generation and returning\n // the partial accumulation would present a truncated answer as complete.\n if (!sawDone && !finishReason) {\n logger.error(\n id,\n `OpenRouter stream ended prematurely after ${dataChunks} data chunks`,\n );\n throw new Error(\"OpenRouter stream error: ended prematurely\");\n }\n\n return finalizeOpenRouterMessage(id, {\n content: paragraph || null,\n toolCalls,\n reasoning,\n reasoningDetails: reasoningDetails.length ? reasoningDetails : undefined,\n provider,\n usage,\n forLog: () =>\n JSON.stringify({\n finishReason,\n provider,\n usage,\n paragraph: paragraph.slice(0, 500),\n reasoningChars: reasoning.length,\n toolCalls,\n }),\n });\n } catch (error: any) {\n // Restore the real reason: fetch/reader surface our timer aborts as bare\n // AbortErrors. Caller-signal aborts pass through untouched so\n // withRetries/callWithRetries see signal.aborted and bail.\n if (abortReason && !signal?.aborted) {\n logger.error(id, abortReason);\n throw new Error(abortReason);\n }\n throw error;\n } finally {\n clearTimeout(totalTimer);\n clearTimeout(stallTimer);\n }\n}\n\n/** Parse a complete (non-streamed) OpenRouter response body. */\nfunction parseOpenRouterBody(id: Identifier, data: any): ParsedResponseMessage {\n // OpenRouter wraps upstream provider failures (rate limits, moderation,\n // model-unavailable) in an HTTP 200 whose body is `{ error: {...} }` with no\n // `choices` key. Surface that error instead of letting `choices[0]` throw a\n // cryptic \"Cannot read properties of undefined (reading '0')\" TypeError that\n // hides the real reason. (Mirrors the OpenAI non-streaming guard above.)\n if (data.error) {\n logger.error(id, \"OpenRouter error:\", data.error);\n const error = new Error(`OpenRouter error: ${data.error.message}`) as any;\n // Carry the raw error body (as the stream path does) so the retry loop can\n // classify it — moderation eviction needs code/metadata, not just message.\n error.data = data.error;\n throw error;\n }\n\n const answer = data.choices?.[0]?.message;\n if (!answer) {\n logger.error(id, \"Missing answer in OpenRouter API response:\", data);\n throw new Error(\"Missing answer in OpenRouter API\");\n }\n\n return finalizeOpenRouterMessage(id, {\n content: answer.content ?? null,\n toolCalls: (answer.tool_calls ?? []).map((tc: any) => ({\n id: tc.id,\n name: tc.function.name,\n argumentsJson: tc.function.arguments,\n })),\n reasoning: answer.reasoning ?? undefined,\n reasoningDetails: answer.reasoning_details ?? undefined,\n provider: data.provider ?? undefined,\n usage: data.usage ?? null,\n forLog: () => JSON.stringify(data),\n });\n}\n\n/** Non-streaming transport — kept for callers that set `streaming: false`. */\nasync function callOpenRouterNonStreaming(\n id: Identifier,\n payload: OpenRouterPayload,\n requestTimeoutMs: number = OPENROUTER_NONSTREAM_TIMEOUT_MS,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const response = await withRequestDeadline(\n \"OpenRouter\",\n requestTimeoutMs,\n signal,\n (mergedSignal) =>\n axios.post(openRouterEndpoint(), payload, {\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,\n },\n timeout: requestTimeoutMs,\n signal: mergedSignal,\n }),\n );\n\n return parseOpenRouterBody(id, response.data);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Moderation eviction\n// ─────────────────────────────────────────────────────────────────────────────\n// A provider's content-moderation rejection (\"Upstream error from Alibaba:\n// Output data may contain inappropriate content.\") is deterministic for a\n// given payload — re-rolling the same provider burns the whole retry budget\n// for nothing (observed 2026-07-27: 5 identical rejections per turn, ~20-25s\n// of user-visible stall, before fallbackModel saved the turn). On the FIRST\n// moderation-classified error, evict the refusing provider from the request's\n// provider preferences (ignore += provider, order -= provider) so every\n// remaining attempt reroutes; OpenRouter's next-ranked provider answers\n// instead. Non-moderation errors keep plain retry semantics.\n\n/** \"AtlasCloud\" / \"atlas-cloud/fp4\" / \"Atlas Cloud\" → \"atlascloud\" */\nconst normalizeProviderKey = (name: string) =>\n name.split(\"/\")[0].toLowerCase().replace(/[^a-z0-9]/g, \"\");\n\nconst MODERATION_RE =\n /moderat|inappropriate content|content polic|content management|flagged/i;\n\n/**\n * If `error` is a provider content-moderation rejection, return the refusing\n * provider's slug (in the payload's own `order` spelling when possible, since\n * OpenRouter's `ignore` wants slugs, not the display name error metadata\n * carries). Null for everything else.\n */\nfunction moderationEvictionSlug(\n error: any,\n payload: OpenRouterPayload,\n): string | null {\n const body = error?.data ?? error?.response?.data?.error;\n if (!body) return null;\n const message = String(body.message ?? \"\");\n const isModeration =\n body.code === 403 ||\n Array.isArray(body.metadata?.reasons) ||\n MODERATION_RE.test(message);\n if (!isModeration) return null;\n\n const display: string | undefined =\n body.metadata?.provider_name ??\n /Upstream error from ([^:]+):/.exec(message)?.[1];\n if (!display) return null;\n\n const key = normalizeProviderKey(display);\n const fromOrder = payload.provider?.order?.find(\n (entry) => normalizeProviderKey(entry) === key,\n );\n // Best effort when the provider wasn't in our order (OpenRouter default\n // routing): lowercased display name matches the slug for single-word\n // providers (alibaba, novita, baidu), which covers the observed cases.\n return fromOrder ? fromOrder.split(\"/\")[0] : display.toLowerCase();\n}\n\n/**\n * Least time a streaming attempt is worth starting with. Below this the\n * generation cannot plausibly finish before the caller's deadline, so burning\n * a provider call (and paying for tokens that get discarded) is pure waste.\n */\nexport const MIN_STREAM_ATTEMPT_MS = 10_000;\n\ninterface OpenRouterCallOptions {\n streaming: boolean;\n streamTimeoutMs: number;\n streamDeadlineAt?: number;\n requestTimeoutMs: number;\n chunkTimeoutMs: number;\n}\n\n/**\n * Per-attempt streaming budget: the smaller of the per-attempt cap and the\n * time left until the caller's absolute deadline. Returns null when too little\n * remains to be worth an attempt.\n */\nfunction streamAttemptBudgetMs(options: OpenRouterCallOptions): number | null {\n if (options.streamDeadlineAt === undefined) return options.streamTimeoutMs;\n const remaining = options.streamDeadlineAt - Date.now();\n if (remaining < MIN_STREAM_ATTEMPT_MS) return null;\n return Math.min(options.streamTimeoutMs, remaining);\n}\n\nasync function callOpenRouterWithRetries(\n id: Identifier,\n payload: OpenRouterPayload,\n retries: number = 5,\n options: OpenRouterCallOptions,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const evicted: string[] = [];\n return withRetries(\n id,\n \"OpenRouter\",\n () =>\n (options.streaming\n ? (() => {\n const budget = streamAttemptBudgetMs(options);\n if (budget === null) {\n // Fail fast rather than start a doomed generation. Thrown (not\n // returned) so fallbackModel still gets its chance — a cheaper\n // model may answer in the time that's left.\n const error = new Error(\n \"OpenRouter stream skipped: caller deadline leaves too little time for another attempt\",\n ) as any;\n error.deadlineExceeded = true;\n logger.error(id, error.message);\n throw error;\n }\n return callOpenRouterStream(\n id,\n payload,\n budget,\n options.chunkTimeoutMs,\n signal,\n );\n })()\n : callOpenRouterNonStreaming(\n id,\n payload,\n options.requestTimeoutMs,\n signal,\n )\n ).catch((error) => {\n const slug = moderationEvictionSlug(error, payload);\n if (slug && !evicted.includes(slug)) {\n evicted.push(slug);\n // Mutating this attempt-scoped payload is safe: it's built fresh per\n // callWithRetries invocation and a fallbackModel run rebuilds it.\n payload.provider = {\n ...payload.provider,\n ignore: [...(payload.provider?.ignore ?? []), slug],\n order: payload.provider?.order?.filter(\n (entry) => normalizeProviderKey(entry) !== normalizeProviderKey(slug),\n ),\n };\n logger.log(\n id,\n `OpenRouter moderation eviction: ignoring provider \"${slug}\" for remaining attempts`,\n );\n }\n throw error;\n }),\n { retries, signal },\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// MAIN ENTRY POINT\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst VALID_PROVIDERS: Provider[] = [\"openai\", \"anthropic\", \"google\", \"groq\", \"openrouter\"];\n\nconst ENUM_PROVIDER_MAP: { values: Set<string>; provider: Provider }[] = [\n { values: new Set(Object.values(GPTModel)), provider: \"openai\" },\n { values: new Set(Object.values(ClaudeModel)), provider: \"anthropic\" },\n { values: new Set(Object.values(GeminiModel)), provider: \"google\" },\n { values: new Set(Object.values(GroqModel)), provider: \"groq\" },\n { values: new Set(Object.values(OpenRouterModel)), provider: \"openrouter\" },\n];\n\nexport function parseModelString(model: string): { provider: Provider; modelId: string } {\n const colonIndex = model.indexOf(\":\");\n\n if (colonIndex !== -1) {\n const prefix = model.substring(0, colonIndex);\n\n if (VALID_PROVIDERS.includes(prefix as Provider)) {\n const modelId = model.substring(colonIndex + 1);\n\n if (!modelId) {\n throw new Error(\n `Empty model ID in model string '${model}'. Expected format: 'provider:model-id'`,\n );\n }\n\n return { provider: prefix as Provider, modelId };\n }\n\n // Prefix isn't a known provider — fall through to enum lookup\n // (handles model values that contain colons, e.g. OpenRouter \"google/gemma-4-31b-it:free\")\n }\n\n // Fallback: check enum values\n for (const { values, provider } of ENUM_PROVIDER_MAP) {\n if (values.has(model)) {\n return { provider, modelId: model };\n }\n }\n\n // If string had a colon but wasn't a known provider, give a specific error\n if (colonIndex !== -1) {\n const prefix = model.substring(0, colonIndex);\n throw new Error(\n `Unknown provider '${prefix}' in model string '${model}'. Valid providers: ${VALID_PROVIDERS.join(\", \")}`,\n );\n }\n\n throw new Error(\n `Unable to determine provider for model '${model}'. Use a provider prefix (e.g. 'openai:${model}') or a known model enum value. Valid providers: ${VALID_PROVIDERS.join(\", \")}`,\n );\n}\n\nexport async function callWithRetries(\n id: string | string[],\n aiPayload: GenericPayload,\n aiConfig?: OpenAIConfig | AnthropicAIConfig,\n retries: number = 5,\n chunkTimeoutMs: number = 15_000,\n): Promise<ParsedResponseMessage> {\n try {\n const { provider, modelId } = parseModelString(aiPayload.model);\n const routingPayload = { ...aiPayload, model: modelId as AnyModel };\n // Per-attempt HTTP timeout, honored by every adapter. Default applied once\n // here so all providers share it; callers override via payload.requestTimeoutMs.\n const requestTimeoutMs = aiPayload.requestTimeoutMs ?? 120_000;\n const signal = aiPayload.signal;\n\n let result: ParsedResponseMessage;\n switch (provider) {\n case \"anthropic\":\n result = await callAnthropicWithRetries(\n id,\n await prepareAnthropicPayload(id, routingPayload),\n aiConfig as AnthropicAIConfig,\n retries,\n requestTimeoutMs,\n signal,\n );\n break;\n\n case \"openai\":\n result = await callOpenAiWithRetries(\n id,\n await prepareOpenAIPayload(id, routingPayload),\n aiConfig as OpenAIConfig,\n retries,\n chunkTimeoutMs,\n requestTimeoutMs,\n signal,\n );\n break;\n\n case \"groq\":\n result = await callGroqWithRetries(\n id,\n prepareGroqPayload(routingPayload),\n retries,\n requestTimeoutMs,\n signal,\n );\n break;\n\n case \"google\":\n result = await callGoogleAIWithRetries(\n id,\n await prepareGoogleAIPayload(id, routingPayload),\n retries,\n requestTimeoutMs,\n signal,\n );\n break;\n\n case \"openrouter\":\n // OpenRouter streams by default. The two transports have independent\n // budgets on purpose: `requestTimeoutMs` only bounds non-streaming\n // attempts (OpenRouter default 180s, tighter 120s global default kept\n // for other providers), while streaming gets `streamTimeoutMs`\n // (default 600s) total + the per-useful-chunk stall timeout, further\n // bounded by `streamDeadlineAt` when the caller has a turn budget.\n result = await callOpenRouterWithRetries(\n id,\n prepareOpenRouterPayload(routingPayload),\n retries,\n {\n streaming: aiPayload.streaming ?? true,\n streamTimeoutMs:\n aiPayload.streamTimeoutMs ?? OPENROUTER_STREAM_TIMEOUT_MS,\n streamDeadlineAt: aiPayload.streamDeadlineAt,\n requestTimeoutMs:\n aiPayload.requestTimeoutMs ?? OPENROUTER_NONSTREAM_TIMEOUT_MS,\n chunkTimeoutMs,\n },\n signal,\n );\n break;\n }\n\n // Attribution stamp: adapters that know the actual serving provider set it\n // themselves (OpenRouter returns the upstream provider it routed to); for\n // the rest, the SDK provider name is the answer. Because fallback recurses\n // through callWithRetries, the stamp always comes from the invocation whose\n // model actually answered.\n result.provider ??= provider;\n return result;\n } catch (error) {\n // Caller cancelled — reject immediately, never fall back to another model.\n if (aiPayload.signal?.aborted) throw error;\n if (aiPayload.fallbackModel) {\n logger.error(\n id,\n `Primary model ${aiPayload.model} failed, falling back to ${aiPayload.fallbackModel}`,\n {\n error: error instanceof Error ? error.message : error,\n cause:\n error instanceof Error && (error as any).cause instanceof Error\n ? (error as any).cause.message\n : undefined,\n },\n );\n return callWithRetries(\n id,\n {\n ...aiPayload,\n model: aiPayload.fallbackModel,\n fallbackModel: undefined,\n },\n aiConfig,\n retries,\n chunkTimeoutMs,\n );\n }\n throw error;\n }\n}\n","/** @deprecated Use provider prefix strings instead, e.g. `\"anthropic:claude-sonnet-4-5\"` */\nexport enum ClaudeModel {\n HAIKU_3 = \"claude-3-haiku-20240307\",\n SONNET_3 = \"claude-3-sonnet-20240229\",\n OPUS_3 = \"claude-3-opus-20240229\",\n HAIKU_3_5 = \"claude-3-5-haiku-20241022\",\n SONNET_3_5 = \"claude-3-5-sonnet-20241022\",\n SONNET_4 = \"claude-sonnet-4-20250514\",\n OPUS_4 = \"claude-opus-4-20250514\",\n OPUS_4_1 = \"claude-opus-4-1\",\n HAIKU_4_5 = \"claude-haiku-4-5\",\n SONNET_4_5 = \"claude-sonnet-4-5\",\n OPUS_4_5 = \"claude-opus-4-5\",\n}\n\n/** @deprecated Use provider prefix strings instead, e.g. `\"openai:gpt-4o\"` */\nexport enum GPTModel {\n GPT35_0613 = \"gpt-3.5-turbo-0613\",\n GPT35_0613_16K = \"gpt-3.5-turbo-16k-0613\",\n GPT35_0125 = \"gpt-3.5-turbo-0125\",\n GPT4_1106_PREVIEW = \"gpt-4-1106-preview\",\n GPT4_0125_PREVIEW = \"gpt-4-0125-preview\",\n GPT4_0409 = \"gpt-4-turbo-2024-04-09\",\n GPT4O = \"gpt-4o\",\n GPT4O_MINI = \"gpt-4o-mini\",\n O1_PREVIEW = \"o1-preview\",\n O1_MINI = \"o1-mini\",\n O3_MINI = \"o3-mini\",\n GPT4_1 = \"gpt-4.1\",\n GPT4_1_MINI = \"gpt-4.1-mini\",\n GPT4_1_NANO = \"gpt-4.1-nano\",\n GPT5 = \"gpt-5\",\n GPT5_MINI = \"gpt-5-mini\",\n}\n\n/** @deprecated Use provider prefix strings instead, e.g. `\"groq:llama-3.3-70b-versatile\"` */\nexport enum GroqModel {\n LLAMA_3_70B_8192 = \"llama3-70b-8192\",\n LLAMA_3_3_70B_VERSATILE = \"llama-3.3-70b-versatile\",\n QWEN3_32B = \"qwen/qwen3-32b\",\n DEEPSEEK_R1_DISTILL_LLAMA_70B = \"deepseek-r1-distill-llama-70b\",\n}\n\n/** @deprecated Use provider prefix strings instead, e.g. `\"openrouter:qwen/qwen3.6-plus:free\"` */\nexport enum OpenRouterModel {\n GEMMA_4_31B_IT_FREE = \"google/gemma-4-31b-it:free\",\n GEMMA_4_31B_IT = \"google/gemma-4-31b-it\",\n}\n\n/** @deprecated Use provider prefix strings instead, e.g. `\"google:gemini-2.0-flash\"` */\nexport enum GeminiModel {\n GEMINI_1_5_PRO = \"gemini-1.5-pro-latest\",\n GEMINI_EXP_1206 = \"gemini-exp-1206\",\n GEMINI_2_0_FLASH = \"gemini-2.0-flash\",\n GEMINI_2_0_FLASH_EXP_IMAGE_GENERATION = \"gemini-2.0-flash-exp-image-generation\",\n GEMINI_2_0_FLASH_THINKING_EXP = \"gemini-2.0-flash-thinking-exp\",\n GEMINI_2_0_FLASH_THINKING_EXP_01_21 = \"gemini-2.0-flash-thinking-exp-01-21\",\n GEMINI_2_5_FLASH_PREVIEW_04_17 = \"gemini-2.5-flash-preview-04-17\",\n GEMINI_3_FLASH_PREVIEW = \"gemini-3-flash-preview\",\n GEMINI_3_1_FLASH_LITE_PREVIEW = \"gemini-3.1-flash-lite-preview\",\n}\n\nexport interface GenericError {\n message: string;\n}\n\nexport enum ContentType {\n TEXT = \"text\",\n ATTACHMENT = \"attachment\",\n}\n\nexport type AIChainResponse = {\n content: string | null;\n contentType?: ContentType;\n functionCalls: FunctionCall[];\n};\n\n/**\n * A single conversation turn passed to `callWithRetries`. The SDK serializes\n * these into each provider's native message format.\n *\n * ## Multi-turn tool calls\n * To continue after the model calls a tool, append the model's own assistant\n * turn and then the tool result, then call again:\n *\n * 1. Read the assistant turn off the response: `function_calls` (each with an\n * `id`) and — for reasoning models — `reasoning` / `reasoningDetails`.\n * 2. Push back an `assistant` message carrying those same `functionCalls` (and,\n * to keep the model's chain-of-thought, the captured reasoning fields).\n * 3. Push back one `role: \"tool\"` message whose `toolResults` answer each call\n * by `toolCallId`.\n *\n * The SDK is a pure transport: it does NOT echo reasoning or pair results for\n * you — it serializes exactly what you put here. Every tool/reasoning field is\n * optional, so a plain `{ role, content }` message behaves as before.\n *\n * @example\n * // turn 1 — model asks for the weather\n * const a = await callWithRetries(id, { model, messages, functions });\n * // a.function_calls -> [{ id: \"call_abc\", name: \"get_weather\", arguments: { city: \"Tokyo\" } }]\n *\n * // turn 2 — feed the call + its result back\n * const next = await callWithRetries(id, { model, functions, messages: [\n * ...messages,\n * { role: \"assistant\", content: a.content ?? \"\", functionCalls: a.function_calls,\n * reasoning: a.reasoning, reasoningDetails: a.reasoningDetails },\n * { role: \"tool\", content: \"\", toolResults: [\n * { toolCallId: \"call_abc\", name: \"get_weather\", content: '{\"tempC\":22}' } ] },\n * ]});\n */\nexport interface GenericMessage {\n /**\n * `\"tool\"` carries tool results (see `toolResults`) back to the model and\n * must immediately follow the `assistant` turn that made the matching calls.\n */\n role: \"user\" | \"assistant\" | \"system\" | \"tool\";\n /** Plain-text content. Use `\"\"` for a tool-call-only or tool-result turn. */\n content: string;\n timestamp?: string;\n files?: File[];\n /**\n * Tool calls the model made on an `assistant` turn. Pass back the `id`s you\n * received in `ParsedResponseMessage.function_calls` so the provider can pair\n * them with the `toolResults` that follow.\n */\n functionCalls?: FunctionCall[];\n /**\n * Tool outputs on a `role: \"tool\"` message — one entry per call (parallel\n * calls produce several). Each `toolCallId` must match a `FunctionCall.id`\n * from the preceding assistant turn.\n */\n toolResults?: ToolResult[];\n /**\n * Optional reasoning string to echo back on an `assistant` turn (e.g.\n * OpenRouter/DeepSeek `reasoning`). Round-tripping it keeps the model's\n * chain-of-thought across tool calls; some thinking models (DeepSeek V4)\n * require it to avoid a 400 on the next turn.\n */\n reasoning?: string;\n /**\n * Optional structured reasoning to echo back on an `assistant` turn\n * (OpenRouter `reasoning_details`, or Anthropic `thinking` /\n * `redacted_thinking` blocks captured in\n * `ParsedResponseMessage.reasoningDetails`). Preserves the signatures /\n * encrypted payloads that providers validate on round-trip.\n *\n * Safe to echo regardless of which provider serves the next call: each\n * serializer keeps only its own provider's block shapes (Anthropic keeps\n * `thinking`/`redacted_thinking`; OpenAI-compat keeps `reasoning.*`), so a\n * cross-provider fallback drops foreign blocks instead of 400ing.\n */\n reasoningDetails?: any;\n}\n\n/**\n * The result of executing one tool call, fed back to the model on a\n * `role: \"tool\"` message. The SDK maps this to each provider's native shape:\n * OpenAI/Groq/OpenRouter `{ role: \"tool\", tool_call_id, content }`, Anthropic a\n * `tool_result` block, Google a `functionResponse` part.\n */\nexport interface ToolResult {\n /** The `id` of the `FunctionCall` this answers (from the prior assistant turn). */\n toolCallId: string;\n /**\n * The tool/function name. Required by Anthropic and Google on round-trip; the\n * SDK falls back to the matching call's name when omitted, but supplying it is\n * recommended.\n */\n name?: string;\n /** The tool output, serialized to a string (JSON or plain text). */\n content: string;\n}\n\nexport interface File {\n mimeType: string;\n url?: string;\n data?: string;\n}\n\n/**\n * A tool/function call on the wire for OpenAI-compatible APIs (OpenAI, Groq,\n * OpenRouter).\n */\nexport interface OpenAIToolCall {\n id: string;\n type: \"function\";\n function: {\n name: string;\n /** JSON-stringified arguments object. */\n arguments: string;\n };\n}\n\nexport interface OpenAIMessage {\n role: \"user\" | \"assistant\" | \"system\" | \"tool\";\n /** `null` for an assistant turn that is tool-calls-only. */\n content: string | OpenAIContentBlock[] | null;\n /** Present on an assistant turn that called tools. */\n tool_calls?: OpenAIToolCall[];\n /** Present on a `role: \"tool\"` message; matches the originating `OpenAIToolCall.id`. */\n tool_call_id?: string;\n /** Reasoning echoed back on an assistant turn (OpenRouter/DeepSeek; OAI-compatible proxies). */\n reasoning?: string;\n /** Structured reasoning echoed back on an assistant turn (OpenRouter `reasoning_details`). */\n reasoning_details?: any;\n}\n\nexport type OpenAIContentBlock =\n | OpenAITextContentBlock\n | OpenAIImageContentBlock\n | OpenAIAudioContentBlock;\n\nexport interface OpenAITextContentBlock {\n type: \"text\";\n text: string;\n}\n\nexport interface OpenAIImageContentBlock {\n type: \"image_url\";\n image_url: {\n url: string; // URL to the image, can also be a base64 string\n };\n}\n\nexport interface OpenAIAudioContentBlock {\n type: \"audio_url\";\n audio_url: {\n url: string; // URL to the audio, can also be a base64 string\n };\n}\n\nexport interface AnthropicAIMessage {\n role: \"user\" | \"assistant\" | \"system\";\n content: string | AnthropicContentBlock[];\n}\n\nexport type AnthropicContentBlock =\n | AnthropicTextContentBlock\n | AnthropicImageContentBlock\n | AnthropicToolUseBlock\n | AnthropicToolResultBlock\n | AnthropicThinkingBlock\n | AnthropicRedactedThinkingBlock;\n\nexport interface AnthropicTextContentBlock {\n type: \"text\";\n text: string;\n}\n\nexport interface AnthropicImageContentBlock {\n type: \"image\";\n source: {\n type: \"base64\";\n media_type: \"image/jpeg\" | \"image/png\" | \"image/gif\" | \"image/webp\";\n data: string; // Must be a base64 string\n };\n}\n\n/** A tool call on an Anthropic assistant turn. */\nexport interface AnthropicToolUseBlock {\n type: \"tool_use\";\n id: string;\n name: string;\n input: Record<string, any>;\n}\n\n/** A tool result, carried on a (user-role) Anthropic message. */\nexport interface AnthropicToolResultBlock {\n type: \"tool_result\";\n tool_use_id: string;\n content: string;\n}\n\n/** A reasoning block round-tripped on an assistant turn; `signature` is validated by Anthropic. */\nexport interface AnthropicThinkingBlock {\n type: \"thinking\";\n thinking: string;\n signature: string;\n}\n\n/** An encrypted reasoning block round-tripped verbatim on an assistant turn. */\nexport interface AnthropicRedactedThinkingBlock {\n type: \"redacted_thinking\";\n data: string;\n}\n\nexport interface OpenAIResponseMessage {\n role: \"assistant\";\n content: string | null;\n function_call: {\n name: string;\n arguments: string; // unparsed arguments object\n } | null;\n}\n\nexport interface ParsedResponseMessage {\n role: \"assistant\";\n content: string | null;\n /** First of `function_calls` (backward-compat); carries `id` when the provider returns one. */\n function_call: FunctionCall | null;\n /** All tool calls the model made this turn, each with an `id` for round-tripping. */\n function_calls: FunctionCall[];\n files: File[];\n /**\n * Reasoning string from reasoning models (OpenRouter/DeepSeek `reasoning`).\n * Echo back via `GenericMessage.reasoning` to preserve chain-of-thought across\n * tool calls. Undefined when the model/provider returns none.\n */\n reasoning?: string;\n /**\n * Structured reasoning (OpenRouter `reasoning_details`, or Anthropic\n * `thinking` / `redacted_thinking` blocks). Echo back verbatim via\n * `GenericMessage.reasoningDetails` — it carries signatures some providers\n * validate. Undefined when the model/provider returns none.\n */\n reasoningDetails?: any;\n /**\n * Who actually served the response. For OpenRouter this is the upstream\n * provider from the response body (e.g. \"Baidu\", \"Morph\") — the routing\n * decision OpenRouter made, not the requested model slug. For direct\n * providers it's the SDK provider name (\"anthropic\", \"openai\", \"google\",\n * \"groq\"). On model fallback it reflects the model that answered, so a\n * mismatch with the requested model's provider reveals the fallback.\n */\n provider?: string;\n usage: {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n /** Prompt tokens served from the provider's cache (subset of prompt_tokens). */\n cached_tokens?: number;\n } | null;\n}\n\nexport interface FunctionCall {\n /**\n * Provider tool-call id, surfaced on responses and used to pair a call with\n * its `ToolResult.toolCallId` on the next turn. The SDK synthesizes\n * `call_<index>` for providers that don't return one (e.g. Google).\n */\n id?: string;\n name: string;\n arguments: Record<string, any>;\n /**\n * Opaque per-call signature that must be echoed back verbatim on round-trip.\n * Currently Google's `thoughtSignature` — Gemini REQUIRES it on functionCall\n * parts in multi-turn tool use (a missing one 400s the next request). The SDK\n * captures it on responses and re-emits it when you pass the call back;\n * undefined for providers that don't use one.\n */\n thoughtSignature?: string;\n}\n\nexport interface OpenAIConfig {\n service: \"azure\" | \"openai\";\n apiKey: string;\n /**\n * Override the base URL for the OpenAI service (e.g. an OpenAI-compatible\n * proxy or self-hosted endpoint). The path `/chat/completions` is appended.\n * Ignored when `service === \"azure\"` (use `modelConfigMap` instead).\n * Defaults to `https://api.openai.com/v1`.\n */\n baseUrl?: string;\n orgId?: string;\n modelConfigMap?: Record<\n GPTModel,\n {\n resource: string;\n deployment: string;\n apiVersion: string;\n apiKey: string;\n endpoint?: string;\n }\n >;\n}\n\nexport interface AnthropicAIConfig {\n service: \"anthropic\" | \"bedrock\";\n}\n\nexport interface FunctionDefinition {\n name: string;\n description?: string;\n parameters: Record<string, any>;\n}\n\ninterface FunctionWrapped {\n type: \"function\";\n function: FunctionDefinition;\n}\n\nexport interface GroqPayload {\n model: GroqModel | string;\n messages: OpenAIMessage[];\n tools?: FunctionWrapped[];\n tool_choice?:\n | \"none\"\n | \"auto\"\n | { type: \"function\"; function: { name: string } };\n temperature?: number;\n\n functions?: any[]; // Deprecate this\n}\n\n/**\n * OpenRouter provider-routing preferences, forwarded verbatim as the request\n * body's `provider` field. See https://openrouter.ai/docs/guides/routing/provider-selection\n */\nexport interface OpenRouterProviderPreferences {\n /** Ordered list of provider slugs to try first (e.g. [\"baidu\", \"siliconflow\"]). */\n order?: string[];\n /** Restrict routing to exactly these provider slugs. */\n only?: string[];\n /** Provider slugs to exclude. */\n ignore?: string[];\n /** Only use providers serving these quantizations (e.g. [\"fp8\"]). */\n quantizations?: string[];\n /** When false, never fall back to providers outside `order`/`only`. */\n allow_fallbacks?: boolean;\n /** Override the default sort (\"price\" | \"throughput\" | \"latency\"). */\n sort?: string;\n}\n\nexport interface OpenRouterPayload {\n model: OpenRouterModel | string;\n messages: OpenAIMessage[];\n tools?: FunctionWrapped[];\n tool_choice?:\n | \"none\"\n | \"auto\"\n | { type: \"function\"; function: { name: string } };\n temperature?: number;\n provider?: OpenRouterProviderPreferences;\n /** Set by the adapter, never by callers: SSE streaming on/off. */\n stream?: boolean;\n /**\n * Set by the adapter on streamed requests: OpenRouter's usage-accounting\n * flag, which makes the final SSE chunk carry the `usage` object.\n */\n usage?: { include: boolean };\n}\n\nexport interface OpenAIPayload {\n model: GPTModel | string;\n messages: OpenAIMessage[];\n tools?: FunctionWrapped[];\n tool_choice?:\n | \"none\"\n | \"auto\"\n | { type: \"function\"; function: { name: string } };\n}\n\nexport interface AnthropicAIPayload {\n model: ClaudeModel | string;\n messages: AnthropicAIMessage[];\n functions?: any[]; // TODO type this JSON schema\n temperature?: number;\n system?: string;\n tool_choice?: { type: \"none\" | \"auto\" } | { type: \"tool\"; name: string };\n}\n\nexport interface GoogleAITextPart {\n text: string;\n}\n\nexport interface GoogleAIInlineDataPart {\n inlineData: {\n mimeType: string;\n data: string;\n };\n}\n\nexport interface GoogleAIFileDataPart {\n fileData: {\n mimeType: string;\n fileUri: string;\n };\n}\n\n/** A tool call on a Google `model` turn. */\nexport interface GoogleAIFunctionCallPart {\n functionCall: {\n id?: string;\n name: string;\n args: Record<string, any>;\n };\n /** Echoed back verbatim on round-trip — Gemini requires it for tool use. */\n thoughtSignature?: string;\n}\n\n/** A tool result, carried on a Google `user` turn. */\nexport interface GoogleAIFunctionResponsePart {\n functionResponse: {\n id?: string;\n name: string;\n response: Record<string, any>;\n };\n}\n\nexport type GoogleAIPart =\n | GoogleAITextPart\n | GoogleAIInlineDataPart\n | GoogleAIFileDataPart\n | GoogleAIFunctionCallPart\n | GoogleAIFunctionResponsePart;\nexport interface GoogleAIMessage {\n role: \"user\" | \"model\";\n parts: GoogleAIPart[];\n}\nexport interface GoogleAIPayload {\n model: GeminiModel | string;\n messages: GoogleAIMessage[];\n tools?: {\n functionDeclarations: FunctionDefinition[];\n };\n toolConfig?: {\n functionCallingConfig: { mode: \"NONE\" | \"AUTO\" | \"ANY\" };\n };\n systemInstruction?: string;\n}\n\nexport type Provider = \"openai\" | \"anthropic\" | \"google\" | \"groq\" | \"openrouter\";\n\nexport type AnyModel = GPTModel | ClaudeModel | GroqModel | GeminiModel | OpenRouterModel | (string & {});\n\nexport interface GenericPayload {\n model: AnyModel;\n messages: GenericMessage[];\n functions?: FunctionDefinition[];\n function_call?: \"none\" | \"auto\" | { name: string };\n temperature?: number;\n fallbackModel?: AnyModel;\n /**\n * OpenRouter-only: provider-routing preferences. Ignored by non-OpenRouter\n * adapters. Forwarded as the request body's `provider` field.\n */\n provider?: OpenRouterProviderPreferences;\n /**\n * Per-request HTTP timeout in ms for the underlying provider call (applied\n * per attempt, not across retries). Honored by all adapters (Anthropic,\n * Google, OpenAI, OpenRouter, Groq); defaults to 120s when omitted. Raise it\n * for slow, large generations (e.g. single-file app codegen) so a long-but-\n * valid response isn't cut short.\n */\n requestTimeoutMs?: number;\n /**\n * OpenRouter-only: stream the completion over SSE instead of waiting for a\n * single JSON body. Defaults to true. Streaming attempts are bounded by\n * `streamTimeoutMs` (total) plus a per-useful-chunk stall timeout — NOT by\n * `requestTimeoutMs`, which only governs non-streaming attempts (default\n * 180s for OpenRouter). Set to false to force the old non-streaming path.\n */\n streaming?: boolean;\n /**\n * OpenRouter-only: total wall-clock budget in ms for one streaming attempt\n * (connect + full generation). Defaults to 600s. Independent of\n * `requestTimeoutMs` by design: a healthy long generation keeps streaming\n * useful chunks and may run far past any sane non-streaming deadline, while\n * a hung one is killed much earlier by the per-useful-chunk stall timeout\n * (`chunkTimeoutMs` argument of `callWithRetries`, default 15s — reset only\n * by chunks that advance the output, never by keep-alive bytes/comments).\n */\n streamTimeoutMs?: number;\n /**\n * OpenRouter-only: absolute wall-clock deadline (epoch ms) for the whole\n * call INCLUDING retries — the caller's turn budget, not a per-attempt one.\n * Each streaming attempt gets `min(streamTimeoutMs, deadline - now)`, and\n * once too little time remains to be worth an attempt the call fails fast\n * instead of starting a generation that cannot finish.\n *\n * Without it, a per-attempt budget is re-granted on every retry, so a slow\n * generation can outlive the caller's own turn deadline and get killed with\n * nothing to show (2026-07-28: a 538s completion finished just as the\n * caller's 585s turn budget expired, and the reply was discarded).\n */\n streamDeadlineAt?: number;\n /**\n * Optional caller-supplied cancellation signal. When it aborts, the in-flight\n * provider request is cancelled and `callWithRetries` rejects immediately —\n * it does NOT retry or fall back (both retry loop and fallback branch bail on\n * `signal.aborted`). Threaded through every adapter to the underlying\n * fetch/axios/SDK call, mirroring `requestTimeoutMs`.\n */\n signal?: AbortSignal;\n}\n\nexport interface OpenAIBody {\n choices: {\n message: OpenAIResponseMessage;\n }[];\n error?: {\n code: string;\n };\n usage: {\n completion_tokens: number;\n prompt_tokens: number;\n total_tokens: number;\n prompt_tokens_details?: {\n cached_tokens?: number;\n };\n };\n}\n","type LogLevel = \"LOG\" | \"WARN\" | \"ERROR\";\nexport type Identifier = string | string[];\n\nfunction formatIdentifier(identifier: Identifier): string {\n if (Array.isArray(identifier)) {\n return identifier.map((id) => `[${id}]`).join(\" \");\n }\n return `[${identifier}]`;\n}\n\nfunction formatMessage(\n level: LogLevel,\n identifier: Identifier,\n message: string\n): string {\n return `[${level}] ${formatIdentifier(identifier)} ${message}`;\n}\n\nexport function log(\n identifier: Identifier,\n message: string,\n ...args: any[]\n): void {\n console.log(formatMessage(\"LOG\", identifier, message), ...args);\n}\n\nexport function warn(\n identifier: Identifier,\n message: string,\n ...args: any[]\n): void {\n console.warn(formatMessage(\"WARN\", identifier, message), ...args);\n}\n\nexport function error(\n identifier: Identifier,\n message: string,\n ...args: any[]\n): void {\n console.error(formatMessage(\"ERROR\", identifier, message), ...args);\n}\n\nexport default {\n log,\n warn,\n error,\n};\n","export function timeout(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function isHeicImage(name: string, mime?: string): boolean {\n const extension = name.split(\".\").pop()?.toLowerCase() || \"\";\n return (\n [\"heic\", \"heif\", \"heics\"].includes(extension) ||\n !!(\n mime && [\"image/heic\", \"image/heif\", \"image/heic-sequence\"].includes(mime)\n )\n );\n}\n"],"mappings":"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","names":["ClaudeModel","GPTModel","GroqModel","OpenRouterModel","GeminiModel","error","axios","_a"]}
1
+ {"version":3,"sources":["../index.ts","../interfaces.ts","../logger.ts","../utils.ts"],"sourcesContent":["import {\n ClaudeModel,\n GPTModel,\n OpenAIPayload,\n OpenAIMessage,\n OpenAIConfig,\n AnthropicAIPayload,\n AnthropicAIMessage,\n GenericMessage,\n AnthropicAIConfig,\n GenericPayload,\n GroqPayload,\n GroqModel,\n OpenRouterPayload,\n OpenRouterModel,\n ParsedResponseMessage,\n FunctionCall,\n AnthropicContentBlock,\n OpenAIContentBlock,\n GoogleAIPayload,\n GeminiModel,\n GoogleAIPart,\n File,\n GoogleAIMessage,\n AnyModel,\n Provider,\n} from \"./interfaces\";\nimport logger, { Identifier } from \"./logger\";\nimport {\n BedrockRuntimeClient,\n InvokeModelCommand,\n} from \"@aws-sdk/client-bedrock-runtime\";\nimport axios from \"axios\";\nimport { isHeicImage, timeout } from \"./utils\";\n\nconst sharp = require(\"sharp\");\nconst decode = require(\"heic-decode\");\n\nexport {\n ClaudeModel,\n GPTModel,\n GroqModel,\n GeminiModel,\n OpenRouterModel,\n OpenAIConfig,\n FunctionDefinition,\n FunctionCall,\n GenericMessage,\n GenericPayload,\n ToolResult,\n ParsedResponseMessage,\n OpenRouterProviderPreferences,\n AnyModel,\n Provider,\n} from \"./interfaces\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// SHARED UTILITIES\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * `AbortSignal.any` exists at runtime (Node 18.17+/20.3+) but isn't in the\n * pinned @types/node lib; centralize the cast so call sites stay typed. Used to\n * merge a caller's cancellation signal with an adapter's internal timeout\n * controller without clobbering either.\n */\nfunction anySignal(signals: AbortSignal[]): AbortSignal {\n return (AbortSignal as unknown as { any(s: AbortSignal[]): AbortSignal }).any(\n signals,\n );\n}\n\n/**\n * Run an axios-based provider call under a wall-clock deadline. Axios's\n * `timeout` option is a socket *idle* timer — providers that dribble\n * keep-alive bytes while a long generation runs (OpenRouter does this\n * explicitly) reset it forever, so a stuck upstream holds the request open\n * until the caller's walltime kills the whole turn (2026-07-26: a 9.7-minute\n * OpenRouter call with requestTimeoutMs=120s \"set\"). AbortSignal.timeout\n * bounds elapsed time instead; the idle `timeout` stays as a faster trigger\n * for fully dead sockets.\n */\nasync function withRequestDeadline<T>(\n apiName: string,\n requestTimeoutMs: number,\n signal: AbortSignal | undefined,\n fn: (mergedSignal: AbortSignal) => Promise<T>,\n): Promise<T> {\n const deadline = AbortSignal.timeout(requestTimeoutMs);\n try {\n return await fn(signal ? anySignal([signal, deadline]) : deadline);\n } catch (error) {\n // Axios surfaces any abort as a bare \"canceled\" — restore the real reason\n // so retry logs and model-facing errors say what actually happened.\n if (deadline.aborted && !signal?.aborted) {\n throw new Error(\n `${apiName} request exceeded hard deadline of ${requestTimeoutMs}ms`,\n );\n }\n throw error;\n }\n}\n\n/**\n * Generic retry wrapper for API calls with exponential backoff.\n */\nasync function withRetries<T>(\n identifier: Identifier,\n apiName: string,\n fn: () => Promise<T>,\n options: {\n retries?: number;\n baseDelayMs?: number;\n onError?: (error: any, attempt: number) => void;\n signal?: AbortSignal;\n } = {},\n): Promise<T> {\n const { retries = 5, baseDelayMs = 125, onError } = options;\n\n logger.log(identifier, `Calling ${apiName} API with retries`);\n\n let lastError: any;\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n return await fn();\n } catch (error: any) {\n lastError = error;\n\n // Caller cancelled — reject immediately, never retry. Keyed on\n // signal.aborted (not error.name/code) because some adapters re-wrap the\n // underlying abort error and lose its name (e.g. the Google adapter).\n if (options.signal?.aborted) throw error;\n\n if (onError) {\n onError(error, attempt);\n } else {\n logger.error(\n identifier,\n `Retry #${attempt} error: ${error.message}`,\n error.response?.data || error,\n );\n }\n\n await timeout(baseDelayMs * attempt);\n }\n }\n\n // Fold the underlying cause into .message so it survives callers that read\n // error.message (and drop error.cause) — otherwise the raw reason (timeout,\n // provider 4xx body, etc.) never reaches the agent's model-facing error. Prefer\n // the provider's response body, which is richer than axios's \"Request failed\n // with status code N\".\n const detail =\n lastError?.response?.data?.error?.message ||\n lastError?.message ||\n String(lastError);\n const error = new Error(\n `Failed to call ${apiName} API after ${retries} attempts: ${detail}`,\n ) as any;\n error.cause = lastError;\n throw error;\n}\n\nfunction parseStreamedResponse(\n identifier: Identifier,\n paragraph: string,\n toolCallAccumulators: { id?: string; name: string; arguments: string }[],\n allowedFunctionNames: Set<string> | null,\n reasoning?: string,\n): ParsedResponseMessage {\n const functionCalls: FunctionCall[] = [];\n\n for (let i = 0; i < toolCallAccumulators.length; i++) {\n const acc = toolCallAccumulators[i];\n if (!acc.name || !acc.arguments) continue;\n\n if (allowedFunctionNames && !allowedFunctionNames.has(acc.name)) {\n throw new Error(\n `Stream error: received function call with unknown name: ${acc.name}`,\n );\n }\n\n try {\n functionCalls.push({\n id: acc.id || `call_${i}`,\n name: acc.name,\n arguments: JSON.parse(acc.arguments),\n });\n } catch (error) {\n logger.error(\n identifier,\n \"Error parsing function call arguments:\",\n acc.arguments,\n );\n throw error;\n }\n }\n\n if (!paragraph && !functionCalls.length) {\n logger.error(\n identifier,\n \"Stream error: received message without content or function_call:\",\n JSON.stringify({ paragraph, toolCallAccumulators }),\n );\n throw new Error(\n \"Stream error: received message without content or function_call\",\n );\n }\n\n return {\n role: \"assistant\",\n content: paragraph || null,\n function_call: functionCalls[0] || null,\n function_calls: functionCalls,\n files: [],\n reasoning: reasoning || undefined,\n usage: null,\n };\n}\n\nfunction truncatePayload(payload: OpenAIPayload): string {\n return JSON.stringify(\n {\n ...payload,\n messages: payload.messages.map((message) => {\n const truncatedMessage = { ...message };\n if (typeof truncatedMessage.content === \"string\") {\n truncatedMessage.content = truncatedMessage.content.slice(0, 100);\n } else if (Array.isArray(truncatedMessage.content)) {\n truncatedMessage.content = truncatedMessage.content.map((block) => {\n if (block.type === \"image_url\") {\n return {\n ...block,\n image_url: { url: block.image_url.url.slice(0, 100) },\n };\n }\n return block;\n });\n }\n return truncatedMessage;\n }),\n },\n null,\n 2,\n );\n}\n\nasync function getNormalizedBase64PNG(\n url: string,\n mime: string,\n): Promise<string> {\n const response = await axios.get(url, { responseType: \"arraybuffer\" });\n\n let imageBuffer = Buffer.from(response.data);\n let sharpOptions = {};\n\n if (isHeicImage(url, mime)) {\n const imageData = await decode({ buffer: imageBuffer });\n imageBuffer = Buffer.from(imageData.data);\n sharpOptions = {\n raw: {\n width: imageData.width,\n height: imageData.height,\n channels: 4,\n },\n };\n }\n\n // Limits size of image to < 5MB Anthropic limit\n const resizedBuffer = await sharp(imageBuffer, sharpOptions)\n .withMetadata()\n .resize(1024, 1024, { fit: \"inside\", withoutEnlargement: true })\n .png()\n .toBuffer();\n\n return resizedBuffer.toString(\"base64\");\n}\n\nconst ALLOWED_IMAGE_MIME_TYPES = [\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\",\n];\n\n// ─────────────────────────────────────────────────────────────────────────────\n// OPENAI\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface OpenAIRequestConfig {\n endpoint: string;\n headers: Record<string, string>;\n}\n\nfunction buildOpenAIRequestConfig(\n identifier: Identifier,\n model: string,\n config: OpenAIConfig | undefined,\n): OpenAIRequestConfig {\n if (!config) {\n config = {\n service: \"openai\",\n apiKey: process.env.OPENAI_API_KEY as string,\n baseUrl: \"\",\n };\n }\n\n if (config.service === \"azure\") {\n logger.log(identifier, \"Using Azure OpenAI service:\", model);\n\n if (!config.modelConfigMap) {\n throw new Error(\n \"OpenAI config modelConfigMap is required when using Azure OpenAI service.\",\n );\n }\n\n const azureConfig = config.modelConfigMap[model as GPTModel];\n if (!azureConfig?.endpoint) {\n throw new Error(\"Azure OpenAI endpoint is required in modelConfigMap.\");\n }\n\n const endpoint = `${azureConfig.endpoint}/openai/deployments/${azureConfig.deployment}/chat/completions?api-version=${azureConfig.apiVersion}`;\n logger.log(identifier, \"Using endpoint:\", endpoint);\n\n return {\n endpoint,\n headers: {\n \"Content-Type\": \"application/json\",\n \"api-key\": azureConfig.apiKey,\n },\n };\n }\n\n // Default: OpenAI (or any OpenAI-compatible server via config.baseUrl)\n logger.log(identifier, \"Using OpenAI service:\", model);\n if (config.orgId) {\n logger.log(identifier, \"Using orgId:\", config.orgId);\n }\n\n const base = (config.baseUrl?.trim() || \"https://api.openai.com/v1\").replace(\n /\\/$/,\n \"\",\n );\n return {\n endpoint: `${base}/chat/completions`,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${config.apiKey}`,\n ...(config.orgId ? { \"OpenAI-Organization\": config.orgId } : {}),\n },\n };\n}\n\n/**\n * Keep only OpenAI-compat `reasoning.*` blocks when echoing reasoning_details.\n * A cross-provider fallback replays reasoningDetails captured from Anthropic\n * (`thinking`/`redacted_thinking`), which don't belong in reasoning_details.\n * Returns undefined when nothing native-shaped remains.\n */\nfunction filterOpenAICompatReasoningDetails(details: any): any[] | undefined {\n if (!Array.isArray(details)) return details || undefined;\n const blocks = details.filter(\n (block: any) =>\n typeof block?.type === \"string\" && block.type.startsWith(\"reasoning.\"),\n );\n return blocks.length ? blocks : undefined;\n}\n\nasync function prepareOpenAIPayload(\n identifier: Identifier,\n payload: GenericPayload,\n): Promise<OpenAIPayload> {\n const preparedPayload: OpenAIPayload = {\n model: payload.model as GPTModel,\n messages: [],\n tools: payload.functions?.map((fn) => ({\n type: \"function\",\n function: fn,\n })),\n tool_choice: payload.function_call\n ? typeof payload.function_call === \"string\"\n ? payload.function_call\n : { type: \"function\", function: payload.function_call }\n : undefined,\n };\n\n for (const message of payload.messages) {\n // role:\"tool\" → one OpenAI tool message per result (parallel calls expand).\n if (message.role === \"tool\") {\n for (const tr of message.toolResults || []) {\n preparedPayload.messages.push({\n role: \"tool\",\n tool_call_id: tr.toolCallId,\n content: tr.content,\n });\n }\n continue;\n }\n\n const contentBlocks: OpenAIContentBlock[] = [];\n\n if (message.content) {\n contentBlocks.push({ type: \"text\", text: message.content });\n }\n\n for (const file of message.files || []) {\n if (ALLOWED_IMAGE_MIME_TYPES.includes(file.mimeType)) {\n if (file.url) {\n contentBlocks.push({\n type: \"image_url\",\n image_url: { url: file.url },\n });\n contentBlocks.push({ type: \"text\", text: `Image (${file.url})` });\n } else if (file.data) {\n contentBlocks.push({\n type: \"image_url\",\n image_url: { url: `data:${file.mimeType};base64,${file.data}` },\n });\n }\n } else if (file.url) {\n // Non-image file with URL - add text reference\n contentBlocks.push({\n type: \"text\",\n text: `File (${file.url})`,\n });\n }\n }\n\n const outMessage: OpenAIMessage = {\n role: message.role,\n // OpenAI wants null (not []) content on a tool-call-only assistant turn.\n content: contentBlocks.length ? contentBlocks : null,\n };\n if (message.functionCalls?.length) {\n outMessage.tool_calls = message.functionCalls.map((fc, i) => ({\n id: fc.id ?? `call_${i}`,\n type: \"function\" as const,\n function: {\n name: fc.name,\n arguments: JSON.stringify(fc.arguments),\n },\n }));\n }\n // Reasoning passthrough — only when the caller supplied it (never injected).\n if (message.reasoning) outMessage.reasoning = message.reasoning;\n const reasoningDetails = filterOpenAICompatReasoningDetails(\n message.reasoningDetails,\n );\n if (reasoningDetails) outMessage.reasoning_details = reasoningDetails;\n preparedPayload.messages.push(outMessage);\n }\n\n return preparedPayload;\n}\n\nasync function callOpenAIStream(\n id: Identifier,\n openAiPayload: OpenAIPayload,\n openAiConfig: OpenAIConfig | undefined,\n chunkTimeoutMs: number,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const functionNames: Set<string> | null = openAiPayload.tools\n ? new Set(openAiPayload.tools.map((fn) => fn.function.name as string))\n : null;\n\n const { endpoint, headers } = buildOpenAIRequestConfig(\n id,\n openAiPayload.model,\n openAiConfig,\n );\n\n const controller = new AbortController();\n // Overall per-attempt deadline (separate from the per-chunk stall timeout\n // below): aborts the same controller if the whole stream runs past the\n // budget. unref'd so it never holds the event loop; cleared on the success\n // path, and a no-op abort on a finished stream otherwise.\n const overallTimeout = setTimeout(() => {\n logger.error(id, `Request timeout after ${requestTimeoutMs}ms`);\n controller.abort();\n }, requestTimeoutMs);\n if (typeof overallTimeout === \"object\" && \"unref\" in overallTimeout) {\n overallTimeout.unref();\n }\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ ...openAiPayload, stream: true }),\n // Merge (don't overwrite) the internal timeout controller with the caller's\n // cancellation signal so both an internal timeout and an external abort stop\n // the stream.\n signal: signal ? anySignal([controller.signal, signal]) : controller.signal,\n });\n\n if (!response.body) {\n throw new Error(\"Stream error: no response body\");\n }\n\n let paragraph = \"\";\n let reasoning = \"\";\n const toolCallAccumulators: { id?: string; name: string; arguments: string }[] =\n [];\n\n const reader = response.body.getReader();\n let partialChunk = \"\";\n let chunkIndex = -1;\n\n const createAbortTimeout = () =>\n setTimeout(() => {\n logger.error(id, `Stream timeout after ${chunkTimeoutMs}ms`);\n controller.abort();\n }, chunkTimeoutMs);\n\n while (true) {\n chunkIndex++;\n const abortTimeout = createAbortTimeout();\n const { done, value } = await reader.read();\n clearTimeout(abortTimeout);\n\n if (done) {\n logger.error(\n id,\n `Stream ended prematurely after ${chunkIndex + 1} chunks`,\n );\n throw new Error(\"Stream error: ended prematurely\");\n }\n\n let chunk = new TextDecoder().decode(value);\n if (partialChunk) {\n chunk = partialChunk + chunk;\n partialChunk = \"\";\n }\n\n const jsonStrings = chunk.split(/^data: /gm);\n\n for (const jsonString of jsonStrings) {\n if (!jsonString) continue;\n\n if (jsonString.includes(\"[DONE]\")) {\n clearTimeout(overallTimeout);\n return parseStreamedResponse(\n id,\n paragraph,\n toolCallAccumulators,\n functionNames,\n reasoning,\n );\n }\n\n let json;\n try {\n json = JSON.parse(jsonString.trim());\n } catch {\n partialChunk = jsonString;\n continue;\n }\n\n if (!json.choices?.length) {\n if (json.error) {\n logger.error(id, \"Stream error from OpenAI:\", json.error);\n const error = new Error(\"Stream error: OpenAI error\") as any;\n error.data = json.error;\n error.requestBody = truncatePayload(openAiPayload);\n throw error;\n }\n if (chunkIndex !== 0) {\n logger.error(id, \"Stream error: no choices in JSON:\", json);\n }\n continue;\n }\n\n const toolCalls = json.choices[0]?.delta?.tool_calls;\n if (toolCalls) {\n for (const toolCall of toolCalls) {\n const idx = toolCall.index ?? 0;\n while (toolCallAccumulators.length <= idx) {\n toolCallAccumulators.push({ name: \"\", arguments: \"\" });\n }\n // The id arrives on the first fragment of each call.\n if (toolCall.id) toolCallAccumulators[idx].id = toolCall.id;\n if (toolCall.function?.name)\n toolCallAccumulators[idx].name += toolCall.function.name;\n if (toolCall.function?.arguments)\n toolCallAccumulators[idx].arguments += toolCall.function.arguments;\n }\n }\n\n const text = json.choices[0]?.delta?.content;\n if (text) paragraph += text;\n\n // Reasoning models (OpenRouter/OAI-compatible) stream a parallel\n // `reasoning` channel; accumulate it so callers can round-trip it.\n const reasoningDelta = json.choices[0]?.delta?.reasoning;\n if (reasoningDelta) reasoning += reasoningDelta;\n }\n }\n}\n\nasync function callOpenAI(\n id: Identifier,\n openAiPayload: OpenAIPayload,\n openAiConfig: OpenAIConfig | undefined,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const { endpoint, headers } = buildOpenAIRequestConfig(\n id,\n openAiPayload.model,\n openAiConfig,\n );\n\n // Per-attempt deadline covering the request + body read (fetch has no built-in\n // timeout). Cleared once the body is read; an abort surfaces as a retryable error.\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), requestTimeoutMs);\n let data: any;\n try {\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ ...openAiPayload, stream: false }),\n // Merge the internal timeout controller with the caller's cancellation signal.\n signal: signal ? anySignal([controller.signal, signal]) : controller.signal,\n });\n\n if (!response.ok) {\n const errorData = await response.json();\n logger.error(id, \"OpenAI API error:\", errorData);\n throw new Error(`OpenAI API Error: ${errorData.error.message}`);\n }\n\n data = await response.json();\n } finally {\n clearTimeout(timer);\n }\n\n if (!data.choices?.length) {\n if (data.error) {\n logger.error(id, \"OpenAI error:\", data.error);\n throw new Error(`OpenAI error: ${data.error.message}`);\n }\n throw new Error(\"OpenAI error: No choices returned.\");\n }\n\n const choice = data.choices[0];\n\n // Check for tool_calls (modern API) first, fall back to function_call (legacy)\n const toolCalls = choice.message?.tool_calls;\n const functionCalls: FunctionCall[] = [];\n\n if (toolCalls?.length) {\n for (let i = 0; i < toolCalls.length; i++) {\n const tc = toolCalls[i];\n functionCalls.push({\n id: tc.id ?? `call_${i}`,\n name: tc.function.name,\n arguments: JSON.parse(tc.function.arguments),\n });\n }\n } else if (choice.function_call) {\n functionCalls.push({\n id: \"call_0\",\n name: choice.function_call.name,\n arguments: JSON.parse(choice.function_call.arguments),\n });\n }\n\n // An empty 200 (no content, no tool call) is not a usable answer — throw so\n // withRetries retries and callWithRetries can fall back. (Mirrors the\n // streaming path's guard in parseStreamedResponse.)\n if (!choice.message?.content && !functionCalls.length) {\n logger.error(\n id,\n \"OpenAI: received message without content or function_call:\",\n JSON.stringify(data),\n );\n throw new Error(\n \"OpenAI: received message without content or function_call\",\n );\n }\n\n return {\n role: \"assistant\",\n content: choice.message.content || null,\n function_call: functionCalls[0] || null,\n function_calls: functionCalls,\n files: [],\n reasoning: choice.message?.reasoning ?? undefined,\n reasoningDetails: choice.message?.reasoning_details ?? undefined,\n usage: data.usage\n ? {\n prompt_tokens: data.usage.prompt_tokens,\n completion_tokens: data.usage.completion_tokens,\n total_tokens: data.usage.total_tokens,\n cached_tokens: data.usage.prompt_tokens_details?.cached_tokens ?? 0,\n }\n : null,\n };\n}\n\nasync function callOpenAiWithRetries(\n id: Identifier,\n openAiPayload: OpenAIPayload,\n openAiConfig?: OpenAIConfig,\n retries: number = 5,\n chunkTimeoutMs: number = 15_000,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n logger.log(\n id,\n \"Calling OpenAI API with retries:\",\n openAiConfig?.service,\n openAiPayload.model,\n );\n\n const modelStr = openAiPayload.model as string;\n const useStreaming =\n modelStr !== GPTModel.O1_MINI &&\n modelStr !== GPTModel.O1_PREVIEW &&\n !modelStr.startsWith(\"o1\");\n\n return withRetries(\n id,\n \"OpenAI\",\n async () => {\n if (useStreaming) {\n return callOpenAIStream(\n id,\n openAiPayload,\n openAiConfig,\n chunkTimeoutMs,\n requestTimeoutMs,\n signal,\n );\n } else {\n return callOpenAI(id, openAiPayload, openAiConfig, requestTimeoutMs, signal);\n }\n },\n {\n retries,\n signal,\n baseDelayMs: 250,\n onError: (error, attempt) => {\n logger.error(\n id,\n `Retry #${attempt} error: ${error.message}`,\n error.response?.data || error.data || error,\n );\n\n // Remove images on content policy violation\n if (error.data?.code === \"content_policy_violation\") {\n logger.log(id, \"Removing images due to content policy violation\");\n openAiPayload.messages.forEach((message: OpenAIMessage) => {\n if (Array.isArray(message.content)) {\n message.content = message.content.filter(\n (content) => content.type === \"text\",\n );\n }\n });\n }\n },\n },\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ANTHROPIC\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction jigAnthropicMessages(\n messages: AnthropicAIMessage[],\n): AnthropicAIMessage[] {\n const hasToolBlock = (content: AnthropicAIMessage[\"content\"]) =>\n Array.isArray(content) &&\n content.some((b) => b.type === \"tool_use\" || b.type === \"tool_result\");\n\n let jiggedMessages = messages.slice();\n\n // Ensure first message is from user\n if (jiggedMessages[0]?.role !== \"user\") {\n jiggedMessages = [\n { role: \"user\" as const, content: \"...\" },\n ...jiggedMessages,\n ];\n }\n\n // Group consecutive messages with the same role\n jiggedMessages = jiggedMessages.reduce((acc, message) => {\n if (acc.length === 0) return [message];\n\n const lastMessage = acc[acc.length - 1];\n if (lastMessage.role === message.role) {\n const lastContent = Array.isArray(lastMessage.content)\n ? lastMessage.content\n : [{ type: \"text\" as const, text: lastMessage.content }];\n const newContent = Array.isArray(message.content)\n ? message.content\n : [{ type: \"text\" as const, text: message.content }];\n\n // Never inject a text separator into a turn carrying tool_use/tool_result\n // blocks — it would sit between a tool_use and its result and break\n // Anthropic's pairing requirement.\n const separator: AnthropicContentBlock[] =\n hasToolBlock(lastMessage.content) || hasToolBlock(message.content)\n ? []\n : [{ type: \"text\", text: \"\\n\\n---\\n\\n\" }];\n\n lastMessage.content = [...lastContent, ...separator, ...newContent];\n return acc;\n }\n\n // Convert string content to text content block\n if (typeof message.content === \"string\") {\n message.content = [{ type: \"text\", text: message.content }];\n }\n\n return [...acc, message];\n }, [] as AnthropicAIMessage[]);\n\n // Ensure last message is from user — but never append a placeholder after an\n // unanswered tool_use turn (a text-only user can't satisfy it).\n const last = jiggedMessages[jiggedMessages.length - 1];\n if (last?.role === \"assistant\" && !hasToolBlock(last.content)) {\n jiggedMessages.push({ role: \"user\", content: \"...\" });\n }\n\n return jiggedMessages;\n}\n\nasync function prepareAnthropicPayload(\n _identifier: Identifier,\n payload: GenericPayload,\n): Promise<AnthropicAIPayload> {\n const preparedPayload: AnthropicAIPayload = {\n model: payload.model as ClaudeModel,\n messages: [],\n functions: payload.functions,\n temperature: payload.temperature,\n // Map the generic function_call to Anthropic tool_choice (\"none\" forces a\n // text-only turn). Only meaningful alongside tools — callAnthropic sends\n // it only when tools are present (tool_choice without tools 400s).\n tool_choice: payload.function_call\n ? typeof payload.function_call === \"string\"\n ? { type: payload.function_call }\n : { type: \"tool\", name: payload.function_call.name }\n : undefined,\n };\n\n for (const message of payload.messages) {\n if (message.role === \"system\") {\n preparedPayload.system = message.content;\n continue;\n }\n\n // role:\"tool\" → a user message carrying tool_result blocks (parallel\n // results share one message, matching Anthropic's expected shape).\n if (message.role === \"tool\") {\n preparedPayload.messages.push({\n role: \"user\",\n content: (message.toolResults || []).map((tr) => ({\n type: \"tool_result\" as const,\n tool_use_id: tr.toolCallId,\n content: tr.content,\n })),\n });\n continue;\n }\n\n const contentBlocks: AnthropicContentBlock[] = [];\n\n if (message.content) {\n contentBlocks.push({ type: \"text\", text: message.content });\n }\n\n for (const file of message.files || []) {\n if (ALLOWED_IMAGE_MIME_TYPES.includes(file.mimeType)) {\n if (file.url) {\n if (message.role == \"user\") {\n // anthropic assistant turns can't have images\n contentBlocks.push({\n type: \"image\",\n source: {\n type: \"base64\",\n media_type: \"image/png\",\n data: await getNormalizedBase64PNG(file.url, file.mimeType),\n },\n });\n }\n contentBlocks.push({ type: \"text\", text: `Image (${file.url})` });\n } else if (file.data) {\n if (message.role == \"user\") {\n // anthropic assistant turns can't have images\n contentBlocks.push({\n type: \"image\",\n source: {\n type: \"base64\",\n media_type: file.mimeType as any,\n data: file.data,\n },\n });\n }\n }\n } else if (file.url) {\n // Non-image file with URL - add text reference\n contentBlocks.push({\n type: \"text\",\n text: `File (${file.url})`,\n });\n }\n }\n\n // Thinking blocks (if the caller echoes them) must lead an assistant turn,\n // before text; tool_use blocks come last. Only Anthropic's own block shapes\n // survive: a cross-provider fallback replays reasoningDetails captured from\n // another provider (e.g. OpenRouter `reasoning.text`), and Anthropic 400s\n // on the unknown input tag.\n const leadingBlocks: AnthropicContentBlock[] =\n message.role === \"assistant\" && Array.isArray(message.reasoningDetails)\n ? message.reasoningDetails.filter(\n (block: any) =>\n block?.type === \"thinking\" ||\n block?.type === \"redacted_thinking\",\n )\n : [];\n const toolUseBlocks: AnthropicContentBlock[] = (\n message.functionCalls || []\n ).map((fc, i) => ({\n type: \"tool_use\" as const,\n id: fc.id ?? `call_${i}`,\n name: fc.name,\n input: fc.arguments,\n }));\n\n preparedPayload.messages.push({\n role: message.role,\n content: [...leadingBlocks, ...contentBlocks, ...toolUseBlocks],\n });\n }\n\n return preparedPayload;\n}\n\nasync function callAnthropic(\n id: Identifier,\n payload: AnthropicAIPayload,\n config?: AnthropicAIConfig,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const anthropicMessages = jigAnthropicMessages(payload.messages);\n const tools = payload.functions?.map((f) => ({\n ...f,\n input_schema: f.parameters,\n parameters: undefined,\n }));\n\n let data;\n\n if (config?.service === \"bedrock\") {\n const AWS_REGION = \"us-east-1\";\n const MODEL_ID = \"anthropic.claude-3-haiku-20240307-v1:0\";\n\n const client = new BedrockRuntimeClient({ region: AWS_REGION });\n const bedrockPayload = {\n anthropic_version: \"bedrock-2023-05-31\",\n max_tokens: 4096,\n messages: anthropicMessages,\n tools,\n };\n\n const response = await client.send(\n new InvokeModelCommand({\n contentType: \"application/json\",\n body: JSON.stringify(bedrockPayload),\n modelId: MODEL_ID,\n }),\n { abortSignal: signal },\n );\n\n const decodedResponseBody = new TextDecoder().decode(response.body);\n data = JSON.parse(decodedResponseBody);\n } else {\n // Default: Anthropic API\n // Prompt caching: mark a breakpoint on the last tool only. Tool schemas\n // are fully static and identical across users, so that span gets real\n // cache reads; the system prompt is left uncached because callers embed\n // per-user / per-minute content in it, and a breakpoint after a volatile\n // span pays 1.25x cache writes with near-zero reads. Anthropic ignores\n // breakpoints below the model's minimum cacheable length, so small tool\n // sets are a safe no-op.\n const cachedTools = tools?.length\n ? [\n ...tools.slice(0, -1),\n { ...tools[tools.length - 1], cache_control: { type: \"ephemeral\" } },\n ]\n : tools;\n const response = await withRequestDeadline(\n \"Anthropic\",\n requestTimeoutMs,\n signal,\n (mergedSignal) =>\n axios.post(\n \"https://api.anthropic.com/v1/messages\",\n {\n model: payload.model,\n messages: anthropicMessages,\n tools: cachedTools,\n // tool_choice requires tools in the request; drop it otherwise.\n tool_choice: cachedTools?.length ? payload.tool_choice : undefined,\n temperature: payload.temperature,\n system: payload.system,\n max_tokens: 4096,\n },\n {\n headers: {\n \"content-type\": \"application/json\",\n \"x-api-key\": process.env.ANTHROPIC_API_KEY as string,\n \"anthropic-version\": \"2023-06-01\",\n \"anthropic-beta\": \"tools-2024-04-04\",\n },\n timeout: requestTimeoutMs,\n signal: mergedSignal,\n },\n ),\n );\n data = response.data;\n }\n\n const answers = data.content;\n if (!answers?.[0]) {\n logger.error(id, \"Missing answer in Anthropic API response:\", data);\n throw new Error(\"Missing answer in Anthropic API\");\n }\n\n let textResponse = \"\";\n const functionCalls: FunctionCall[] = [];\n // Native API thinking blocks (`{type:\"thinking\",thinking,signature}` /\n // `redacted_thinking`), kept raw so callers can echo them back verbatim —\n // their signatures are validated by Anthropic on the next turn.\n const reasoningBlocks: any[] = [];\n\n for (const answer of answers) {\n if (!answer.type) {\n logger.error(id, \"Missing answer type in Anthropic API response:\", data);\n throw new Error(\"Missing answer type in Anthropic API\");\n }\n\n if (answer.type === \"text\") {\n let text = answer.text\n .replace(/<thinking>.*?<\\/thinking>/gs, \"\")\n .replace(/<answer>|<\\/answer>/gs, \"\")\n .trim();\n\n if (!text) {\n text = answer.text.replace(\n /<thinking>|<\\/thinking>|<answer>|<\\/answer>/gs,\n \"\",\n );\n logger.log(id, \"No text in answer, returning text within tags:\", text);\n }\n\n textResponse = textResponse ? `${textResponse}\\n\\n${text}` : text;\n } else if (answer.type === \"tool_use\") {\n functionCalls.push({\n id: answer.id,\n name: answer.name,\n arguments: answer.input,\n });\n } else if (\n answer.type === \"thinking\" ||\n answer.type === \"redacted_thinking\"\n ) {\n reasoningBlocks.push(answer);\n }\n }\n\n if (!textResponse && !functionCalls.length) {\n logger.error(\n id,\n \"Missing text & functions in Anthropic API response:\",\n data,\n );\n throw new Error(\"Missing text & functions in Anthropic API response\");\n }\n\n // Anthropic's input_tokens EXCLUDES cache reads/writes; fold them back in\n // so prompt_tokens means \"all input tokens\" like OpenAI, where\n // cached_tokens is a subset of prompt_tokens.\n let usage: ParsedResponseMessage[\"usage\"] = null;\n if (data.usage) {\n const cacheRead = data.usage.cache_read_input_tokens ?? 0;\n const cacheWrite = data.usage.cache_creation_input_tokens ?? 0;\n const promptTokens = data.usage.input_tokens + cacheRead + cacheWrite;\n usage = {\n prompt_tokens: promptTokens,\n completion_tokens: data.usage.output_tokens,\n total_tokens: promptTokens + data.usage.output_tokens,\n cached_tokens: cacheRead,\n };\n }\n\n return {\n role: \"assistant\",\n content: textResponse,\n function_call: functionCalls[0] || null,\n function_calls: functionCalls,\n files: [],\n reasoningDetails: reasoningBlocks.length ? reasoningBlocks : undefined,\n usage,\n };\n}\n\nasync function callAnthropicWithRetries(\n id: Identifier,\n payload: AnthropicAIPayload,\n config?: AnthropicAIConfig,\n retries: number = 5,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n return withRetries(\n id,\n \"Anthropic\",\n () => callAnthropic(id, payload, config, requestTimeoutMs, signal),\n {\n retries,\n signal,\n },\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// GOOGLE AI\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction jigGoogleMessages(messages: GoogleAIMessage[]): GoogleAIMessage[] {\n const hasFunctionPart = (parts: GoogleAIPart[]) =>\n parts.some((p) => \"functionCall\" in p || \"functionResponse\" in p);\n\n let jiggedMessages = messages.slice();\n\n // Ensure first message is from user\n if (jiggedMessages[0]?.role === \"model\") {\n jiggedMessages = [\n { role: \"user\" as const, parts: [{ text: \"...\" }] },\n ...jiggedMessages,\n ];\n }\n\n // Group consecutive messages with the same role\n jiggedMessages = jiggedMessages.reduce((acc, message) => {\n if (acc.length === 0) return [message];\n\n const lastMessage = acc[acc.length - 1];\n if (lastMessage.role === message.role) {\n lastMessage.parts = [...lastMessage.parts, ...message.parts];\n return acc;\n }\n\n return [...acc, message];\n }, [] as GoogleAIMessage[]);\n\n // Ensure last message is from user — but don't append a placeholder after a\n // model turn that ends in a functionCall (it would orphan the call into\n // history and send \"...\" as the message).\n const last = jiggedMessages[jiggedMessages.length - 1];\n if (last?.role === \"model\" && !hasFunctionPart(last.parts)) {\n jiggedMessages.push({ role: \"user\", parts: [{ text: \"...\" }] });\n }\n\n return jiggedMessages;\n}\n\nasync function prepareGoogleAIPayload(\n _identifier: Identifier,\n payload: GenericPayload,\n): Promise<GoogleAIPayload> {\n const preparedPayload: GoogleAIPayload = {\n model: payload.model as GeminiModel,\n messages: [],\n tools: payload.functions\n ? {\n functionDeclarations: payload.functions.map((fn) => ({\n name: fn.name,\n parameters: {\n description: fn.description,\n ...fn.parameters,\n },\n })),\n }\n : undefined,\n // Map the generic function_call to Gemini's functionCallingConfig (\"none\"\n // → mode NONE forces a text-only turn). Only meaningful alongside tools.\n toolConfig:\n payload.functions && payload.function_call\n ? {\n functionCallingConfig: {\n mode:\n typeof payload.function_call === \"string\"\n ? payload.function_call === \"none\"\n ? \"NONE\"\n : \"AUTO\"\n : \"ANY\",\n },\n }\n : undefined,\n };\n\n // id -> tool name, to backfill functionResponse.name when a caller omits it.\n const toolNameById = new Map<string, string>();\n for (const m of payload.messages) {\n for (const fc of m.functionCalls || []) {\n if (fc.id) toolNameById.set(fc.id, fc.name);\n }\n }\n\n for (const message of payload.messages) {\n if (message.role === \"system\") {\n preparedPayload.systemInstruction = message.content;\n continue;\n }\n\n // role:\"tool\" → a user turn carrying functionResponse parts.\n if (message.role === \"tool\") {\n preparedPayload.messages.push({\n role: \"user\",\n parts: (message.toolResults || []).map((tr) => ({\n functionResponse: {\n id: tr.toolCallId,\n name: tr.name ?? toolNameById.get(tr.toolCallId) ?? \"\",\n response: { output: tr.content },\n },\n })),\n });\n continue;\n }\n\n const parts: GoogleAIPart[] = [];\n\n if (message.content) {\n parts.push({ text: message.content });\n }\n\n for (const file of message.files || []) {\n if (ALLOWED_IMAGE_MIME_TYPES.includes(file.mimeType)) {\n if (file.url) {\n parts.push({\n fileData: {\n mimeType: file.mimeType,\n fileUri: file.url,\n },\n });\n parts.push({ text: `Image (${file.url})` });\n } else if (file.data) {\n parts.push({\n inlineData: {\n mimeType: file.mimeType,\n data: file.data,\n },\n });\n }\n } else if (file.url) {\n // Non-image file with URL - add text reference\n parts.push({\n text: `File (${file.url})`,\n });\n }\n }\n\n for (const fc of message.functionCalls || []) {\n parts.push({\n functionCall: {\n id: fc.id,\n name: fc.name,\n args: fc.arguments,\n },\n // Gemini requires its thoughtSignature echoed back on the call part.\n ...(fc.thoughtSignature\n ? { thoughtSignature: fc.thoughtSignature }\n : {}),\n });\n }\n\n preparedPayload.messages.push({\n role: message.role === \"assistant\" ? \"model\" : message.role,\n parts,\n });\n }\n\n return preparedPayload;\n}\n\nasync function callGoogleAI(\n id: Identifier,\n payload: GoogleAIPayload,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const contents = jigGoogleMessages(payload.messages);\n\n // Call the REST generateContent endpoint directly rather than via @google/genai:\n // the pinned SDK (0.6.1) silently strips Gemini's per-call `thoughtSignature`,\n // which Gemini REQUIRES echoed back on multi-turn tool calls (a missing one\n // 400s the request). Going over the wire ourselves preserves it both ways.\n const requestBody: any = {\n contents,\n generationConfig: { responseModalities: [\"TEXT\"] },\n };\n if (payload.tools) requestBody.tools = [payload.tools];\n if (payload.tools && payload.toolConfig) {\n requestBody.toolConfig = payload.toolConfig;\n }\n if (payload.systemInstruction) {\n requestBody.systemInstruction = {\n parts: [{ text: payload.systemInstruction }],\n };\n }\n\n let response: any;\n try {\n const httpResponse = await withRequestDeadline(\n \"Google AI\",\n requestTimeoutMs,\n signal,\n (mergedSignal) =>\n axios.post(\n `https://generativelanguage.googleapis.com/v1beta/models/${payload.model}:generateContent`,\n requestBody,\n {\n headers: {\n \"content-type\": \"application/json\",\n \"x-goog-api-key\": process.env.GEMINI_API_KEY as string,\n },\n timeout: requestTimeoutMs,\n signal: mergedSignal,\n },\n ),\n );\n response = httpResponse.data;\n } catch (err: any) {\n // Re-shape the API error so callGoogleAIWithRetries' circuit breaker can read\n // message / status / promptFeedback off it.\n const apiError = err?.response?.data?.error;\n const wrapped = new Error(\n apiError?.message || err?.message || \"Google AI API request failed\",\n ) as any;\n wrapped.status = apiError?.status ?? err?.response?.status;\n wrapped.code = apiError?.code;\n wrapped.details = apiError?.details;\n wrapped.promptFeedback = err?.response?.data?.promptFeedback;\n throw wrapped;\n }\n\n let text = \"\";\n const files: File[] = [];\n const reasoningParts: any[] = [];\n // Built from content.parts (not response.functionCalls) so we can keep each\n // call's thoughtSignature, which the accessor drops. Gemini may omit ids —\n // synthesize positional ones so the caller can pair each with a\n // `ToolResult.toolCallId` next turn; the thoughtSignature MUST be echoed back\n // on round-trip (else Gemini 400s \"missing a thought_signature\").\n const functionCalls: FunctionCall[] = [];\n\n for (const part of response.candidates?.[0]?.content?.parts || []) {\n // Thinking parts (thought:true) carry chain-of-thought, not the answer.\n if ((part as any).thought) {\n reasoningParts.push(part);\n continue;\n }\n if (part.functionCall) {\n functionCalls.push({\n id: part.functionCall.id ?? `call_${functionCalls.length}`,\n name: part.functionCall.name ?? \"\",\n arguments: part.functionCall.args ?? {},\n thoughtSignature: (part as any).thoughtSignature,\n });\n continue;\n }\n if (part.text) text += part.text;\n if (part.inlineData?.data) {\n files.push({ mimeType: \"image/png\", data: part.inlineData.data });\n }\n }\n\n if (!text && !functionCalls.length && !files.length) {\n const candidate = response.candidates?.[0];\n const finishReason = candidate?.finishReason;\n\n logger.error(id, \"Missing text & functions in Google AI API response:\", {\n finishReason,\n safetyRatings: candidate?.safetyRatings,\n usageMetadata: response.usageMetadata,\n modelVersion: response.modelVersion,\n candidateContent: candidate?.content,\n promptFeedback: response.promptFeedback,\n });\n\n let errorMessage = \"Missing text & functions in Google AI API response\";\n if (finishReason) {\n const reasonDescriptions: Record<string, string> = {\n MALFORMED_FUNCTION_CALL:\n \"(Google could not generate valid function call arguments)\",\n SAFETY: \"(blocked by safety filters)\",\n RECITATION: \"(blocked due to recitation)\",\n MAX_TOKENS: \"(response truncated due to max tokens)\",\n };\n errorMessage += `: finishReason=${finishReason} ${reasonDescriptions[finishReason] || \"\"}`;\n }\n\n const error = new Error(errorMessage) as any;\n error.finishReason = finishReason;\n error.safetyRatings = candidate?.safetyRatings;\n error.usageMetadata = response.usageMetadata;\n error.promptFeedback = response.promptFeedback;\n throw error;\n }\n\n return {\n role: \"assistant\",\n content: text || null,\n files,\n function_call: functionCalls[0] || null,\n function_calls: functionCalls,\n reasoningDetails: reasoningParts.length ? reasoningParts : undefined,\n usage: response.usageMetadata\n ? {\n prompt_tokens: response.usageMetadata.promptTokenCount ?? 0,\n completion_tokens: response.usageMetadata.candidatesTokenCount ?? 0,\n total_tokens: response.usageMetadata.totalTokenCount ?? 0,\n cached_tokens: response.usageMetadata.cachedContentTokenCount ?? 0,\n }\n : null,\n };\n}\n\n/**\n * Content violation finish reasons that should trigger circuit breaker behavior.\n * These errors won't resolve with simple retries - the content itself is the problem.\n */\nconst CONTENT_VIOLATION_REASONS = new Set([\"PROHIBITED_CONTENT\", \"SAFETY\"]);\n\n/**\n * Removes inline image data from Google AI messages, preserving text content.\n * Used as a fallback when content violations are detected.\n */\nfunction removeImagesFromGooglePayload(payload: GoogleAIPayload): boolean {\n let removedImages = false;\n\n for (const message of payload.messages) {\n message.parts = message.parts.filter((part) => {\n if (\"inlineData\" in part || \"fileData\" in part) {\n removedImages = true;\n return false;\n }\n return true;\n });\n\n // Ensure message still has content after removing images\n if (message.parts.length === 0) {\n message.parts = [{ text: \"(image removed due to content policy)\" }];\n }\n }\n\n return removedImages;\n}\n\nasync function callGoogleAIWithRetries(\n id: Identifier,\n payload: GoogleAIPayload,\n retries: number = 5,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n let hasTriedWithoutImages = false;\n\n return withRetries(id, \"Google AI\", () => callGoogleAI(id, payload, requestTimeoutMs, signal), {\n retries,\n signal,\n onError: (error, attempt) => {\n const errorDetails: Record<string, any> = {\n message: error.message,\n finishReason: error.finishReason,\n modelVersion: error.modelVersion,\n };\n\n if (error.safetyRatings) errorDetails.safetyRatings = error.safetyRatings;\n if (error.usageMetadata) errorDetails.usageMetadata = error.usageMetadata;\n if (error.promptFeedback)\n errorDetails.promptFeedback = error.promptFeedback;\n if (error.status) errorDetails.httpStatus = error.status;\n if (error.code) errorDetails.errorCode = error.code;\n if (error.details) errorDetails.errorDetails = error.details;\n\n const fileUris = payload.messages\n .flatMap((m) => m.parts)\n .filter((p) => \"fileData\" in p)\n .map((p) => (p as any).fileData.fileUri);\n if (fileUris.length) errorDetails.fileUris = fileUris;\n\n logger.error(\n id,\n `Retry #${attempt} error: ${error.message}`,\n errorDetails,\n );\n\n // Circuit breaker: Google's fetcher couldn't pull our image URL(s). We pass\n // images as fileData.fileUri, but arbitrary (non-Files-API) URLs are only\n // best-effort for Gemini, so this 400 is episodic and retrying the same URL\n // almost never recovers within a request. Fail fast so the caller's\n // fallbackModel (whose adapter inlines the image bytes) takes over instead of\n // burning all retries first. Unlike the content-violation path we do NOT strip\n // images — the fallback model should still see them.\n if (\n typeof error?.message === \"string\" &&\n error.message.includes(\"Cannot fetch content from the provided URL\")\n ) {\n logger.error(\n id,\n \"Circuit breaker: Google could not fetch image URL(s); failing over (no more Google retries)\",\n );\n const fetchError = new Error(\n \"Google AI could not fetch the provided image URL(s).\",\n ) as any;\n fetchError.cause = error;\n fetchError.googleFetchFailure = true;\n throw fetchError;\n }\n\n // Circuit breaker: detect content violations and try removing images\n // Check both finishReason (candidate-level) and promptFeedback.blockReason (prompt-level)\n const violationReason =\n (CONTENT_VIOLATION_REASONS.has(error.finishReason) &&\n error.finishReason) ||\n (CONTENT_VIOLATION_REASONS.has(error.promptFeedback?.blockReason) &&\n error.promptFeedback?.blockReason);\n\n if (violationReason) {\n if (!hasTriedWithoutImages) {\n const removedImages = removeImagesFromGooglePayload(payload);\n if (removedImages) {\n logger.log(\n id,\n `Circuit breaker triggered: removing images due to ${violationReason}`,\n );\n hasTriedWithoutImages = true;\n return; // Continue to next retry with images removed\n }\n }\n\n // If we already tried without images or there were no images, fail fast\n logger.error(\n id,\n `Circuit breaker: failing fast due to ${violationReason} (no more fallbacks)`,\n );\n const circuitBreakerError = new Error(\n `Google AI content violation: ${violationReason}. Request cannot succeed with current content.`,\n ) as any;\n circuitBreakerError.finishReason = error.finishReason;\n circuitBreakerError.safetyRatings = error.safetyRatings;\n circuitBreakerError.usageMetadata = error.usageMetadata;\n circuitBreakerError.circuitBreaker = true;\n throw circuitBreakerError;\n }\n },\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// GROQ\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction normalizeMessageContent(\n content: AnthropicAIMessage[\"content\"],\n): string {\n return Array.isArray(content)\n ? content\n .map((c) => (c.type === \"text\" ? c.text : `[${c.type}]`))\n .join(\"\\n\")\n : content;\n}\n\n/**\n * Serialize generic messages for OpenAI-compatible chat APIs (Groq, OpenRouter).\n * Mirrors the OpenAI adapter but keeps content as a plain string. Tool calls\n * become assistant `tool_calls`, and a `role:\"tool\"` message expands to one\n * `{role:\"tool\", tool_call_id, content}` per result. Reasoning is passed\n * through only when the caller supplied it.\n */\nfunction prepareOpenAICompatMessages(\n messages: GenericMessage[],\n): OpenAIMessage[] {\n const out: OpenAIMessage[] = [];\n for (const message of messages) {\n if (message.role === \"tool\") {\n for (const tr of message.toolResults || []) {\n out.push({\n role: \"tool\",\n tool_call_id: tr.toolCallId,\n content: tr.content,\n });\n }\n continue;\n }\n\n // Content stays a plain string on this path, so attachments become URL\n // references appended to it — images included, since the models behind\n // OpenRouter/Groq are text-only here and would otherwise never learn a\n // file exists.\n const fileRefs = (message.files || [])\n .filter((file) => file.url)\n .map((file) =>\n ALLOWED_IMAGE_MIME_TYPES.includes(file.mimeType)\n ? `Image (${file.url})`\n : `File (${file.url})`,\n );\n const content = [normalizeMessageContent(message.content), ...fileRefs]\n .filter(Boolean)\n .join(\"\\n\");\n\n const outMessage: OpenAIMessage = {\n role: message.role,\n content,\n };\n if (message.functionCalls?.length) {\n outMessage.tool_calls = message.functionCalls.map((fc, i) => ({\n id: fc.id ?? `call_${i}`,\n type: \"function\" as const,\n function: {\n name: fc.name,\n arguments: JSON.stringify(fc.arguments),\n },\n }));\n // OpenAI-compatible APIs want null content on a tool-call-only turn.\n if (!content) outMessage.content = null;\n }\n if (message.reasoning) outMessage.reasoning = message.reasoning;\n const reasoningDetails = filterOpenAICompatReasoningDetails(\n message.reasoningDetails,\n );\n if (reasoningDetails) outMessage.reasoning_details = reasoningDetails;\n out.push(outMessage);\n }\n return out;\n}\n\nfunction prepareGroqPayload(payload: GenericPayload): GroqPayload {\n return {\n model: payload.model as GroqModel,\n messages: prepareOpenAICompatMessages(payload.messages),\n tools: payload.functions?.map((fn) => ({\n type: \"function\",\n function: fn,\n })),\n tool_choice: payload.function_call\n ? typeof payload.function_call === \"string\"\n ? payload.function_call\n : { type: \"function\", function: payload.function_call }\n : undefined,\n temperature: payload.temperature,\n };\n}\n\nasync function callGroq(\n id: Identifier,\n payload: GroqPayload,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const response = await withRequestDeadline(\n \"Groq\",\n requestTimeoutMs,\n signal,\n (mergedSignal) =>\n axios.post(\n \"https://api.groq.com/openai/v1/chat/completions\",\n payload,\n {\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${process.env.GROQ_API_KEY}`,\n },\n timeout: requestTimeoutMs,\n signal: mergedSignal,\n },\n ),\n );\n\n // Like OpenRouter, Groq can return an error-shaped HTTP 200 with no `choices`\n // key; surface it instead of throwing a cryptic `choices[0]` TypeError.\n if (response.data.error) {\n logger.error(id, \"Groq error:\", response.data.error);\n throw new Error(`Groq error: ${response.data.error.message}`);\n }\n\n const answer = response.data.choices?.[0]?.message;\n if (!answer) {\n logger.error(id, \"Missing answer in Groq API response:\", response.data);\n throw new Error(\"Missing answer in Groq API\");\n }\n\n const functionCalls: FunctionCall[] = [];\n if (answer.tool_calls?.length) {\n for (let i = 0; i < answer.tool_calls.length; i++) {\n const tc = answer.tool_calls[i];\n functionCalls.push({\n id: tc.id ?? `call_${i}`,\n name: tc.function.name,\n arguments: JSON.parse(tc.function.arguments),\n });\n }\n }\n\n // An empty 200 (no content, no tool call) is not a usable answer — throw so\n // withRetries retries and callWithRetries can fall back. (Mirrors the\n // streaming path's guard in parseStreamedResponse.)\n if (!answer.content && !functionCalls.length) {\n logger.error(\n id,\n \"Groq: received message without content or function_call:\",\n JSON.stringify(response.data),\n );\n throw new Error(\n \"Groq: received message without content or function_call\",\n );\n }\n\n return {\n role: \"assistant\",\n content: answer.content || null,\n function_call: functionCalls[0] || null,\n function_calls: functionCalls,\n files: [],\n reasoning: answer.reasoning ?? undefined,\n usage: response.data.usage\n ? {\n prompt_tokens: response.data.usage.prompt_tokens,\n completion_tokens: response.data.usage.completion_tokens,\n total_tokens: response.data.usage.total_tokens,\n cached_tokens:\n response.data.usage.prompt_tokens_details?.cached_tokens ?? 0,\n }\n : null,\n };\n}\n\nasync function callGroqWithRetries(\n id: Identifier,\n payload: GroqPayload,\n retries: number = 5,\n requestTimeoutMs: number = 120_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n return withRetries(id, \"Groq\", () => callGroq(id, payload, requestTimeoutMs, signal), {\n retries,\n signal,\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// OPENROUTER\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction prepareOpenRouterPayload(payload: GenericPayload): OpenRouterPayload {\n return {\n model: payload.model as OpenRouterModel,\n messages: prepareOpenAICompatMessages(payload.messages),\n tools: payload.functions?.map((fn) => ({\n type: \"function\",\n function: fn,\n })),\n tool_choice: payload.function_call\n ? typeof payload.function_call === \"string\"\n ? payload.function_call\n : { type: \"function\", function: payload.function_call }\n : undefined,\n temperature: payload.temperature,\n provider: payload.provider,\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// DeepSeek \"DSML\" tool-call recovery\n// ─────────────────────────────────────────────────────────────────────────────\n// DeepSeek models (e.g. deepseek-v4-flash) on OpenRouter intermittently emit\n// their native tool-call markup as plain assistant *content* instead of\n// populating the response's `tool_calls`. The markup (\"DSML\") looks like:\n//\n// <|DSML|tool_calls>\n// <|DSML|invoke name=\"use_skills\">\n// <|DSML|parameter name=\"skills\" string=\"false\">[\"search\"]</|DSML|parameter>\n// </|DSML|invoke>\n// </|DSML|tool_calls>\n//\n// with either one or two fullwidth vertical bars (| = U+FF5C) around DSML. The\n// `string` attribute says whether the value is a literal string (\"true\") or a\n// JSON value to parse (\"false\"). We recover these into structured FunctionCalls\n// so the turn executes normally instead of leaking raw markup to the caller.\n//\n// Regex tags use `|+` (one-or-more fullwidth vertical bars) so the single-\n// and double-bar variants both match.\nconst DSML_ENVELOPE_RE = /<|+DSML|+tool_calls>/;\nconst DSML_DELIMITER_RE = /<\\/?|+DSML|+/;\nconst DSML_INVOKE_RE =\n /<|+DSML|+invoke\\s+name=\"([^\"]+)\"\\s*>([\\s\\S]*?)<\\/|+DSML|+invoke>/g;\nconst DSML_PARAM_RE =\n /<|+DSML|+parameter\\s+name=\"([^\"]+)\"(?:\\s+string=\"(true|false)\")?\\s*>([\\s\\S]*?)<\\/|+DSML|+parameter>/g;\n// Any DSML tag (open or close), used to excise the whole markup span from\n// surrounding prose once the calls have been extracted.\nconst DSML_ANY_TAG_RE = /<\\/?|+DSML|+[^>]*>/g;\n\nfunction parseDsmlToolCalls(content: string): {\n calls: FunctionCall[];\n remainingContent: string | null;\n} {\n const calls: FunctionCall[] = [];\n\n DSML_INVOKE_RE.lastIndex = 0;\n let invokeMatch: RegExpExecArray | null;\n while ((invokeMatch = DSML_INVOKE_RE.exec(content)) !== null) {\n const name = invokeMatch[1];\n const inner = invokeMatch[2];\n const args: Record<string, any> = {};\n let ok = true;\n\n DSML_PARAM_RE.lastIndex = 0;\n let paramMatch: RegExpExecArray | null;\n while ((paramMatch = DSML_PARAM_RE.exec(inner)) !== null) {\n const [, paramName, stringAttr, rawValue] = paramMatch;\n if (stringAttr === \"false\") {\n // value is a JSON literal (array / number / object / bool / quoted string)\n try {\n args[paramName] = JSON.parse(rawValue);\n } catch {\n ok = false; // malformed typed arg → don't emit a wrong-typed call\n break;\n }\n } else {\n // string=\"true\" (or attribute absent) → literal string value\n args[paramName] = rawValue;\n }\n }\n\n if (ok && name) {\n calls.push({ id: `call_${calls.length}`, name, arguments: args });\n }\n }\n\n if (!calls.length) {\n return { calls, remainingContent: content };\n }\n\n // Excise the whole DSML span (first tag through last tag, including the\n // already-captured parameter values between them) so any surrounding prose\n // survives but the raw markup never reaches the caller.\n DSML_ANY_TAG_RE.lastIndex = 0;\n let first = -1;\n let last = -1;\n let tag: RegExpExecArray | null;\n while ((tag = DSML_ANY_TAG_RE.exec(content)) !== null) {\n if (first === -1) first = tag.index;\n last = tag.index + tag[0].length;\n }\n const remaining =\n first === -1\n ? content\n : (content.slice(0, first) + content.slice(last)).trim();\n return { calls, remainingContent: remaining.length ? remaining : null };\n}\n\n// Independent timeout budgets for the two OpenRouter transports. Streaming is\n// bounded by elapsed total + a per-useful-chunk stall timeout, so it can afford\n// a generous total: a healthy long generation keeps producing useful chunks,\n// while a hung one dies within one stall window. Non-streaming has no\n// progress signal at all, so its total must stay tight.\nexport const OPENROUTER_STREAM_TIMEOUT_MS = 600_000;\nexport const OPENROUTER_NONSTREAM_TIMEOUT_MS = 180_000;\n\nfunction openRouterEndpoint(): string {\n // Override point for tests (deadline/stream behavior needs a local server).\n return `${process.env.OPENROUTER_BASE_URL || \"https://openrouter.ai\"}/api/v1/chat/completions`;\n}\n\n/**\n * Shared tail of both OpenRouter transports: assemble the ParsedResponseMessage\n * from the raw pieces, recover DSML tool calls, and reject unusable (empty /\n * truncated-markup) completions so withRetries retries and callWithRetries can\n * fall back.\n */\nfunction finalizeOpenRouterMessage(\n id: Identifier,\n raw: {\n content: string | null;\n toolCalls: { id?: string; name: string; argumentsJson: string }[];\n reasoning?: string;\n reasoningDetails?: any;\n provider?: string;\n usage?: {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n prompt_tokens_details?: { cached_tokens?: number };\n } | null;\n /** Whole response (or a summary of the stream) for the failure log. */\n forLog: () => string;\n },\n): ParsedResponseMessage {\n const functionCalls: FunctionCall[] = [];\n for (let i = 0; i < raw.toolCalls.length; i++) {\n const tc = raw.toolCalls[i];\n if (!tc.name) continue;\n functionCalls.push({\n id: tc.id ?? `call_${i}`,\n name: tc.name,\n // Streamed no-arg calls can close with an empty fragment; treat as {}.\n arguments: tc.argumentsJson.trim() ? JSON.parse(tc.argumentsJson) : {},\n });\n }\n\n // DeepSeek sometimes emits its native \"DSML\" tool-call markup as plain content\n // instead of populating tool_calls. Recover it into structured calls so the\n // turn executes normally instead of leaking raw markup to the caller.\n let content = raw.content;\n if (!functionCalls.length && content && DSML_ENVELOPE_RE.test(content)) {\n const { calls, remainingContent } = parseDsmlToolCalls(content);\n if (calls.length) {\n functionCalls.push(...calls);\n content = remainingContent;\n }\n }\n\n // Not a usable answer — an empty completion (reasoning models e.g. deepseek\n // can route all output to the discarded `reasoning` channel), OR a DSML\n // envelope we couldn't parse into a call (truncated/malformed). Throw so\n // withRetries retries this model and, on exhaustion, callWithRetries falls\n // back to fallbackModel.\n const hasUnparsedDsml = !!content && DSML_DELIMITER_RE.test(content);\n if (!functionCalls.length && (!content || hasUnparsedDsml)) {\n logger.error(id, \"OpenRouter: empty or unparseable completion:\", raw.forLog());\n throw new Error(\n \"OpenRouter: received message without usable content or function_call\",\n );\n }\n\n return {\n role: \"assistant\",\n content: content || null,\n function_call: functionCalls[0] || null,\n function_calls: functionCalls,\n files: [],\n reasoning: raw.reasoning || undefined,\n reasoningDetails: raw.reasoningDetails ?? undefined,\n // The upstream provider OpenRouter routed to (e.g. \"Baidu\") — finer-grained\n // than the \"openrouter\" stamp callWithRetries would apply.\n provider: raw.provider ?? undefined,\n usage: raw.usage\n ? {\n prompt_tokens: raw.usage.prompt_tokens,\n completion_tokens: raw.usage.completion_tokens,\n total_tokens: raw.usage.total_tokens,\n cached_tokens: raw.usage.prompt_tokens_details?.cached_tokens ?? 0,\n }\n : null,\n };\n}\n\n/**\n * Streaming transport (the default). Two timers, both required:\n *\n * - `streamTimeoutMs` bounds the whole attempt (connect + generation). It is\n * deliberately independent of the non-streaming `requestTimeoutMs`: with a\n * progress signal available, a long healthy generation shouldn't be killed\n * by a deadline sized for opaque requests (2026-07-27: 9–12k-token deepseek\n * completions at healthy tps were being executed at the 120s hard deadline\n * just before finishing, then retried from scratch).\n * - `chunkTimeoutMs` is a stall detector: it resets ONLY on a \"useful\" chunk —\n * one advancing content, reasoning, reasoning_details, tool-call fragments,\n * finish_reason, or usage. SSE comments (OpenRouter dribbles\n * \": OPENROUTER PROCESSING\" as keep-alive), role-only deltas, and other\n * heartbeat noise do NOT reset it, so a provider that keeps the socket warm\n * while generating nothing dies within one window instead of holding the\n * turn to the total deadline. The window also covers connect + time to first\n * token.\n */\nasync function callOpenRouterStream(\n id: Identifier,\n payload: OpenRouterPayload,\n streamTimeoutMs: number = OPENROUTER_STREAM_TIMEOUT_MS,\n chunkTimeoutMs: number = 15_000,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const controller = new AbortController();\n // Why the reason is tracked out-of-band: fetch/reader surface any abort as a\n // bare AbortError, so without this the retry log would say \"This operation\n // was aborted\" no matter which timer fired.\n let abortReason: string | null = null;\n // Which timer fired: a deadline abort can still yield a usable (truncated)\n // answer, a stall abort by definition cannot.\n let abortKind: \"deadline\" | \"stall\" | null = null;\n const abortWith = (kind: \"deadline\" | \"stall\", reason: string) => {\n abortKind = kind;\n abortReason = reason;\n controller.abort();\n };\n\n const unref = (t: ReturnType<typeof setTimeout>) => {\n if (typeof t === \"object\" && \"unref\" in t) t.unref();\n return t;\n };\n const totalTimer = unref(\n setTimeout(\n () =>\n abortWith(\n \"deadline\",\n `OpenRouter stream exceeded total deadline of ${streamTimeoutMs}ms`,\n ),\n streamTimeoutMs,\n ),\n );\n let stallTimer: ReturnType<typeof setTimeout> | undefined;\n const armStallTimer = () => {\n clearTimeout(stallTimer);\n stallTimer = unref(\n setTimeout(\n () =>\n abortWith(\n \"stall\",\n `OpenRouter stream stalled: no useful chunk for ${chunkTimeoutMs}ms`,\n ),\n chunkTimeoutMs,\n ),\n );\n };\n\n let paragraph = \"\";\n let reasoning = \"\";\n const reasoningDetails: any[] = [];\n const toolCalls: { id?: string; name: string; argumentsJson: string }[] = [];\n let provider: string | undefined;\n let usage: any = null;\n let finishReason: string | null = null;\n let sawDone = false;\n let dataChunks = 0;\n\n try {\n armStallTimer(); // covers connect + time to first token\n const response = await fetch(openRouterEndpoint(), {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,\n },\n body: JSON.stringify({ ...payload, stream: true, usage: { include: true } }),\n signal: signal ? anySignal([controller.signal, signal]) : controller.signal,\n });\n\n if (!response.ok) {\n let data: any;\n try {\n data = await response.json();\n } catch {\n data = undefined;\n }\n logger.error(id, `OpenRouter stream HTTP ${response.status}:`, data);\n const error = new Error(\n `OpenRouter error: ${data?.error?.message || `HTTP ${response.status}`}`,\n ) as any;\n error.response = { status: response.status, data };\n throw error;\n }\n // Some responses to a streamed request arrive as a plain JSON body anyway\n // (error-in-200 payloads, proxies/providers that ignore `stream`). Parse\n // those as a non-streaming body instead of scanning them for SSE lines.\n if (response.headers.get(\"content-type\")?.includes(\"application/json\")) {\n return parseOpenRouterBody(id, await response.json());\n }\n if (!response.body) {\n throw new Error(\"OpenRouter stream error: no response body\");\n }\n\n const reader = response.body.getReader();\n // One decoder in stream mode for the whole body: multi-byte UTF-8\n // sequences (CJK output!) split across TCP chunks must not be decoded\n // per-chunk or they turn into replacement characters.\n const decoder = new TextDecoder();\n let lineBuffer = \"\";\n\n outer: while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n lineBuffer += decoder.decode(value, { stream: true });\n\n let newlineIdx: number;\n while ((newlineIdx = lineBuffer.indexOf(\"\\n\")) !== -1) {\n let line = lineBuffer.slice(0, newlineIdx);\n lineBuffer = lineBuffer.slice(newlineIdx + 1);\n if (line.endsWith(\"\\r\")) line = line.slice(0, -1);\n if (!line) continue; // SSE event separator\n if (line.startsWith(\":\")) continue; // SSE comment — keep-alive, NOT useful\n if (!line.startsWith(\"data:\")) continue; // ignore event:/id:/retry: fields\n const dataStr = line.slice(5).trimStart();\n if (dataStr === \"[DONE]\") {\n sawDone = true;\n break outer;\n }\n\n let json: any;\n try {\n json = JSON.parse(dataStr);\n } catch {\n // SSE frames one complete JSON object per data line and the line\n // buffer already reassembles split TCP chunks, so this is a\n // malformed event, not a partial one — skip it rather than corrupt\n // the accumulation.\n logger.error(\n id,\n \"OpenRouter stream: unparseable data line:\",\n dataStr.slice(0, 200),\n );\n continue;\n }\n dataChunks++;\n\n // Same error-in-200 wrapping as the non-streaming body, delivered as\n // an SSE event (rate limits, moderation, provider failures).\n if (json.error) {\n logger.error(id, \"OpenRouter stream error event:\", json.error);\n const error = new Error(\n `OpenRouter error: ${json.error.message}`,\n ) as any;\n error.data = json.error;\n throw error;\n }\n\n if (json.provider) provider = json.provider;\n let useful = false;\n if (json.usage) {\n usage = json.usage;\n useful = true;\n }\n const choice = json.choices?.[0];\n if (choice) {\n const delta = choice.delta ?? {};\n if (delta.content) {\n paragraph += delta.content;\n useful = true;\n }\n if (delta.reasoning) {\n reasoning += delta.reasoning;\n useful = true;\n }\n if (Array.isArray(delta.reasoning_details) && delta.reasoning_details.length) {\n reasoningDetails.push(...delta.reasoning_details);\n useful = true;\n }\n if (Array.isArray(delta.tool_calls)) {\n for (const toolCall of delta.tool_calls) {\n const idx = toolCall.index ?? 0;\n while (toolCalls.length <= idx) {\n toolCalls.push({ name: \"\", argumentsJson: \"\" });\n }\n if (toolCall.id) toolCalls[idx].id = toolCall.id;\n if (toolCall.function?.name)\n toolCalls[idx].name += toolCall.function.name;\n if (toolCall.function?.arguments)\n toolCalls[idx].argumentsJson += toolCall.function.arguments;\n useful = true;\n }\n }\n if (choice.finish_reason) {\n finishReason = choice.finish_reason;\n useful = true;\n }\n }\n if (useful) armStallTimer();\n }\n }\n\n // After [DONE] the server should close, but don't rely on it — release the\n // socket instead of holding it until GC.\n if (sawDone) reader.cancel().catch(() => {});\n\n // A clean close without [DONE] is acceptable only when the provider said\n // it finished; otherwise the connection died mid-generation and returning\n // the partial accumulation would present a truncated answer as complete.\n if (!sawDone && !finishReason) {\n logger.error(\n id,\n `OpenRouter stream ended prematurely after ${dataChunks} data chunks`,\n );\n throw new Error(\"OpenRouter stream error: ended prematurely\");\n }\n\n return finalizeOpenRouterMessage(id, {\n content: paragraph || null,\n toolCalls,\n reasoning,\n reasoningDetails: reasoningDetails.length ? reasoningDetails : undefined,\n provider,\n usage,\n forLog: () =>\n JSON.stringify({\n finishReason,\n provider,\n usage,\n paragraph: paragraph.slice(0, 500),\n reasoningChars: reasoning.length,\n toolCalls,\n }),\n });\n } catch (error: any) {\n // Restore the real reason: fetch/reader surface our timer aborts as bare\n // AbortErrors. Caller-signal aborts pass through untouched so\n // withRetries/callWithRetries see signal.aborted and bail.\n if (abortReason && !signal?.aborted) {\n // Deadline abort with usable prose in hand: return it truncated rather\n // than discard tokens the provider already generated (and billed) and\n // retry from zero. Tool calls are excluded — a half-streamed arguments\n // fragment is unparseable JSON, so there's nothing to salvage.\n const kept = paragraph.trim();\n if (abortKind === \"deadline\" && kept && !toolCalls.length) {\n try {\n const message = finalizeOpenRouterMessage(id, {\n content: kept,\n toolCalls: [],\n reasoning,\n reasoningDetails: reasoningDetails.length\n ? reasoningDetails\n : undefined,\n provider,\n usage,\n forLog: () => JSON.stringify({ provider, kept: kept.slice(0, 500) }),\n });\n message.truncated = true;\n logger.log(\n id,\n `${abortReason} — returning truncated answer (${kept.length} chars, ~${estimateTokens(kept)} tokens kept)`,\n );\n return message;\n } catch {\n // Unusable partial (empty after DSML excision, unparsed markup) —\n // fall through to the discard path below.\n }\n }\n // Nothing salvageable: say how much generation is being thrown away, so\n // wasted spend is visible (aborted attempts write no usage record —\n // OpenRouter only sends `usage` in the final chunk we never receive).\n logger.error(\n id,\n `${abortReason} — discarding ~${estimateTokens(paragraph + reasoning)} generated tokens (content ${paragraph.length} chars, reasoning ${reasoning.length} chars, ${dataChunks} chunks)`,\n );\n throw new Error(abortReason);\n }\n throw error;\n } finally {\n clearTimeout(totalTimer);\n clearTimeout(stallTimer);\n }\n}\n\n/** Parse a complete (non-streamed) OpenRouter response body. */\nfunction parseOpenRouterBody(id: Identifier, data: any): ParsedResponseMessage {\n // OpenRouter wraps upstream provider failures (rate limits, moderation,\n // model-unavailable) in an HTTP 200 whose body is `{ error: {...} }` with no\n // `choices` key. Surface that error instead of letting `choices[0]` throw a\n // cryptic \"Cannot read properties of undefined (reading '0')\" TypeError that\n // hides the real reason. (Mirrors the OpenAI non-streaming guard above.)\n if (data.error) {\n logger.error(id, \"OpenRouter error:\", data.error);\n const error = new Error(`OpenRouter error: ${data.error.message}`) as any;\n // Carry the raw error body (as the stream path does) so the retry loop can\n // classify it — moderation eviction needs code/metadata, not just message.\n error.data = data.error;\n throw error;\n }\n\n const answer = data.choices?.[0]?.message;\n if (!answer) {\n logger.error(id, \"Missing answer in OpenRouter API response:\", data);\n throw new Error(\"Missing answer in OpenRouter API\");\n }\n\n return finalizeOpenRouterMessage(id, {\n content: answer.content ?? null,\n toolCalls: (answer.tool_calls ?? []).map((tc: any) => ({\n id: tc.id,\n name: tc.function.name,\n argumentsJson: tc.function.arguments,\n })),\n reasoning: answer.reasoning ?? undefined,\n reasoningDetails: answer.reasoning_details ?? undefined,\n provider: data.provider ?? undefined,\n usage: data.usage ?? null,\n forLog: () => JSON.stringify(data),\n });\n}\n\n/** Non-streaming transport — kept for callers that set `streaming: false`. */\nasync function callOpenRouterNonStreaming(\n id: Identifier,\n payload: OpenRouterPayload,\n requestTimeoutMs: number = OPENROUTER_NONSTREAM_TIMEOUT_MS,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const response = await withRequestDeadline(\n \"OpenRouter\",\n requestTimeoutMs,\n signal,\n (mergedSignal) =>\n axios.post(openRouterEndpoint(), payload, {\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,\n },\n timeout: requestTimeoutMs,\n signal: mergedSignal,\n }),\n );\n\n return parseOpenRouterBody(id, response.data);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Moderation eviction\n// ─────────────────────────────────────────────────────────────────────────────\n// A provider's content-moderation rejection (\"Upstream error from Alibaba:\n// Output data may contain inappropriate content.\") is deterministic for a\n// given payload — re-rolling the same provider burns the whole retry budget\n// for nothing (observed 2026-07-27: 5 identical rejections per turn, ~20-25s\n// of user-visible stall, before fallbackModel saved the turn). On the FIRST\n// moderation-classified error, evict the refusing provider from the request's\n// provider preferences (ignore += provider, order -= provider) so every\n// remaining attempt reroutes; OpenRouter's next-ranked provider answers\n// instead. Non-moderation errors keep plain retry semantics.\n\n/** \"AtlasCloud\" / \"atlas-cloud/fp4\" / \"Atlas Cloud\" → \"atlascloud\" */\nconst normalizeProviderKey = (name: string) =>\n name.split(\"/\")[0].toLowerCase().replace(/[^a-z0-9]/g, \"\");\n\nconst MODERATION_RE =\n /moderat|inappropriate content|content polic|content management|flagged/i;\n\n/**\n * If `error` is a provider content-moderation rejection, return the refusing\n * provider's slug (in the payload's own `order` spelling when possible, since\n * OpenRouter's `ignore` wants slugs, not the display name error metadata\n * carries). Null for everything else.\n */\nfunction moderationEvictionSlug(\n error: any,\n payload: OpenRouterPayload,\n): string | null {\n const body = error?.data ?? error?.response?.data?.error;\n if (!body) return null;\n const message = String(body.message ?? \"\");\n const isModeration =\n body.code === 403 ||\n Array.isArray(body.metadata?.reasons) ||\n MODERATION_RE.test(message);\n if (!isModeration) return null;\n\n const display: string | undefined =\n body.metadata?.provider_name ??\n /Upstream error from ([^:]+):/.exec(message)?.[1];\n if (!display) return null;\n\n const key = normalizeProviderKey(display);\n const fromOrder = payload.provider?.order?.find(\n (entry) => normalizeProviderKey(entry) === key,\n );\n // Best effort when the provider wasn't in our order (OpenRouter default\n // routing): lowercased display name matches the slug for single-word\n // providers (alibaba, novita, baidu), which covers the observed cases.\n return fromOrder ? fromOrder.split(\"/\")[0] : display.toLowerCase();\n}\n\n/**\n * Least time a streaming attempt is worth starting with. Below this the\n * generation cannot plausibly finish before the caller's deadline, so burning\n * a provider call (and paying for tokens that get discarded) is pure waste.\n */\nexport const MIN_STREAM_ATTEMPT_MS = 10_000;\n\n/**\n * Rough token count for discard/truncation accounting only (~4 chars/token).\n * Aborted attempts never receive OpenRouter's `usage` chunk, so this is the\n * only signal for how much generation was paid for and thrown away.\n */\nconst estimateTokens = (text: string) => Math.round(text.length / 4);\n\ninterface OpenRouterCallOptions {\n streaming: boolean;\n streamTimeoutMs: number;\n streamDeadlineAt?: number;\n requestTimeoutMs: number;\n chunkTimeoutMs: number;\n}\n\n/**\n * Per-attempt streaming budget: the smaller of the per-attempt cap and the\n * time left until the caller's absolute deadline. Returns null when too little\n * remains to be worth an attempt.\n */\nfunction streamAttemptBudgetMs(options: OpenRouterCallOptions): number | null {\n if (options.streamDeadlineAt === undefined) return options.streamTimeoutMs;\n const remaining = options.streamDeadlineAt - Date.now();\n if (remaining < MIN_STREAM_ATTEMPT_MS) return null;\n return Math.min(options.streamTimeoutMs, remaining);\n}\n\nasync function callOpenRouterWithRetries(\n id: Identifier,\n payload: OpenRouterPayload,\n retries: number = 5,\n options: OpenRouterCallOptions,\n signal?: AbortSignal,\n): Promise<ParsedResponseMessage> {\n const evicted: string[] = [];\n return withRetries(\n id,\n \"OpenRouter\",\n () =>\n (options.streaming\n ? (() => {\n const budget = streamAttemptBudgetMs(options);\n if (budget === null) {\n // Fail fast rather than start a doomed generation. Thrown (not\n // returned) so fallbackModel still gets its chance — a cheaper\n // model may answer in the time that's left.\n const error = new Error(\n \"OpenRouter stream skipped: caller deadline leaves too little time for another attempt\",\n ) as any;\n error.deadlineExceeded = true;\n logger.error(id, error.message);\n throw error;\n }\n return callOpenRouterStream(\n id,\n payload,\n budget,\n options.chunkTimeoutMs,\n signal,\n );\n })()\n : callOpenRouterNonStreaming(\n id,\n payload,\n options.requestTimeoutMs,\n signal,\n )\n ).catch((error) => {\n const slug = moderationEvictionSlug(error, payload);\n if (slug && !evicted.includes(slug)) {\n evicted.push(slug);\n // Mutating this attempt-scoped payload is safe: it's built fresh per\n // callWithRetries invocation and a fallbackModel run rebuilds it.\n payload.provider = {\n ...payload.provider,\n ignore: [...(payload.provider?.ignore ?? []), slug],\n order: payload.provider?.order?.filter(\n (entry) => normalizeProviderKey(entry) !== normalizeProviderKey(slug),\n ),\n };\n logger.log(\n id,\n `OpenRouter moderation eviction: ignoring provider \"${slug}\" for remaining attempts`,\n );\n }\n throw error;\n }),\n { retries, signal },\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// MAIN ENTRY POINT\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst VALID_PROVIDERS: Provider[] = [\"openai\", \"anthropic\", \"google\", \"groq\", \"openrouter\"];\n\nconst ENUM_PROVIDER_MAP: { values: Set<string>; provider: Provider }[] = [\n { values: new Set(Object.values(GPTModel)), provider: \"openai\" },\n { values: new Set(Object.values(ClaudeModel)), provider: \"anthropic\" },\n { values: new Set(Object.values(GeminiModel)), provider: \"google\" },\n { values: new Set(Object.values(GroqModel)), provider: \"groq\" },\n { values: new Set(Object.values(OpenRouterModel)), provider: \"openrouter\" },\n];\n\nexport function parseModelString(model: string): { provider: Provider; modelId: string } {\n const colonIndex = model.indexOf(\":\");\n\n if (colonIndex !== -1) {\n const prefix = model.substring(0, colonIndex);\n\n if (VALID_PROVIDERS.includes(prefix as Provider)) {\n const modelId = model.substring(colonIndex + 1);\n\n if (!modelId) {\n throw new Error(\n `Empty model ID in model string '${model}'. Expected format: 'provider:model-id'`,\n );\n }\n\n return { provider: prefix as Provider, modelId };\n }\n\n // Prefix isn't a known provider — fall through to enum lookup\n // (handles model values that contain colons, e.g. OpenRouter \"google/gemma-4-31b-it:free\")\n }\n\n // Fallback: check enum values\n for (const { values, provider } of ENUM_PROVIDER_MAP) {\n if (values.has(model)) {\n return { provider, modelId: model };\n }\n }\n\n // If string had a colon but wasn't a known provider, give a specific error\n if (colonIndex !== -1) {\n const prefix = model.substring(0, colonIndex);\n throw new Error(\n `Unknown provider '${prefix}' in model string '${model}'. Valid providers: ${VALID_PROVIDERS.join(\", \")}`,\n );\n }\n\n throw new Error(\n `Unable to determine provider for model '${model}'. Use a provider prefix (e.g. 'openai:${model}') or a known model enum value. Valid providers: ${VALID_PROVIDERS.join(\", \")}`,\n );\n}\n\nexport async function callWithRetries(\n id: string | string[],\n aiPayload: GenericPayload,\n aiConfig?: OpenAIConfig | AnthropicAIConfig,\n retries: number = 5,\n chunkTimeoutMs: number = 15_000,\n): Promise<ParsedResponseMessage> {\n try {\n const { provider, modelId } = parseModelString(aiPayload.model);\n const routingPayload = { ...aiPayload, model: modelId as AnyModel };\n // Per-attempt HTTP timeout, honored by every adapter. Default applied once\n // here so all providers share it; callers override via payload.requestTimeoutMs.\n const requestTimeoutMs = aiPayload.requestTimeoutMs ?? 120_000;\n const signal = aiPayload.signal;\n\n let result: ParsedResponseMessage;\n switch (provider) {\n case \"anthropic\":\n result = await callAnthropicWithRetries(\n id,\n await prepareAnthropicPayload(id, routingPayload),\n aiConfig as AnthropicAIConfig,\n retries,\n requestTimeoutMs,\n signal,\n );\n break;\n\n case \"openai\":\n result = await callOpenAiWithRetries(\n id,\n await prepareOpenAIPayload(id, routingPayload),\n aiConfig as OpenAIConfig,\n retries,\n chunkTimeoutMs,\n requestTimeoutMs,\n signal,\n );\n break;\n\n case \"groq\":\n result = await callGroqWithRetries(\n id,\n prepareGroqPayload(routingPayload),\n retries,\n requestTimeoutMs,\n signal,\n );\n break;\n\n case \"google\":\n result = await callGoogleAIWithRetries(\n id,\n await prepareGoogleAIPayload(id, routingPayload),\n retries,\n requestTimeoutMs,\n signal,\n );\n break;\n\n case \"openrouter\":\n // OpenRouter streams by default. The two transports have independent\n // budgets on purpose: `requestTimeoutMs` only bounds non-streaming\n // attempts (OpenRouter default 180s, tighter 120s global default kept\n // for other providers), while streaming gets `streamTimeoutMs`\n // (default 600s) total + the per-useful-chunk stall timeout, further\n // bounded by `streamDeadlineAt` when the caller has a turn budget.\n result = await callOpenRouterWithRetries(\n id,\n prepareOpenRouterPayload(routingPayload),\n retries,\n {\n streaming: aiPayload.streaming ?? true,\n streamTimeoutMs:\n aiPayload.streamTimeoutMs ?? OPENROUTER_STREAM_TIMEOUT_MS,\n streamDeadlineAt: aiPayload.streamDeadlineAt,\n requestTimeoutMs:\n aiPayload.requestTimeoutMs ?? OPENROUTER_NONSTREAM_TIMEOUT_MS,\n chunkTimeoutMs,\n },\n signal,\n );\n break;\n }\n\n // Attribution stamp: adapters that know the actual serving provider set it\n // themselves (OpenRouter returns the upstream provider it routed to); for\n // the rest, the SDK provider name is the answer. Because fallback recurses\n // through callWithRetries, the stamp always comes from the invocation whose\n // model actually answered.\n result.provider ??= provider;\n return result;\n } catch (error) {\n // Caller cancelled — reject immediately, never fall back to another model.\n if (aiPayload.signal?.aborted) throw error;\n if (aiPayload.fallbackModel) {\n logger.error(\n id,\n `Primary model ${aiPayload.model} failed, falling back to ${aiPayload.fallbackModel}`,\n {\n error: error instanceof Error ? error.message : error,\n cause:\n error instanceof Error && (error as any).cause instanceof Error\n ? (error as any).cause.message\n : undefined,\n },\n );\n return callWithRetries(\n id,\n {\n ...aiPayload,\n model: aiPayload.fallbackModel,\n fallbackModel: undefined,\n },\n aiConfig,\n retries,\n chunkTimeoutMs,\n );\n }\n throw error;\n }\n}\n","/** @deprecated Use provider prefix strings instead, e.g. `\"anthropic:claude-sonnet-4-5\"` */\nexport enum ClaudeModel {\n HAIKU_3 = \"claude-3-haiku-20240307\",\n SONNET_3 = \"claude-3-sonnet-20240229\",\n OPUS_3 = \"claude-3-opus-20240229\",\n HAIKU_3_5 = \"claude-3-5-haiku-20241022\",\n SONNET_3_5 = \"claude-3-5-sonnet-20241022\",\n SONNET_4 = \"claude-sonnet-4-20250514\",\n OPUS_4 = \"claude-opus-4-20250514\",\n OPUS_4_1 = \"claude-opus-4-1\",\n HAIKU_4_5 = \"claude-haiku-4-5\",\n SONNET_4_5 = \"claude-sonnet-4-5\",\n OPUS_4_5 = \"claude-opus-4-5\",\n}\n\n/** @deprecated Use provider prefix strings instead, e.g. `\"openai:gpt-4o\"` */\nexport enum GPTModel {\n GPT35_0613 = \"gpt-3.5-turbo-0613\",\n GPT35_0613_16K = \"gpt-3.5-turbo-16k-0613\",\n GPT35_0125 = \"gpt-3.5-turbo-0125\",\n GPT4_1106_PREVIEW = \"gpt-4-1106-preview\",\n GPT4_0125_PREVIEW = \"gpt-4-0125-preview\",\n GPT4_0409 = \"gpt-4-turbo-2024-04-09\",\n GPT4O = \"gpt-4o\",\n GPT4O_MINI = \"gpt-4o-mini\",\n O1_PREVIEW = \"o1-preview\",\n O1_MINI = \"o1-mini\",\n O3_MINI = \"o3-mini\",\n GPT4_1 = \"gpt-4.1\",\n GPT4_1_MINI = \"gpt-4.1-mini\",\n GPT4_1_NANO = \"gpt-4.1-nano\",\n GPT5 = \"gpt-5\",\n GPT5_MINI = \"gpt-5-mini\",\n}\n\n/** @deprecated Use provider prefix strings instead, e.g. `\"groq:llama-3.3-70b-versatile\"` */\nexport enum GroqModel {\n LLAMA_3_70B_8192 = \"llama3-70b-8192\",\n LLAMA_3_3_70B_VERSATILE = \"llama-3.3-70b-versatile\",\n QWEN3_32B = \"qwen/qwen3-32b\",\n DEEPSEEK_R1_DISTILL_LLAMA_70B = \"deepseek-r1-distill-llama-70b\",\n}\n\n/** @deprecated Use provider prefix strings instead, e.g. `\"openrouter:qwen/qwen3.6-plus:free\"` */\nexport enum OpenRouterModel {\n GEMMA_4_31B_IT_FREE = \"google/gemma-4-31b-it:free\",\n GEMMA_4_31B_IT = \"google/gemma-4-31b-it\",\n}\n\n/** @deprecated Use provider prefix strings instead, e.g. `\"google:gemini-2.0-flash\"` */\nexport enum GeminiModel {\n GEMINI_1_5_PRO = \"gemini-1.5-pro-latest\",\n GEMINI_EXP_1206 = \"gemini-exp-1206\",\n GEMINI_2_0_FLASH = \"gemini-2.0-flash\",\n GEMINI_2_0_FLASH_EXP_IMAGE_GENERATION = \"gemini-2.0-flash-exp-image-generation\",\n GEMINI_2_0_FLASH_THINKING_EXP = \"gemini-2.0-flash-thinking-exp\",\n GEMINI_2_0_FLASH_THINKING_EXP_01_21 = \"gemini-2.0-flash-thinking-exp-01-21\",\n GEMINI_2_5_FLASH_PREVIEW_04_17 = \"gemini-2.5-flash-preview-04-17\",\n GEMINI_3_FLASH_PREVIEW = \"gemini-3-flash-preview\",\n GEMINI_3_1_FLASH_LITE_PREVIEW = \"gemini-3.1-flash-lite-preview\",\n}\n\nexport interface GenericError {\n message: string;\n}\n\nexport enum ContentType {\n TEXT = \"text\",\n ATTACHMENT = \"attachment\",\n}\n\nexport type AIChainResponse = {\n content: string | null;\n contentType?: ContentType;\n functionCalls: FunctionCall[];\n};\n\n/**\n * A single conversation turn passed to `callWithRetries`. The SDK serializes\n * these into each provider's native message format.\n *\n * ## Multi-turn tool calls\n * To continue after the model calls a tool, append the model's own assistant\n * turn and then the tool result, then call again:\n *\n * 1. Read the assistant turn off the response: `function_calls` (each with an\n * `id`) and — for reasoning models — `reasoning` / `reasoningDetails`.\n * 2. Push back an `assistant` message carrying those same `functionCalls` (and,\n * to keep the model's chain-of-thought, the captured reasoning fields).\n * 3. Push back one `role: \"tool\"` message whose `toolResults` answer each call\n * by `toolCallId`.\n *\n * The SDK is a pure transport: it does NOT echo reasoning or pair results for\n * you — it serializes exactly what you put here. Every tool/reasoning field is\n * optional, so a plain `{ role, content }` message behaves as before.\n *\n * @example\n * // turn 1 — model asks for the weather\n * const a = await callWithRetries(id, { model, messages, functions });\n * // a.function_calls -> [{ id: \"call_abc\", name: \"get_weather\", arguments: { city: \"Tokyo\" } }]\n *\n * // turn 2 — feed the call + its result back\n * const next = await callWithRetries(id, { model, functions, messages: [\n * ...messages,\n * { role: \"assistant\", content: a.content ?? \"\", functionCalls: a.function_calls,\n * reasoning: a.reasoning, reasoningDetails: a.reasoningDetails },\n * { role: \"tool\", content: \"\", toolResults: [\n * { toolCallId: \"call_abc\", name: \"get_weather\", content: '{\"tempC\":22}' } ] },\n * ]});\n */\nexport interface GenericMessage {\n /**\n * `\"tool\"` carries tool results (see `toolResults`) back to the model and\n * must immediately follow the `assistant` turn that made the matching calls.\n */\n role: \"user\" | \"assistant\" | \"system\" | \"tool\";\n /** Plain-text content. Use `\"\"` for a tool-call-only or tool-result turn. */\n content: string;\n timestamp?: string;\n files?: File[];\n /**\n * Tool calls the model made on an `assistant` turn. Pass back the `id`s you\n * received in `ParsedResponseMessage.function_calls` so the provider can pair\n * them with the `toolResults` that follow.\n */\n functionCalls?: FunctionCall[];\n /**\n * Tool outputs on a `role: \"tool\"` message — one entry per call (parallel\n * calls produce several). Each `toolCallId` must match a `FunctionCall.id`\n * from the preceding assistant turn.\n */\n toolResults?: ToolResult[];\n /**\n * Optional reasoning string to echo back on an `assistant` turn (e.g.\n * OpenRouter/DeepSeek `reasoning`). Round-tripping it keeps the model's\n * chain-of-thought across tool calls; some thinking models (DeepSeek V4)\n * require it to avoid a 400 on the next turn.\n */\n reasoning?: string;\n /**\n * Optional structured reasoning to echo back on an `assistant` turn\n * (OpenRouter `reasoning_details`, or Anthropic `thinking` /\n * `redacted_thinking` blocks captured in\n * `ParsedResponseMessage.reasoningDetails`). Preserves the signatures /\n * encrypted payloads that providers validate on round-trip.\n *\n * Safe to echo regardless of which provider serves the next call: each\n * serializer keeps only its own provider's block shapes (Anthropic keeps\n * `thinking`/`redacted_thinking`; OpenAI-compat keeps `reasoning.*`), so a\n * cross-provider fallback drops foreign blocks instead of 400ing.\n */\n reasoningDetails?: any;\n}\n\n/**\n * The result of executing one tool call, fed back to the model on a\n * `role: \"tool\"` message. The SDK maps this to each provider's native shape:\n * OpenAI/Groq/OpenRouter `{ role: \"tool\", tool_call_id, content }`, Anthropic a\n * `tool_result` block, Google a `functionResponse` part.\n */\nexport interface ToolResult {\n /** The `id` of the `FunctionCall` this answers (from the prior assistant turn). */\n toolCallId: string;\n /**\n * The tool/function name. Required by Anthropic and Google on round-trip; the\n * SDK falls back to the matching call's name when omitted, but supplying it is\n * recommended.\n */\n name?: string;\n /** The tool output, serialized to a string (JSON or plain text). */\n content: string;\n}\n\nexport interface File {\n mimeType: string;\n url?: string;\n data?: string;\n}\n\n/**\n * A tool/function call on the wire for OpenAI-compatible APIs (OpenAI, Groq,\n * OpenRouter).\n */\nexport interface OpenAIToolCall {\n id: string;\n type: \"function\";\n function: {\n name: string;\n /** JSON-stringified arguments object. */\n arguments: string;\n };\n}\n\nexport interface OpenAIMessage {\n role: \"user\" | \"assistant\" | \"system\" | \"tool\";\n /** `null` for an assistant turn that is tool-calls-only. */\n content: string | OpenAIContentBlock[] | null;\n /** Present on an assistant turn that called tools. */\n tool_calls?: OpenAIToolCall[];\n /** Present on a `role: \"tool\"` message; matches the originating `OpenAIToolCall.id`. */\n tool_call_id?: string;\n /** Reasoning echoed back on an assistant turn (OpenRouter/DeepSeek; OAI-compatible proxies). */\n reasoning?: string;\n /** Structured reasoning echoed back on an assistant turn (OpenRouter `reasoning_details`). */\n reasoning_details?: any;\n}\n\nexport type OpenAIContentBlock =\n | OpenAITextContentBlock\n | OpenAIImageContentBlock\n | OpenAIAudioContentBlock;\n\nexport interface OpenAITextContentBlock {\n type: \"text\";\n text: string;\n}\n\nexport interface OpenAIImageContentBlock {\n type: \"image_url\";\n image_url: {\n url: string; // URL to the image, can also be a base64 string\n };\n}\n\nexport interface OpenAIAudioContentBlock {\n type: \"audio_url\";\n audio_url: {\n url: string; // URL to the audio, can also be a base64 string\n };\n}\n\nexport interface AnthropicAIMessage {\n role: \"user\" | \"assistant\" | \"system\";\n content: string | AnthropicContentBlock[];\n}\n\nexport type AnthropicContentBlock =\n | AnthropicTextContentBlock\n | AnthropicImageContentBlock\n | AnthropicToolUseBlock\n | AnthropicToolResultBlock\n | AnthropicThinkingBlock\n | AnthropicRedactedThinkingBlock;\n\nexport interface AnthropicTextContentBlock {\n type: \"text\";\n text: string;\n}\n\nexport interface AnthropicImageContentBlock {\n type: \"image\";\n source: {\n type: \"base64\";\n media_type: \"image/jpeg\" | \"image/png\" | \"image/gif\" | \"image/webp\";\n data: string; // Must be a base64 string\n };\n}\n\n/** A tool call on an Anthropic assistant turn. */\nexport interface AnthropicToolUseBlock {\n type: \"tool_use\";\n id: string;\n name: string;\n input: Record<string, any>;\n}\n\n/** A tool result, carried on a (user-role) Anthropic message. */\nexport interface AnthropicToolResultBlock {\n type: \"tool_result\";\n tool_use_id: string;\n content: string;\n}\n\n/** A reasoning block round-tripped on an assistant turn; `signature` is validated by Anthropic. */\nexport interface AnthropicThinkingBlock {\n type: \"thinking\";\n thinking: string;\n signature: string;\n}\n\n/** An encrypted reasoning block round-tripped verbatim on an assistant turn. */\nexport interface AnthropicRedactedThinkingBlock {\n type: \"redacted_thinking\";\n data: string;\n}\n\nexport interface OpenAIResponseMessage {\n role: \"assistant\";\n content: string | null;\n function_call: {\n name: string;\n arguments: string; // unparsed arguments object\n } | null;\n}\n\nexport interface ParsedResponseMessage {\n role: \"assistant\";\n content: string | null;\n /** First of `function_calls` (backward-compat); carries `id` when the provider returns one. */\n function_call: FunctionCall | null;\n /** All tool calls the model made this turn, each with an `id` for round-tripping. */\n function_calls: FunctionCall[];\n files: File[];\n /**\n * Reasoning string from reasoning models (OpenRouter/DeepSeek `reasoning`).\n * Echo back via `GenericMessage.reasoning` to preserve chain-of-thought across\n * tool calls. Undefined when the model/provider returns none.\n */\n reasoning?: string;\n /**\n * Structured reasoning (OpenRouter `reasoning_details`, or Anthropic\n * `thinking` / `redacted_thinking` blocks). Echo back verbatim via\n * `GenericMessage.reasoningDetails` — it carries signatures some providers\n * validate. Undefined when the model/provider returns none.\n */\n reasoningDetails?: any;\n /**\n * Who actually served the response. For OpenRouter this is the upstream\n * provider from the response body (e.g. \"Baidu\", \"Morph\") — the routing\n * decision OpenRouter made, not the requested model slug. For direct\n * providers it's the SDK provider name (\"anthropic\", \"openai\", \"google\",\n * \"groq\"). On model fallback it reflects the model that answered, so a\n * mismatch with the requested model's provider reveals the fallback.\n */\n provider?: string;\n /**\n * True when the answer is INCOMPLETE: the streamed generation was cut at the\n * caller's deadline and the partial prose is returned instead of discarded.\n * Content is mid-sentence (or mid-file) by definition — surface it to the\n * end user as truncated rather than presenting it as a finished answer.\n * Never set on tool-call turns (a half-streamed arguments fragment can't be\n * salvaged) and never on a normal completion.\n */\n truncated?: boolean;\n usage: {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n /** Prompt tokens served from the provider's cache (subset of prompt_tokens). */\n cached_tokens?: number;\n } | null;\n}\n\nexport interface FunctionCall {\n /**\n * Provider tool-call id, surfaced on responses and used to pair a call with\n * its `ToolResult.toolCallId` on the next turn. The SDK synthesizes\n * `call_<index>` for providers that don't return one (e.g. Google).\n */\n id?: string;\n name: string;\n arguments: Record<string, any>;\n /**\n * Opaque per-call signature that must be echoed back verbatim on round-trip.\n * Currently Google's `thoughtSignature` — Gemini REQUIRES it on functionCall\n * parts in multi-turn tool use (a missing one 400s the next request). The SDK\n * captures it on responses and re-emits it when you pass the call back;\n * undefined for providers that don't use one.\n */\n thoughtSignature?: string;\n}\n\nexport interface OpenAIConfig {\n service: \"azure\" | \"openai\";\n apiKey: string;\n /**\n * Override the base URL for the OpenAI service (e.g. an OpenAI-compatible\n * proxy or self-hosted endpoint). The path `/chat/completions` is appended.\n * Ignored when `service === \"azure\"` (use `modelConfigMap` instead).\n * Defaults to `https://api.openai.com/v1`.\n */\n baseUrl?: string;\n orgId?: string;\n modelConfigMap?: Record<\n GPTModel,\n {\n resource: string;\n deployment: string;\n apiVersion: string;\n apiKey: string;\n endpoint?: string;\n }\n >;\n}\n\nexport interface AnthropicAIConfig {\n service: \"anthropic\" | \"bedrock\";\n}\n\nexport interface FunctionDefinition {\n name: string;\n description?: string;\n parameters: Record<string, any>;\n}\n\ninterface FunctionWrapped {\n type: \"function\";\n function: FunctionDefinition;\n}\n\nexport interface GroqPayload {\n model: GroqModel | string;\n messages: OpenAIMessage[];\n tools?: FunctionWrapped[];\n tool_choice?:\n | \"none\"\n | \"auto\"\n | { type: \"function\"; function: { name: string } };\n temperature?: number;\n\n functions?: any[]; // Deprecate this\n}\n\n/**\n * OpenRouter provider-routing preferences, forwarded verbatim as the request\n * body's `provider` field. See https://openrouter.ai/docs/guides/routing/provider-selection\n */\nexport interface OpenRouterProviderPreferences {\n /** Ordered list of provider slugs to try first (e.g. [\"baidu\", \"siliconflow\"]). */\n order?: string[];\n /** Restrict routing to exactly these provider slugs. */\n only?: string[];\n /** Provider slugs to exclude. */\n ignore?: string[];\n /** Only use providers serving these quantizations (e.g. [\"fp8\"]). */\n quantizations?: string[];\n /** When false, never fall back to providers outside `order`/`only`. */\n allow_fallbacks?: boolean;\n /** Override the default sort (\"price\" | \"throughput\" | \"latency\"). */\n sort?: string;\n}\n\nexport interface OpenRouterPayload {\n model: OpenRouterModel | string;\n messages: OpenAIMessage[];\n tools?: FunctionWrapped[];\n tool_choice?:\n | \"none\"\n | \"auto\"\n | { type: \"function\"; function: { name: string } };\n temperature?: number;\n provider?: OpenRouterProviderPreferences;\n /** Set by the adapter, never by callers: SSE streaming on/off. */\n stream?: boolean;\n /**\n * Set by the adapter on streamed requests: OpenRouter's usage-accounting\n * flag, which makes the final SSE chunk carry the `usage` object.\n */\n usage?: { include: boolean };\n}\n\nexport interface OpenAIPayload {\n model: GPTModel | string;\n messages: OpenAIMessage[];\n tools?: FunctionWrapped[];\n tool_choice?:\n | \"none\"\n | \"auto\"\n | { type: \"function\"; function: { name: string } };\n}\n\nexport interface AnthropicAIPayload {\n model: ClaudeModel | string;\n messages: AnthropicAIMessage[];\n functions?: any[]; // TODO type this JSON schema\n temperature?: number;\n system?: string;\n tool_choice?: { type: \"none\" | \"auto\" } | { type: \"tool\"; name: string };\n}\n\nexport interface GoogleAITextPart {\n text: string;\n}\n\nexport interface GoogleAIInlineDataPart {\n inlineData: {\n mimeType: string;\n data: string;\n };\n}\n\nexport interface GoogleAIFileDataPart {\n fileData: {\n mimeType: string;\n fileUri: string;\n };\n}\n\n/** A tool call on a Google `model` turn. */\nexport interface GoogleAIFunctionCallPart {\n functionCall: {\n id?: string;\n name: string;\n args: Record<string, any>;\n };\n /** Echoed back verbatim on round-trip — Gemini requires it for tool use. */\n thoughtSignature?: string;\n}\n\n/** A tool result, carried on a Google `user` turn. */\nexport interface GoogleAIFunctionResponsePart {\n functionResponse: {\n id?: string;\n name: string;\n response: Record<string, any>;\n };\n}\n\nexport type GoogleAIPart =\n | GoogleAITextPart\n | GoogleAIInlineDataPart\n | GoogleAIFileDataPart\n | GoogleAIFunctionCallPart\n | GoogleAIFunctionResponsePart;\nexport interface GoogleAIMessage {\n role: \"user\" | \"model\";\n parts: GoogleAIPart[];\n}\nexport interface GoogleAIPayload {\n model: GeminiModel | string;\n messages: GoogleAIMessage[];\n tools?: {\n functionDeclarations: FunctionDefinition[];\n };\n toolConfig?: {\n functionCallingConfig: { mode: \"NONE\" | \"AUTO\" | \"ANY\" };\n };\n systemInstruction?: string;\n}\n\nexport type Provider = \"openai\" | \"anthropic\" | \"google\" | \"groq\" | \"openrouter\";\n\nexport type AnyModel = GPTModel | ClaudeModel | GroqModel | GeminiModel | OpenRouterModel | (string & {});\n\nexport interface GenericPayload {\n model: AnyModel;\n messages: GenericMessage[];\n functions?: FunctionDefinition[];\n function_call?: \"none\" | \"auto\" | { name: string };\n temperature?: number;\n fallbackModel?: AnyModel;\n /**\n * OpenRouter-only: provider-routing preferences. Ignored by non-OpenRouter\n * adapters. Forwarded as the request body's `provider` field.\n */\n provider?: OpenRouterProviderPreferences;\n /**\n * Per-request HTTP timeout in ms for the underlying provider call (applied\n * per attempt, not across retries). Honored by all adapters (Anthropic,\n * Google, OpenAI, OpenRouter, Groq); defaults to 120s when omitted. Raise it\n * for slow, large generations (e.g. single-file app codegen) so a long-but-\n * valid response isn't cut short.\n */\n requestTimeoutMs?: number;\n /**\n * OpenRouter-only: stream the completion over SSE instead of waiting for a\n * single JSON body. Defaults to true. Streaming attempts are bounded by\n * `streamTimeoutMs` (total) plus a per-useful-chunk stall timeout — NOT by\n * `requestTimeoutMs`, which only governs non-streaming attempts (default\n * 180s for OpenRouter). Set to false to force the old non-streaming path.\n */\n streaming?: boolean;\n /**\n * OpenRouter-only: total wall-clock budget in ms for one streaming attempt\n * (connect + full generation). Defaults to 600s. Independent of\n * `requestTimeoutMs` by design: a healthy long generation keeps streaming\n * useful chunks and may run far past any sane non-streaming deadline, while\n * a hung one is killed much earlier by the per-useful-chunk stall timeout\n * (`chunkTimeoutMs` argument of `callWithRetries`, default 15s — reset only\n * by chunks that advance the output, never by keep-alive bytes/comments).\n */\n streamTimeoutMs?: number;\n /**\n * OpenRouter-only: absolute wall-clock deadline (epoch ms) for the whole\n * call INCLUDING retries — the caller's turn budget, not a per-attempt one.\n * Each streaming attempt gets `min(streamTimeoutMs, deadline - now)`, and\n * once too little time remains to be worth an attempt the call fails fast\n * instead of starting a generation that cannot finish.\n *\n * Without it, a per-attempt budget is re-granted on every retry, so a slow\n * generation can outlive the caller's own turn deadline and get killed with\n * nothing to show (2026-07-28: a 538s completion finished just as the\n * caller's 585s turn budget expired, and the reply was discarded).\n */\n streamDeadlineAt?: number;\n /**\n * Optional caller-supplied cancellation signal. When it aborts, the in-flight\n * provider request is cancelled and `callWithRetries` rejects immediately —\n * it does NOT retry or fall back (both retry loop and fallback branch bail on\n * `signal.aborted`). Threaded through every adapter to the underlying\n * fetch/axios/SDK call, mirroring `requestTimeoutMs`.\n */\n signal?: AbortSignal;\n}\n\nexport interface OpenAIBody {\n choices: {\n message: OpenAIResponseMessage;\n }[];\n error?: {\n code: string;\n };\n usage: {\n completion_tokens: number;\n prompt_tokens: number;\n total_tokens: number;\n prompt_tokens_details?: {\n cached_tokens?: number;\n };\n };\n}\n","type LogLevel = \"LOG\" | \"WARN\" | \"ERROR\";\nexport type Identifier = string | string[];\n\nfunction formatIdentifier(identifier: Identifier): string {\n if (Array.isArray(identifier)) {\n return identifier.map((id) => `[${id}]`).join(\" \");\n }\n return `[${identifier}]`;\n}\n\nfunction formatMessage(\n level: LogLevel,\n identifier: Identifier,\n message: string\n): string {\n return `[${level}] ${formatIdentifier(identifier)} ${message}`;\n}\n\nexport function log(\n identifier: Identifier,\n message: string,\n ...args: any[]\n): void {\n console.log(formatMessage(\"LOG\", identifier, message), ...args);\n}\n\nexport function warn(\n identifier: Identifier,\n message: string,\n ...args: any[]\n): void {\n console.warn(formatMessage(\"WARN\", identifier, message), ...args);\n}\n\nexport function error(\n identifier: Identifier,\n message: string,\n ...args: any[]\n): void {\n console.error(formatMessage(\"ERROR\", identifier, message), ...args);\n}\n\nexport default {\n log,\n warn,\n error,\n};\n","export function timeout(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function isHeicImage(name: string, mime?: string): boolean {\n const extension = name.split(\".\").pop()?.toLowerCase() || \"\";\n return (\n [\"heic\", \"heif\", \"heics\"].includes(extension) ||\n !!(\n mime && [\"image/heic\", \"image/heif\", \"image/heic-sequence\"].includes(mime)\n )\n );\n}\n"],"mappings":"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","names":["ClaudeModel","GPTModel","GroqModel","OpenRouterModel","GeminiModel","error","axios","_a"]}