@jecruz/merc-ai 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"openai-completions.d.ts","sourceRoot":"","sources":["../../src/providers/openai-completions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAQX,0BAA0B,EAG1B,MAAM,sCAAsC,CAAC;AAG9C,OAAO,KAAK,EAGX,OAAO,EAGP,KAAK,EACL,uBAAuB,EAEvB,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAMb,MAAM,aAAa,CAAC;AAoIrB,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC9D,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IAC7F,eAAe,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;CAC1E;AAOD,KAAK,+BAA+B,GAAG,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,oBAAoB,CAAC,GAAG;IACtG,kBAAkB,CAAC,EAAE,uBAAuB,CAAC,oBAAoB,CAAC,CAAC;CACnE,CAAC;AAgDF,eAAO,MAAM,uBAAuB,EAAE,cAAc,CAAC,oBAAoB,EAAE,wBAAwB,CA4alG,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CAoBnG,CAAC;AAuUF,wBAAgB,eAAe,CAC9B,KAAK,EAAE,KAAK,CAAC,oBAAoB,CAAC,EAClC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,+BAA+B,GACrC,0BAA0B,EAAE,CAsO9B","sourcesContent":["import OpenAI from \"openai\";\nimport type {\n\tChatCompletion,\n\tChatCompletionAssistantMessageParam,\n\tChatCompletionChunk,\n\tChatCompletionContentPart,\n\tChatCompletionContentPartImage,\n\tChatCompletionContentPartText,\n\tChatCompletionDeveloperMessageParam,\n\tChatCompletionMessageParam,\n\tChatCompletionSystemMessageParam,\n\tChatCompletionToolMessageParam,\n} from \"openai/resources/chat/completions.js\";\nimport { getEnvApiKey } from \"../env-api-keys.js\";\nimport { calculateCost, clampThinkingLevel } from \"../models.js\";\nimport type {\n\tAssistantMessage,\n\tCacheRetention,\n\tContext,\n\tImageContent,\n\tMessage,\n\tModel,\n\tOpenAICompletionsCompat,\n\tProviderEnv,\n\tSimpleStreamOptions,\n\tStopReason,\n\tStreamFunction,\n\tStreamOptions,\n\tTextContent,\n\tThinkingContent,\n\tTool,\n\tToolCall,\n\tToolResultMessage,\n} from \"../types.js\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.js\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.js\";\nimport { headersToRecord } from \"../utils/headers.js\";\nimport { finalizeToolCallArguments, parseStreamingJson } from \"../utils/json-parse.js\";\nimport { getProviderEnvValue } from \"../utils/provider-env.js\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.js\";\nimport { createProviderToolCallIdNormalizer } from \"../utils/tool-call-id.js\";\nimport { isCloudflareProvider, resolveCloudflareBaseUrl } from \"./cloudflare.js\";\nimport { buildCopilotDynamicHeaders, hasCopilotVisionInput } from \"./github-copilot-headers.js\";\nimport { clampOpenAIPromptCacheKey } from \"./openai-prompt-cache.js\";\nimport { buildBaseOptions } from \"./simple-options.js\";\nimport { transformMessages } from \"./transform-messages.js\";\n\n/**\n * Check if conversation messages contain tool calls or tool results.\n * This is needed because Anthropic (via proxy) requires the tools param\n * to be present when messages include tool_calls or tool role messages.\n */\nfunction hasToolHistory(messages: Message[]): boolean {\n\tfor (const msg of messages) {\n\t\tif (msg.role === \"toolResult\") {\n\t\t\treturn true;\n\t\t}\n\t\tif (msg.role === \"assistant\") {\n\t\t\tif (msg.content.some((block) => block.type === \"toolCall\")) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction isTextContentBlock(block: { type: string }): block is TextContent {\n\treturn block.type === \"text\";\n}\n\nfunction isThinkingContentBlock(block: { type: string }): block is ThinkingContent {\n\treturn block.type === \"thinking\";\n}\n\nfunction isToolCallBlock(block: { type: string }): block is ToolCall {\n\treturn block.type === \"toolCall\";\n}\n\nfunction isImageContentBlock(block: { type: string }): block is ImageContent {\n\treturn block.type === \"image\";\n}\n\nfunction isMiniMaxModel(model: Model<\"openai-completions\">): boolean {\n\t// LLM Dynamix is currently allowlisted to MiniMax-M3 on the local runtime;\n\t// retain the provider match when discovery normalizes the model ID.\n\treturn model.provider === \"llmdynamix\" || model.id.toLowerCase().includes(\"minimax-m3\");\n}\n\nfunction createThinkingTagFilter(enabled: boolean): { push: (chunk: string) => string; flush: () => string } {\n\tlet buffer = \"\";\n\tlet inThinking = false;\n\tconst openingTag = \"<think\";\n\tconst closingTag = \"</think>\";\n\n\tconst consume = (): string => {\n\t\tlet visible = \"\";\n\t\twhile (buffer.length > 0) {\n\t\t\tconst lower = buffer.toLowerCase();\n\t\t\tif (inThinking) {\n\t\t\t\tconst end = lower.indexOf(closingTag);\n\t\t\t\tif (end < 0) {\n\t\t\t\t\tbuffer = \"\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbuffer = buffer.slice(end + closingTag.length);\n\t\t\t\tinThinking = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst start = lower.indexOf(openingTag);\n\t\t\tif (start < 0) {\n\t\t\t\tconst strayClosing = lower.indexOf(closingTag);\n\t\t\t\tif (strayClosing >= 0) {\n\t\t\t\t\tvisible += buffer.slice(0, strayClosing);\n\t\t\t\t\tbuffer = buffer.slice(strayClosing + closingTag.length);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst partialStart = Math.max(0, buffer.length - openingTag.length + 1);\n\t\t\t\tconst partial = buffer.slice(partialStart).toLowerCase();\n\t\t\t\tconst closingPartialStart = Math.max(0, buffer.length - closingTag.length + 1);\n\t\t\t\tconst closingPartial = buffer.slice(closingPartialStart).toLowerCase();\n\t\t\t\tconst partialLength = Math.max(\n\t\t\t\t\tpartial && openingTag.startsWith(partial) ? partial.length : 0,\n\t\t\t\t\tclosingPartial && closingTag.startsWith(closingPartial) ? closingPartial.length : 0,\n\t\t\t\t);\n\t\t\t\tvisible += buffer.slice(0, buffer.length - partialLength);\n\t\t\t\tbuffer = buffer.slice(buffer.length - partialLength);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tvisible += buffer.slice(0, start);\n\t\t\tbuffer = buffer.slice(start);\n\t\t\tconst tagEnd = buffer.indexOf(\">\");\n\t\t\tif (tagEnd < 0) break;\n\t\t\tbuffer = buffer.slice(tagEnd + 1);\n\t\t\tinThinking = true;\n\t\t}\n\t\treturn visible;\n\t};\n\n\treturn {\n\t\tpush: (chunk) => {\n\t\t\tif (!enabled) return chunk;\n\t\t\tbuffer += chunk;\n\t\t\treturn consume();\n\t\t},\n\t\tflush: () => (enabled ? consume() : buffer),\n\t};\n}\n\nfunction isEncryptedReasoningDetail(detail: unknown): detail is OpenAIEncryptedReasoningDetail {\n\tif (typeof detail !== \"object\" || detail === null) {\n\t\treturn false;\n\t}\n\tconst candidate = detail as Record<string, unknown>;\n\treturn (\n\t\tcandidate.type === \"reasoning.encrypted\" &&\n\t\ttypeof candidate.id === \"string\" &&\n\t\tcandidate.id.length > 0 &&\n\t\ttypeof candidate.data === \"string\" &&\n\t\tcandidate.data.length > 0\n\t);\n}\n\nexport interface OpenAICompletionsOptions extends StreamOptions {\n\ttoolChoice?: \"auto\" | \"none\" | \"required\" | { type: \"function\"; function: { name: string } };\n\treasoningEffort?: \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n}\n\ninterface OpenAICompatCacheControl {\n\ttype: \"ephemeral\";\n\tttl?: string;\n}\n\ntype ResolvedOpenAICompletionsCompat = Omit<Required<OpenAICompletionsCompat>, \"cacheControlFormat\"> & {\n\tcacheControlFormat?: OpenAICompletionsCompat[\"cacheControlFormat\"];\n};\n\ntype ChatCompletionInstructionMessageParam = ChatCompletionDeveloperMessageParam | ChatCompletionSystemMessageParam;\n\ntype OpenAIEncryptedReasoningDetail = {\n\ttype: \"reasoning.encrypted\";\n\tid: string;\n\tdata: string;\n};\n\ntype ChatCompletionTextPartWithCacheControl = ChatCompletionContentPartText & {\n\tcache_control?: OpenAICompatCacheControl;\n};\n\ntype ChatCompletionToolWithCacheControl = OpenAI.Chat.Completions.ChatCompletionTool & {\n\tcache_control?: OpenAICompatCacheControl;\n};\n\ninterface OpenRouterGeneratedImage {\n\timage_url?: string | { url?: string };\n}\n\ntype OpenRouterImageGenerationMessage = ChatCompletion[\"choices\"][number][\"message\"] & {\n\timages?: OpenRouterGeneratedImage[];\n};\n\ntype OpenRouterImageGenerationChoice = ChatCompletion[\"choices\"][number] & {\n\tmessage: OpenRouterImageGenerationMessage;\n};\n\ntype OpenRouterImageGenerationResponse = ChatCompletion & {\n\tchoices: OpenRouterImageGenerationChoice[];\n};\n\nfunction isOpenRouterImageGenerationModel(model: Model<\"openai-completions\">): boolean {\n\treturn model.provider === \"openrouter\" && model.compat?.openRouterImageGeneration === true;\n}\n\nfunction resolveCacheRetention(cacheRetention?: CacheRetention, env?: ProviderEnv): CacheRetention {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\tif (getProviderEnvValue(\"MERC_CACHE_RETENTION\", env) === \"long\") {\n\t\treturn \"long\";\n\t}\n\treturn \"short\";\n}\n\nexport const streamOpenAICompletions: StreamFunction<\"openai-completions\", OpenAICompletionsOptions> = (\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\toptions?: OpenAICompletionsOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\ttry {\n\t\t\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider, options?.env) || \"\";\n\t\t\tconst compat = getCompat(model);\n\t\t\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\t\t\tconst cacheSessionId = cacheRetention === \"none\" ? undefined : options?.sessionId;\n\t\t\tconst client = createClient(model, context, apiKey, options?.headers, cacheSessionId, compat, options?.env);\n\t\t\tlet params = buildParams(model, context, options, compat, cacheRetention);\n\t\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\t\tif (nextParams !== undefined) {\n\t\t\t\tparams = nextParams as OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming;\n\t\t\t}\n\t\t\tconst requestOptions = {\n\t\t\t\t...(options?.signal ? { signal: options.signal } : {}),\n\t\t\t\t...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n\t\t\t\tmaxRetries: options?.maxRetries ?? 0,\n\t\t\t};\n\t\t\tif (isOpenRouterImageGenerationModel(model)) {\n\t\t\t\tconst { stream_options: _streamOptions, ...nonStreamingBaseParams } = params;\n\t\t\t\tconst nonStreamingParams = {\n\t\t\t\t\t...nonStreamingBaseParams,\n\t\t\t\t\tstream: false,\n\t\t\t\t} as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming;\n\t\t\t\tconst { data: response, response: rawResponse } = await client.chat.completions\n\t\t\t\t\t.create(nonStreamingParams, requestOptions)\n\t\t\t\t\t.withResponse();\n\t\t\t\tawait options?.onResponse?.(\n\t\t\t\t\t{ status: rawResponse.status, headers: headersToRecord(rawResponse.headers) },\n\t\t\t\t\tmodel,\n\t\t\t\t);\n\t\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\t\tconst imageResponse = response as OpenRouterImageGenerationResponse;\n\t\t\t\toutput.responseId ||= imageResponse.id;\n\t\t\t\toutput.usage = parseChunkUsage(imageResponse.usage ?? {}, model);\n\n\t\t\t\tconst choice = imageResponse.choices[0];\n\t\t\t\tif (choice) {\n\t\t\t\t\tconst text = choice.message.content;\n\t\t\t\t\tif (text) {\n\t\t\t\t\t\tconst textBlock: TextContent = { type: \"text\", text };\n\t\t\t\t\t\toutput.content.push(textBlock);\n\t\t\t\t\t\tconst contentIndex = output.content.length - 1;\n\t\t\t\t\t\tstream.push({ type: \"text_start\", contentIndex, partial: output });\n\t\t\t\t\t\tstream.push({ type: \"text_delta\", contentIndex, delta: text, partial: output });\n\t\t\t\t\t\tstream.push({ type: \"text_end\", contentIndex, content: text, partial: output });\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const image of choice.message.images ?? []) {\n\t\t\t\t\t\tconst imageUrl = typeof image.image_url === \"string\" ? image.image_url : image.image_url?.url;\n\t\t\t\t\t\tif (!imageUrl?.startsWith(\"data:\")) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst matches = imageUrl.match(/^data:([^;]+);base64,(.+)$/);\n\t\t\t\t\t\tif (!matches) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst imageBlock: ImageContent = {\n\t\t\t\t\t\t\ttype: \"image\",\n\t\t\t\t\t\t\tmimeType: matches[1],\n\t\t\t\t\t\t\tdata: matches[2],\n\t\t\t\t\t\t};\n\t\t\t\t\t\toutput.content.push(imageBlock);\n\t\t\t\t\t\tconst contentIndex = output.content.length - 1;\n\t\t\t\t\t\tstream.push({ type: \"image_start\", contentIndex, partial: output });\n\t\t\t\t\t\tstream.push({ type: \"image_end\", contentIndex, image: imageBlock, partial: output });\n\t\t\t\t\t}\n\n\t\t\t\t\tif (choice.finish_reason) {\n\t\t\t\t\t\tconst finishReasonResult = mapStopReason(choice.finish_reason);\n\t\t\t\t\t\toutput.stopReason = finishReasonResult.stopReason;\n\t\t\t\t\t\tif (finishReasonResult.errorMessage) {\n\t\t\t\t\t\t\toutput.errorMessage = finishReasonResult.errorMessage;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (output.stopReason === \"stop\" || output.stopReason === \"length\" || output.stopReason === \"toolUse\") {\n\t\t\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\t\t} else {\n\t\t\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\t\t}\n\t\t\t\tstream.end();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { data: openaiStream, response } = await client.chat.completions\n\t\t\t\t.create(params, requestOptions)\n\t\t\t\t.withResponse();\n\t\t\tawait options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\tinterface StreamingToolCallBlock extends ToolCall {\n\t\t\t\tpartialArgs?: string;\n\t\t\t\tstreamIndex?: number;\n\t\t\t}\n\t\t\ttype StreamingBlock = TextContent | ThinkingContent | StreamingToolCallBlock;\n\t\t\ttype StreamingToolCallDelta = NonNullable<ChatCompletionChunk.Choice.Delta[\"tool_calls\"]>[number];\n\n\t\t\tlet textBlock: TextContent | null = null;\n\t\t\tlet thinkingBlock: ThinkingContent | null = null;\n\t\t\tlet hasFinishReason = false;\n\t\t\tlet hasIncompleteToolCallArguments = false;\n\t\t\tconst toolCallBlocksByIndex = new Map<number, StreamingToolCallBlock>();\n\t\t\tconst toolCallBlocksById = new Map<string, StreamingToolCallBlock>();\n\t\t\tconst pendingReasoningDetailsByToolCallId = new Map<string, string>();\n\t\t\tconst blocks = output.content as StreamingBlock[];\n\t\t\tconst thinkingTagFilter = createThinkingTagFilter(\n\t\t\t\tisMiniMaxModel(model) || compat.thinkingFormat === \"minimax\",\n\t\t\t);\n\t\t\tconst getContentIndex = (block: StreamingBlock) => blocks.indexOf(block);\n\t\t\tconst finishBlock = (block: StreamingBlock) => {\n\t\t\t\tconst contentIndex = getContentIndex(block);\n\t\t\t\tif (contentIndex === -1) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (block.type === \"text\") {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\tcontentIndex,\n\t\t\t\t\t\tcontent: block.text,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t} else if (block.type === \"thinking\") {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\tcontentIndex,\n\t\t\t\t\t\tcontent: block.thinking,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\t// Without finish_reason, only strictly valid raw arguments prove the call was not cut off.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tJSON.parse(block.partialArgs ?? \"\");\n\t\t\t\t\t} catch {\n\t\t\t\t\t\thasIncompleteToolCallArguments = true;\n\t\t\t\t\t}\n\t\t\t\t\tfinalizeToolCallArguments(block, block.partialArgs);\n\t\t\t\t\t// Finalize in-place and strip the scratch buffers so replay only\n\t\t\t\t\t// carries parsed arguments.\n\t\t\t\t\tdelete block.partialArgs;\n\t\t\t\t\tdelete block.streamIndex;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\t\tcontentIndex,\n\t\t\t\t\t\ttoolCall: block,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst ensureTextBlock = () => {\n\t\t\t\tif (!textBlock) {\n\t\t\t\t\ttextBlock = { type: \"text\", text: \"\" };\n\t\t\t\t\tblocks.push(textBlock);\n\t\t\t\t\tstream.push({ type: \"text_start\", contentIndex: getContentIndex(textBlock), partial: output });\n\t\t\t\t}\n\t\t\t\treturn textBlock;\n\t\t\t};\n\t\t\tconst appendTextDelta = (delta: string) => {\n\t\t\t\tif (!delta) return;\n\t\t\t\tconst block = ensureTextBlock();\n\t\t\t\tblock.text += delta;\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\tdelta,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t};\n\t\t\tconst ensureThinkingBlock = (thinkingSignature: string) => {\n\t\t\t\tif (!thinkingBlock) {\n\t\t\t\t\tthinkingBlock = {\n\t\t\t\t\t\ttype: \"thinking\",\n\t\t\t\t\t\tthinking: \"\",\n\t\t\t\t\t\tthinkingSignature,\n\t\t\t\t\t};\n\t\t\t\t\tblocks.push(thinkingBlock);\n\t\t\t\t\tstream.push({ type: \"thinking_start\", contentIndex: getContentIndex(thinkingBlock), partial: output });\n\t\t\t\t}\n\t\t\t\treturn thinkingBlock;\n\t\t\t};\n\t\t\tconst applyPendingReasoningDetail = (block: StreamingToolCallBlock) => {\n\t\t\t\tif (!block.id) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst pendingReasoningDetail = pendingReasoningDetailsByToolCallId.get(block.id);\n\t\t\t\tif (pendingReasoningDetail) {\n\t\t\t\t\tblock.thoughtSignature = pendingReasoningDetail;\n\t\t\t\t\tpendingReasoningDetailsByToolCallId.delete(block.id);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst ensureToolCallBlock = (toolCall: StreamingToolCallDelta) => {\n\t\t\t\tconst streamIndex = typeof toolCall.index === \"number\" ? toolCall.index : undefined;\n\t\t\t\tlet block = streamIndex !== undefined ? toolCallBlocksByIndex.get(streamIndex) : undefined;\n\t\t\t\tif (!block && toolCall.id) {\n\t\t\t\t\tblock = toolCallBlocksById.get(toolCall.id);\n\t\t\t\t}\n\t\t\t\tif (!block) {\n\t\t\t\t\tblock = {\n\t\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\t\tid: toolCall.id || \"\",\n\t\t\t\t\t\tname: toolCall.function?.name || \"\",\n\t\t\t\t\t\targuments: {},\n\t\t\t\t\t\tpartialArgs: \"\",\n\t\t\t\t\t\tstreamIndex,\n\t\t\t\t\t};\n\t\t\t\t\tif (streamIndex !== undefined) {\n\t\t\t\t\t\ttoolCallBlocksByIndex.set(streamIndex, block);\n\t\t\t\t\t}\n\t\t\t\t\tif (toolCall.id) {\n\t\t\t\t\t\ttoolCallBlocksById.set(toolCall.id, block);\n\t\t\t\t\t}\n\t\t\t\t\tblocks.push(block);\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"toolcall_start\",\n\t\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (streamIndex !== undefined && block.streamIndex === undefined) {\n\t\t\t\t\tblock.streamIndex = streamIndex;\n\t\t\t\t\ttoolCallBlocksByIndex.set(streamIndex, block);\n\t\t\t\t}\n\t\t\t\tif (toolCall.id) {\n\t\t\t\t\ttoolCallBlocksById.set(toolCall.id, block);\n\t\t\t\t}\n\t\t\t\tapplyPendingReasoningDetail(block);\n\t\t\t\treturn block;\n\t\t\t};\n\n\t\t\tfor await (const chunk of openaiStream) {\n\t\t\t\tif (!chunk || typeof chunk !== \"object\") continue;\n\n\t\t\t\t// OpenAI documents ChatCompletionChunk.id as the unique chat completion identifier,\n\t\t\t\t// and each chunk in a streamed completion carries the same id.\n\t\t\t\toutput.responseId ||= chunk.id;\n\t\t\t\tif (typeof chunk.model === \"string\" && chunk.model.length > 0 && chunk.model !== model.id) {\n\t\t\t\t\toutput.responseModel ||= chunk.model;\n\t\t\t\t}\n\t\t\t\tif (chunk.usage) {\n\t\t\t\t\toutput.usage = parseChunkUsage(chunk.usage, model);\n\t\t\t\t}\n\n\t\t\t\tconst choice = Array.isArray(chunk.choices) ? chunk.choices[0] : undefined;\n\t\t\t\tif (!choice) continue;\n\n\t\t\t\t// Fallback: some providers (e.g., Moonshot) return usage\n\t\t\t\t// in choice.usage instead of the standard chunk.usage\n\t\t\t\tif (!chunk.usage && (choice as any).usage) {\n\t\t\t\t\toutput.usage = parseChunkUsage((choice as any).usage, model);\n\t\t\t\t}\n\n\t\t\t\tif (choice.finish_reason) {\n\t\t\t\t\tconst finishReasonResult = mapStopReason(choice.finish_reason);\n\t\t\t\t\toutput.stopReason = finishReasonResult.stopReason;\n\t\t\t\t\tif (finishReasonResult.errorMessage) {\n\t\t\t\t\t\toutput.errorMessage = finishReasonResult.errorMessage;\n\t\t\t\t\t}\n\t\t\t\t\thasFinishReason = true;\n\t\t\t\t}\n\n\t\t\t\tif (choice.delta) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tchoice.delta.content !== null &&\n\t\t\t\t\t\tchoice.delta.content !== undefined &&\n\t\t\t\t\t\tchoice.delta.content.length > 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tappendTextDelta(thinkingTagFilter.push(choice.delta.content));\n\t\t\t\t\t}\n\n\t\t\t\t\t// Some endpoints return reasoning in reasoning_content (llama.cpp),\n\t\t\t\t\t// or reasoning (other openai compatible endpoints)\n\t\t\t\t\t// Use the first non-empty reasoning field to avoid duplication\n\t\t\t\t\t// (e.g., chutes.ai returns both reasoning_content and reasoning with same content)\n\t\t\t\t\tconst reasoningFields = [\"reasoning_content\", \"reasoning\", \"reasoning_text\"];\n\t\t\t\t\tconst deltaFields = choice.delta as Record<string, unknown>;\n\t\t\t\t\tlet foundReasoningField: string | null = null;\n\t\t\t\t\tfor (const field of reasoningFields) {\n\t\t\t\t\t\tconst value = deltaFields[field];\n\t\t\t\t\t\tif (typeof value === \"string\" && value.length > 0) {\n\t\t\t\t\t\t\tfoundReasoningField = field;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tfoundReasoningField &&\n\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t(isMiniMaxModel(model) || compat.thinkingFormat === \"minimax\") &&\n\t\t\t\t\t\t\t(!options?.reasoningEffort || model.reasoning === false)\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst delta = deltaFields[foundReasoningField];\n\t\t\t\t\t\tif (typeof delta === \"string\" && delta.length > 0) {\n\t\t\t\t\t\t\tconst thinkingSignature =\n\t\t\t\t\t\t\t\tmodel.provider === \"opencode-go\" && foundReasoningField === \"reasoning\"\n\t\t\t\t\t\t\t\t\t? \"reasoning_content\"\n\t\t\t\t\t\t\t\t\t: foundReasoningField;\n\t\t\t\t\t\t\tconst block = ensureThinkingBlock(thinkingSignature);\n\t\t\t\t\t\t\tblock.thinking += delta;\n\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\t\t\t\tdelta,\n\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (choice?.delta?.tool_calls) {\n\t\t\t\t\t\tfor (const toolCall of choice.delta.tool_calls) {\n\t\t\t\t\t\t\tconst block = ensureToolCallBlock(toolCall);\n\t\t\t\t\t\t\tif (!block.id && toolCall.id) {\n\t\t\t\t\t\t\t\tblock.id = toolCall.id;\n\t\t\t\t\t\t\t\ttoolCallBlocksById.set(toolCall.id, block);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!block.name && toolCall.function?.name) {\n\t\t\t\t\t\t\t\tblock.name = toolCall.function.name;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlet delta = \"\";\n\t\t\t\t\t\t\tif (toolCall.function?.arguments) {\n\t\t\t\t\t\t\t\tdelta = toolCall.function.arguments;\n\t\t\t\t\t\t\t\tblock.partialArgs = (block.partialArgs ?? \"\") + toolCall.function.arguments;\n\t\t\t\t\t\t\t\tblock.arguments = parseStreamingJson(block.partialArgs);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\t\t\t\tdelta,\n\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst reasoningDetails = (choice.delta as { reasoning_details?: unknown }).reasoning_details;\n\t\t\t\t\tif (Array.isArray(reasoningDetails)) {\n\t\t\t\t\t\tfor (const detail of reasoningDetails) {\n\t\t\t\t\t\t\tif (isEncryptedReasoningDetail(detail)) {\n\t\t\t\t\t\t\t\tconst serializedDetail = JSON.stringify(detail);\n\t\t\t\t\t\t\t\tconst matchingToolCall = toolCallBlocksById.get(detail.id);\n\t\t\t\t\t\t\t\tif (matchingToolCall) {\n\t\t\t\t\t\t\t\t\tmatchingToolCall.thoughtSignature = serializedDetail;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tpendingReasoningDetailsByToolCallId.set(detail.id, serializedDetail);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tappendTextDelta(thinkingTagFilter.flush());\n\n\t\t\tfor (const block of blocks) {\n\t\t\t\tfinishBlock(block);\n\t\t\t}\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"aborted\") {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\t\t\tif (!hasFinishReason && !compat.supportsFinishReason) {\n\t\t\t\tif (hasIncompleteToolCallArguments) {\n\t\t\t\t\tthrow new Error(\"Stream ended without finish_reason and with incomplete tool call arguments\");\n\t\t\t\t}\n\t\t\t\toutput.stopReason = output.content.some((block) => block.type === \"toolCall\") ? \"toolUse\" : \"stop\";\n\t\t\t}\n\t\t\tif (output.stopReason === \"error\") {\n\t\t\t\tthrow new Error(output.errorMessage || \"Provider returned an error stop reason\");\n\t\t\t}\n\t\t\tif (compat.supportsFinishReason && !hasFinishReason) {\n\t\t\t\tthrow new Error(\"Stream ended without finish_reason\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tdelete (block as { index?: number }).index;\n\t\t\t\t// Streaming scratch buffers are only used during parsing; never persist them.\n\t\t\t\tdelete (block as { partialArgs?: string }).partialArgs;\n\t\t\t\tdelete (block as { streamIndex?: number }).streamIndex;\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tconst normalized = normalizeProviderError(error);\n\t\t\toutput.errorMetadata = normalized.errorMetadata;\n\t\t\toutput.errorMessage = formatProviderError(normalized);\n\t\t\t// Some providers via OpenRouter give additional information in this field.\n\t\t\t// normalizeProviderError already stringifies the parsed body (error.error)\n\t\t\t// into errorMessage, so only append the raw metadata when it is not already\n\t\t\t// present to avoid double-printing it.\n\t\t\tconst rawMetadata = (error as any)?.error?.metadata?.raw;\n\t\t\tif (rawMetadata && !output.errorMessage.includes(String(rawMetadata))) {\n\t\t\t\toutput.errorMessage += `\\n${rawMetadata}`;\n\t\t\t}\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimpleOpenAICompletions: StreamFunction<\"openai-completions\", SimpleStreamOptions> = (\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider, options?.env);\n\tif (!apiKey && model.authHeader !== false) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\n\tconst base = buildBaseOptions(model, context, options, apiKey ?? \"\");\n\tconst clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;\n\tconst reasoningEffort = clampedReasoning === \"off\" ? undefined : clampedReasoning;\n\tconst toolChoice = (options as OpenAICompletionsOptions | undefined)?.toolChoice;\n\n\treturn streamOpenAICompletions(model, context, {\n\t\t...base,\n\t\treasoningEffort,\n\t\ttoolChoice,\n\t} satisfies OpenAICompletionsOptions);\n};\n\nfunction createClient(\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\tapiKey?: string,\n\toptionsHeaders?: Record<string, string>,\n\tsessionId?: string,\n\tcompat: ResolvedOpenAICompletionsCompat = getCompat(model),\n\tenv?: ProviderEnv,\n) {\n\tconst noAuth = model.authHeader === false;\n\tif (!apiKey && !noAuth) {\n\t\tconst configuredApiKey = getProviderEnvValue(\"OPENAI_API_KEY\", env);\n\t\tif (!configuredApiKey) {\n\t\t\tthrow new Error(\n\t\t\t\t\"OpenAI API key is required. Set OPENAI_API_KEY environment variable or pass it as an argument.\",\n\t\t\t);\n\t\t}\n\t\tapiKey = configuredApiKey;\n\t}\n\tif (!apiKey) apiKey = \"merc-no-auth\";\n\n\tconst headers = { ...model.headers };\n\tif (model.provider === \"github-copilot\") {\n\t\tconst hasImages = hasCopilotVisionInput(context.messages);\n\t\tconst copilotHeaders = buildCopilotDynamicHeaders({\n\t\t\tmessages: context.messages,\n\t\t\thasImages,\n\t\t});\n\t\tObject.assign(headers, copilotHeaders);\n\t}\n\n\tif (sessionId && compat.sendSessionAffinityHeaders) {\n\t\tif (compat.sessionAffinityFormat === \"openrouter\") {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t} else {\n\t\t\tif (compat.sessionAffinityFormat === \"openai\") headers.session_id = sessionId;\n\t\t\theaders[\"x-client-request-id\"] = sessionId;\n\t\t\theaders[\"x-session-affinity\"] = sessionId;\n\t\t}\n\t}\n\n\t// Merge options headers last so they can override defaults\n\tif (optionsHeaders) {\n\t\tObject.assign(headers, optionsHeaders);\n\t}\n\n\tconst defaultHeaders = noAuth\n\t\t? { ...headers, Authorization: null }\n\t\t: model.provider === \"cloudflare-ai-gateway\"\n\t\t\t? {\n\t\t\t\t\t...headers,\n\t\t\t\t\tAuthorization: headers.Authorization ?? null,\n\t\t\t\t\t\"cf-aig-authorization\": `Bearer ${apiKey}`,\n\t\t\t\t}\n\t\t\t: headers;\n\n\treturn new OpenAI({\n\t\tapiKey,\n\t\tbaseURL: isCloudflareProvider(model.provider) ? resolveCloudflareBaseUrl(model, env) : model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tdefaultHeaders,\n\t});\n}\n\nfunction buildParams(\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\toptions?: OpenAICompletionsOptions,\n\tcompat: ResolvedOpenAICompletionsCompat = getCompat(model),\n\tcacheRetention: CacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env),\n) {\n\tconst messages = convertMessages(model, context, compat);\n\tconst cacheControl = getCompatCacheControl(compat, cacheRetention);\n\n\tconst params: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {\n\t\tmodel: model.id,\n\t\tmessages,\n\t\tstream: true,\n\t\tprompt_cache_key:\n\t\t\t(model.baseUrl.includes(\"api.openai.com\") && cacheRetention !== \"none\") ||\n\t\t\t(cacheRetention === \"long\" && compat.supportsLongCacheRetention)\n\t\t\t\t? clampOpenAIPromptCacheKey(options?.sessionId)\n\t\t\t\t: undefined,\n\t\tprompt_cache_retention: cacheRetention === \"long\" && compat.supportsLongCacheRetention ? \"24h\" : undefined,\n\t};\n\n\tif (isOpenRouterImageGenerationModel(model)) {\n\t\tReflect.set(params, \"modalities\", [\"image\"]);\n\t}\n\n\tif (compat.supportsUsageInStreaming !== false) {\n\t\t(params as any).stream_options = { include_usage: true };\n\t}\n\n\tif (compat.supportsStore) {\n\t\tparams.store = false;\n\t}\n\n\tif (options?.maxTokens) {\n\t\tif (compat.maxTokensField === \"max_tokens\") {\n\t\t\t(params as any).max_tokens = options.maxTokens;\n\t\t} else {\n\t\t\tparams.max_completion_tokens = options.maxTokens;\n\t\t}\n\t}\n\n\tif (options?.temperature !== undefined) {\n\t\tparams.temperature = options.temperature;\n\t}\n\n\tif (!isOpenRouterImageGenerationModel(model) && context.tools && context.tools.length > 0) {\n\t\tparams.tools = convertTools(context.tools, compat);\n\t\tif (compat.zaiToolStream) {\n\t\t\t(params as any).tool_stream = true;\n\t\t}\n\t} else if (!isOpenRouterImageGenerationModel(model) && hasToolHistory(context.messages)) {\n\t\t// Anthropic (via LiteLLM/proxy) requires tools param when conversation has tool_calls/tool_results\n\t\tparams.tools = [];\n\t}\n\n\tif (cacheControl) {\n\t\tapplyAnthropicCacheControl(messages, params.tools, cacheControl);\n\t}\n\n\tif (options?.toolChoice && params.tools?.length) {\n\t\tparams.tool_choice = options.toolChoice;\n\t}\n\n\tif (compat.thinkingFormat === \"zai\" && model.reasoning) {\n\t\tconst zaiParams = params as Omit<typeof params, \"reasoning_effort\"> & {\n\t\t\tthinking?: { type: \"enabled\" | \"disabled\"; clear_thinking?: boolean };\n\t\t\treasoning_effort?: string;\n\t\t};\n\t\tzaiParams.thinking = options?.reasoningEffort ? { type: \"enabled\", clear_thinking: false } : { type: \"disabled\" };\n\t\tif (options?.reasoningEffort && compat.supportsReasoningEffort) {\n\t\t\tconst mappedEffort = model.thinkingLevelMap?.[options.reasoningEffort];\n\t\t\tconst effort = mappedEffort === undefined ? options.reasoningEffort : mappedEffort;\n\t\t\tif (typeof effort === \"string\") {\n\t\t\t\tzaiParams.reasoning_effort = effort;\n\t\t\t}\n\t\t}\n\t} else if (compat.thinkingFormat === \"minimax\" || isMiniMaxModel(model)) {\n\t\tconst minimaxParams = params as typeof params & {\n\t\t\tthinking?: { type: \"adaptive\" | \"disabled\" };\n\t\t\treasoning_split?: boolean;\n\t\t};\n\t\tminimaxParams.thinking = { type: options?.reasoningEffort ? \"adaptive\" : \"disabled\" };\n\t\tminimaxParams.reasoning_split = true;\n\t} else if (compat.thinkingFormat === \"qwen\" && model.reasoning) {\n\t\t(params as any).enable_thinking = !!options?.reasoningEffort;\n\t} else if (compat.thinkingFormat === \"qwen-chat-template\" && model.reasoning) {\n\t\t(params as any).chat_template_kwargs = {\n\t\t\tenable_thinking: !!options?.reasoningEffort,\n\t\t\tpreserve_thinking: true,\n\t\t};\n\t} else if (compat.thinkingFormat === \"deepseek\" && model.reasoning) {\n\t\tif (options?.reasoningEffort) {\n\t\t\t(params as any).thinking = { type: \"enabled\" };\n\t\t} else if (model.thinkingLevelMap?.off !== null) {\n\t\t\t(params as any).thinking = { type: \"disabled\" };\n\t\t}\n\t\tif (options?.reasoningEffort && compat.supportsReasoningEffort) {\n\t\t\t(params as any).reasoning_effort =\n\t\t\t\tmodel.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n\t\t}\n\t} else if (compat.thinkingFormat === \"ant-ling\" && model.reasoning && options?.reasoningEffort) {\n\t\tconst effort = model.thinkingLevelMap?.[options.reasoningEffort];\n\t\tif (typeof effort === \"string\") {\n\t\t\t(params as typeof params & { reasoning?: { effort: string } }).reasoning = { effort };\n\t\t}\n\t} else if (compat.thinkingFormat === \"openrouter\" && model.reasoning) {\n\t\t// OpenRouter normalizes reasoning across providers via a nested reasoning object.\n\t\tconst openRouterParams = params as typeof params & { reasoning?: { effort?: string } };\n\t\tif (options?.reasoningEffort) {\n\t\t\topenRouterParams.reasoning = {\n\t\t\t\teffort: model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort,\n\t\t\t};\n\t\t} else if (model.thinkingLevelMap?.off !== null) {\n\t\t\topenRouterParams.reasoning = { effort: model.thinkingLevelMap?.off ?? \"none\" };\n\t\t}\n\t} else if (options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {\n\t\t// OpenAI-style reasoning_effort\n\t\t(params as any).reasoning_effort = model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n\t} else if (!options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {\n\t\tconst offValue = model.thinkingLevelMap?.off;\n\t\tif (typeof offValue === \"string\") {\n\t\t\t(params as any).reasoning_effort = offValue;\n\t\t}\n\t}\n\n\t// OpenRouter provider routing preferences\n\tif (model.baseUrl.includes(\"openrouter.ai\") && model.compat?.openRouterRouting) {\n\t\t(params as any).provider = model.compat.openRouterRouting;\n\t}\n\n\t// Vercel AI Gateway provider routing preferences\n\tif (model.baseUrl.includes(\"ai-gateway.vercel.sh\") && model.compat?.vercelGatewayRouting) {\n\t\tconst routing = model.compat.vercelGatewayRouting;\n\t\tif (routing.only || routing.order) {\n\t\t\tconst gatewayOptions: Record<string, string[]> = {};\n\t\t\tif (routing.only) gatewayOptions.only = routing.only;\n\t\t\tif (routing.order) gatewayOptions.order = routing.order;\n\t\t\t(params as any).providerOptions = { gateway: gatewayOptions };\n\t\t}\n\t}\n\n\treturn params;\n}\n\nfunction getCompatCacheControl(\n\tcompat: ResolvedOpenAICompletionsCompat,\n\tcacheRetention: CacheRetention,\n): OpenAICompatCacheControl | undefined {\n\tif (compat.cacheControlFormat !== \"anthropic\" || cacheRetention === \"none\") {\n\t\treturn undefined;\n\t}\n\n\tconst ttl = cacheRetention === \"long\" && compat.supportsLongCacheRetention ? \"1h\" : undefined;\n\treturn { type: \"ephemeral\", ...(ttl ? { ttl } : {}) };\n}\n\nfunction applyAnthropicCacheControl(\n\tmessages: ChatCompletionMessageParam[],\n\ttools: OpenAI.Chat.Completions.ChatCompletionTool[] | undefined,\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\taddCacheControlToSystemPrompt(messages, cacheControl);\n\taddCacheControlToLastTool(tools, cacheControl);\n\taddCacheControlToLastConversationMessage(messages, cacheControl);\n}\n\nfunction addCacheControlToSystemPrompt(\n\tmessages: ChatCompletionMessageParam[],\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\tfor (const message of messages) {\n\t\tif (message.role === \"system\" || message.role === \"developer\") {\n\t\t\taddCacheControlToInstructionMessage(message, cacheControl);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nfunction addCacheControlToLastConversationMessage(\n\tmessages: ChatCompletionMessageParam[],\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst message = messages[i];\n\t\tif (message.role === \"user\" || message.role === \"assistant\" || message.role === \"tool\") {\n\t\t\tif (addCacheControlToMessage(message, cacheControl)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction addCacheControlToLastTool(\n\ttools: OpenAI.Chat.Completions.ChatCompletionTool[] | undefined,\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\tif (!tools || tools.length === 0) {\n\t\treturn;\n\t}\n\n\tconst lastTool = tools[tools.length - 1] as ChatCompletionToolWithCacheControl;\n\tlastTool.cache_control = cacheControl;\n}\n\nfunction addCacheControlToInstructionMessage(\n\tmessage: ChatCompletionInstructionMessageParam,\n\tcacheControl: OpenAICompatCacheControl,\n): boolean {\n\treturn addCacheControlToTextContent(message, cacheControl);\n}\n\nfunction addCacheControlToMessage(\n\tmessage: ChatCompletionMessageParam,\n\tcacheControl: OpenAICompatCacheControl,\n): boolean {\n\tif (message.role === \"user\" || message.role === \"assistant\" || message.role === \"tool\") {\n\t\treturn addCacheControlToTextContent(message, cacheControl);\n\t}\n\treturn false;\n}\n\nfunction addCacheControlToTextContent(\n\tmessage:\n\t\t| ChatCompletionInstructionMessageParam\n\t\t| ChatCompletionAssistantMessageParam\n\t\t| ChatCompletionToolMessageParam\n\t\t| Extract<ChatCompletionMessageParam, { role: \"user\" }>,\n\tcacheControl: OpenAICompatCacheControl,\n): boolean {\n\tconst content = message.content;\n\tif (typeof content === \"string\") {\n\t\tif (content.length === 0) {\n\t\t\treturn false;\n\t\t}\n\t\tmessage.content = [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: content,\n\t\t\t\tcache_control: cacheControl,\n\t\t\t},\n\t\t] as ChatCompletionTextPartWithCacheControl[];\n\t\treturn true;\n\t}\n\n\tif (!Array.isArray(content)) {\n\t\treturn false;\n\t}\n\n\tfor (let i = content.length - 1; i >= 0; i--) {\n\t\tconst part = content[i];\n\t\tif (part?.type === \"text\") {\n\t\t\tconst textPart = part as ChatCompletionTextPartWithCacheControl;\n\t\t\ttextPart.cache_control = cacheControl;\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nexport function convertMessages(\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\tcompat: ResolvedOpenAICompletionsCompat,\n): ChatCompletionMessageParam[] {\n\tconst params: ChatCompletionMessageParam[] = [];\n\n\tconst normalizeToolCallId = createProviderToolCallIdNormalizer(model);\n\n\tconst transformedMessages = transformMessages(context.messages, model, (id) => normalizeToolCallId(id));\n\n\tif (context.systemPrompt) {\n\t\tconst useDeveloperRole = model.reasoning && compat.supportsDeveloperRole;\n\t\tconst role = useDeveloperRole ? \"developer\" : \"system\";\n\t\tparams.push({ role: role, content: sanitizeSurrogates(context.systemPrompt) });\n\t}\n\n\tlet lastRole: string | null = null;\n\n\tfor (let i = 0; i < transformedMessages.length; i++) {\n\t\tconst msg = transformedMessages[i];\n\t\t// Some providers don't allow user messages directly after tool results\n\t\t// Insert a synthetic assistant message to bridge the gap\n\t\tif (compat.requiresAssistantAfterToolResult && lastRole === \"toolResult\" && msg.role === \"user\") {\n\t\t\tparams.push({\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: \"I have processed the tool results.\",\n\t\t\t});\n\t\t}\n\n\t\tif (msg.role === \"user\") {\n\t\t\tif (typeof msg.content === \"string\") {\n\t\t\t\tparams.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: sanitizeSurrogates(msg.content),\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst content: ChatCompletionContentPart[] = msg.content\n\t\t\t\t\t.filter((item) => item.type !== \"text\" || item.text.length > 0)\n\t\t\t\t\t.map((item): ChatCompletionContentPart => {\n\t\t\t\t\t\tif (item.type === \"text\") {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\ttext: sanitizeSurrogates(item.text),\n\t\t\t\t\t\t\t} satisfies ChatCompletionContentPartText;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\ttype: \"image_url\",\n\t\t\t\t\t\t\t\timage_url: {\n\t\t\t\t\t\t\t\t\turl: `data:${item.mimeType};base64,${item.data}`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t} satisfies ChatCompletionContentPartImage;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tif (content.length === 0) continue;\n\t\t\t\tparams.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (msg.role === \"assistant\") {\n\t\t\t// Some providers don't accept null content, use empty string instead\n\t\t\tconst assistantMsg: ChatCompletionAssistantMessageParam = {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: compat.requiresAssistantAfterToolResult ? \"\" : null,\n\t\t\t};\n\n\t\t\tconst assistantTextParts = msg.content\n\t\t\t\t.filter(isTextContentBlock)\n\t\t\t\t.filter((block) => block.text.trim().length > 0)\n\t\t\t\t.map(\n\t\t\t\t\t(block) =>\n\t\t\t\t\t\t({\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: sanitizeSurrogates(block.text),\n\t\t\t\t\t\t}) satisfies ChatCompletionContentPartText,\n\t\t\t\t);\n\t\t\tconst assistantText = assistantTextParts.map((part) => part.text).join(\"\");\n\n\t\t\tconst nonEmptyThinkingBlocks = msg.content\n\t\t\t\t.filter(isThinkingContentBlock)\n\t\t\t\t.filter((block) => block.thinking.trim().length > 0);\n\t\t\tif (nonEmptyThinkingBlocks.length > 0) {\n\t\t\t\tif (compat.requiresThinkingAsText) {\n\t\t\t\t\t// Convert thinking blocks to plain text (no tags to avoid model mimicking them)\n\t\t\t\t\tconst thinkingText = nonEmptyThinkingBlocks\n\t\t\t\t\t\t.map((block) => sanitizeSurrogates(block.thinking))\n\t\t\t\t\t\t.join(\"\\n\\n\");\n\t\t\t\t\tassistantMsg.content = [{ type: \"text\", text: thinkingText }, ...assistantTextParts];\n\t\t\t\t} else {\n\t\t\t\t\t// Always send assistant content as a plain string (OpenAI Chat Completions\n\t\t\t\t\t// API standard format). Sending as an array of {type:\"text\", text:\"...\"}\n\t\t\t\t\t// objects is non-standard and causes some models (e.g. DeepSeek V3.2 via\n\t\t\t\t\t// NVIDIA NIM) to mirror the content-block structure literally in their\n\t\t\t\t\t// output, producing recursive nesting like [{'type':'text','text':'[{...}]'}].\n\t\t\t\t\tif (assistantText.length > 0) {\n\t\t\t\t\t\tassistantMsg.content = assistantText;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Use the signature from the first thinking block if available (for llama.cpp server + gpt-oss)\n\t\t\t\t\tlet signature = nonEmptyThinkingBlocks[0].thinkingSignature;\n\t\t\t\t\tif (model.provider === \"opencode-go\" && signature === \"reasoning\") {\n\t\t\t\t\t\tsignature = \"reasoning_content\";\n\t\t\t\t\t}\n\t\t\t\t\tif (signature && signature.length > 0) {\n\t\t\t\t\t\t(assistantMsg as any)[signature] = nonEmptyThinkingBlocks.map((block) => block.thinking).join(\"\\n\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (assistantText.length > 0) {\n\t\t\t\t// Always send assistant content as a plain string (OpenAI Chat Completions\n\t\t\t\t// API standard format). Sending as an array of {type:\"text\", text:\"...\"}\n\t\t\t\t// objects is non-standard and causes some models (e.g. DeepSeek V3.2 via\n\t\t\t\t// NVIDIA NIM) to mirror the content-block structure literally in their\n\t\t\t\t// output, producing recursive nesting like [{'type':'text','text':'[{...}]'}].\n\t\t\t\tassistantMsg.content = assistantText;\n\t\t\t}\n\n\t\t\tconst toolCalls = msg.content.filter(isToolCallBlock);\n\t\t\tif (toolCalls.length > 0) {\n\t\t\t\tassistantMsg.tool_calls = toolCalls.map((tc) => ({\n\t\t\t\t\tid: tc.id,\n\t\t\t\t\ttype: \"function\" as const,\n\t\t\t\t\tfunction: {\n\t\t\t\t\t\tname: tc.name,\n\t\t\t\t\t\targuments: JSON.stringify(tc.arguments),\n\t\t\t\t\t},\n\t\t\t\t}));\n\t\t\t\tconst reasoningDetails = toolCalls\n\t\t\t\t\t.filter((tc) => tc.thoughtSignature)\n\t\t\t\t\t.map((tc) => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\treturn JSON.parse(tc.thoughtSignature!);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.filter(Boolean);\n\t\t\t\tif (reasoningDetails.length > 0) {\n\t\t\t\t\t(assistantMsg as any).reasoning_details = reasoningDetails;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (\n\t\t\t\tcompat.requiresReasoningContentOnAssistantMessages &&\n\t\t\t\tmodel.reasoning &&\n\t\t\t\t(assistantMsg as { reasoning_content?: string }).reasoning_content === undefined\n\t\t\t) {\n\t\t\t\t(assistantMsg as { reasoning_content?: string }).reasoning_content = \"\";\n\t\t\t}\n\t\t\t// Skip assistant messages that have no content and no tool calls.\n\t\t\t// Some providers require \"either content or tool_calls, but not none\".\n\t\t\t// Other providers also don't accept empty assistant messages.\n\t\t\t// This handles aborted assistant responses that got no content.\n\t\t\tconst content = assistantMsg.content;\n\t\t\tconst hasContent =\n\t\t\t\tcontent !== null &&\n\t\t\t\tcontent !== undefined &&\n\t\t\t\t(typeof content === \"string\" ? content.length > 0 : content.length > 0);\n\t\t\tif (!hasContent && !assistantMsg.tool_calls) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tparams.push(assistantMsg);\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\tconst imageBlocks: Array<{ type: \"image_url\"; image_url: { url: string } }> = [];\n\t\t\tlet j = i;\n\n\t\t\tfor (; j < transformedMessages.length && transformedMessages[j].role === \"toolResult\"; j++) {\n\t\t\t\tconst toolMsg = transformedMessages[j] as ToolResultMessage;\n\n\t\t\t\t// Extract text and image content\n\t\t\t\tconst textResult = toolMsg.content\n\t\t\t\t\t.filter(isTextContentBlock)\n\t\t\t\t\t.map((block) => block.text)\n\t\t\t\t\t.join(\"\\n\");\n\t\t\t\tconst hasImages = toolMsg.content.some((c) => c.type === \"image\");\n\n\t\t\t\t// Always send tool result with text (or placeholder if only images)\n\t\t\t\tconst hasText = textResult.length > 0;\n\t\t\t\tconst toolResultText = hasText ? textResult : hasImages ? \"(see attached image)\" : \"(no tool output)\";\n\t\t\t\t// Some providers require the 'name' field in tool results\n\t\t\t\tconst toolResultMsg: ChatCompletionToolMessageParam = {\n\t\t\t\t\trole: \"tool\",\n\t\t\t\t\tcontent: sanitizeSurrogates(toolResultText),\n\t\t\t\t\ttool_call_id: toolMsg.toolCallId,\n\t\t\t\t};\n\t\t\t\tif (compat.requiresToolResultName && toolMsg.toolName) {\n\t\t\t\t\t(toolResultMsg as any).name = toolMsg.toolName;\n\t\t\t\t}\n\t\t\t\tparams.push(toolResultMsg);\n\n\t\t\t\tif (hasImages && model.input.includes(\"image\")) {\n\t\t\t\t\tfor (const block of toolMsg.content) {\n\t\t\t\t\t\tif (isImageContentBlock(block)) {\n\t\t\t\t\t\t\timageBlocks.push({\n\t\t\t\t\t\t\t\ttype: \"image_url\",\n\t\t\t\t\t\t\t\timage_url: {\n\t\t\t\t\t\t\t\t\turl: `data:${block.mimeType};base64,${block.data}`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ti = j - 1;\n\n\t\t\tif (imageBlocks.length > 0) {\n\t\t\t\tif (compat.requiresAssistantAfterToolResult) {\n\t\t\t\t\tparams.push({\n\t\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\t\tcontent: \"I have processed the tool results.\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tparams.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: \"Attached image(s) from tool result:\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...imageBlocks,\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\tlastRole = \"user\";\n\t\t\t} else {\n\t\t\t\tlastRole = \"toolResult\";\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tlastRole = msg.role;\n\t}\n\n\treturn params;\n}\n\nfunction convertTools(\n\ttools: Tool[],\n\tcompat: ResolvedOpenAICompletionsCompat,\n): OpenAI.Chat.Completions.ChatCompletionTool[] {\n\treturn tools.map((tool) => ({\n\t\ttype: \"function\",\n\t\tfunction: {\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: tool.parameters as any, // TypeBox already generates JSON Schema\n\t\t\t// Only include strict if provider supports it. Some reject unknown fields.\n\t\t\t...(compat.supportsStrictMode !== false && { strict: false }),\n\t\t},\n\t}));\n}\n\nfunction parseChunkUsage(\n\trawUsage: {\n\t\tprompt_tokens?: number;\n\t\tcompletion_tokens?: number;\n\t\tcached_tokens?: number;\n\t\tprompt_cache_hit_tokens?: number;\n\t\tprompt_tokens_details?: { cached_tokens?: number; cache_write_tokens?: number };\n\t},\n\tmodel: Model<\"openai-completions\">,\n): AssistantMessage[\"usage\"] {\n\tconst promptTokens = rawUsage.prompt_tokens || 0;\n\tconst cacheReadTokens =\n\t\trawUsage.prompt_tokens_details?.cached_tokens ?? rawUsage.prompt_cache_hit_tokens ?? rawUsage.cached_tokens ?? 0;\n\tconst cacheWriteTokens = rawUsage.prompt_tokens_details?.cache_write_tokens || 0;\n\n\t// Follow documented OpenAI/OpenRouter semantics: cached_tokens is cache-read\n\t// tokens (hits). Providers disagree on placement: OpenAI/OpenRouter use\n\t// prompt_tokens_details.cached_tokens, DeepSeek uses prompt_cache_hit_tokens,\n\t// and Kimi documents top-level usage.cached_tokens on the final usage chunk.\n\t// OpenAI does not document or emit cache_write_tokens, but\n\t// OpenRouter-compatible providers can include it as a separate write count.\n\t// OpenRouter's own provider/tests affirm the separate mapping:\n\t// https://github.com/OpenRouterTeam/ai-sdk-provider/pull/409\n\t// Do not subtract writes from cached_tokens, otherwise spec-compliant\n\t// providers are under-reported. DS4 mirrors this contract too:\n\t// https://github.com/antirez/ds4/pull/29\n\tconst input = Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens);\n\t// OpenAI completion_tokens already includes reasoning_tokens.\n\tconst outputTokens = rawUsage.completion_tokens || 0;\n\tconst usage: AssistantMessage[\"usage\"] = {\n\t\tinput,\n\t\toutput: outputTokens,\n\t\tcacheRead: cacheReadTokens,\n\t\tcacheWrite: cacheWriteTokens,\n\t\ttotalTokens: input + outputTokens + cacheReadTokens + cacheWriteTokens,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n\tcalculateCost(model, usage);\n\treturn usage;\n}\n\nfunction mapStopReason(reason: ChatCompletionChunk.Choice[\"finish_reason\"] | string): {\n\tstopReason: StopReason;\n\terrorMessage?: string;\n} {\n\tif (reason === null) return { stopReason: \"stop\" };\n\tswitch (reason) {\n\t\tcase \"stop\":\n\t\tcase \"end\":\n\t\t\treturn { stopReason: \"stop\" };\n\t\tcase \"length\":\n\t\t\treturn { stopReason: \"length\" };\n\t\tcase \"function_call\":\n\t\tcase \"tool_calls\":\n\t\t\treturn { stopReason: \"toolUse\" };\n\t\tcase \"content_filter\":\n\t\t\treturn { stopReason: \"error\", errorMessage: \"Provider finish_reason: content_filter\" };\n\t\tcase \"network_error\":\n\t\t\treturn { stopReason: \"error\", errorMessage: \"Provider finish_reason: network_error\" };\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tstopReason: \"error\",\n\t\t\t\terrorMessage: `Provider finish_reason: ${reason}`,\n\t\t\t};\n\t}\n}\n\n/**\n * Detect compatibility settings from provider and baseUrl for known providers.\n * Provider takes precedence over URL-based detection since it's explicitly configured.\n * Returns a fully resolved OpenAICompletionsCompat object with all fields set.\n */\nfunction detectCompat(model: Model<\"openai-completions\">): ResolvedOpenAICompletionsCompat {\n\tconst provider = model.provider;\n\tconst baseUrl = model.baseUrl;\n\n\tconst isZai = provider === \"zai\" || baseUrl.includes(\"api.z.ai\");\n\tconst isMoonshot = provider === \"moonshotai\" || provider === \"moonshotai-cn\" || baseUrl.includes(\"api.moonshot.\");\n\tconst isCloudflareWorkersAI = provider === \"cloudflare-workers-ai\" || baseUrl.includes(\"api.cloudflare.com\");\n\tconst isCloudflareAiGateway = provider === \"cloudflare-ai-gateway\" || baseUrl.includes(\"gateway.ai.cloudflare.com\");\n\tconst isAntLing = provider === \"ant-ling\" || baseUrl.includes(\"api.ant-ling.com\");\n\tconst isMiniMax = isMiniMaxModel(model);\n\tconst isDeepSeek = provider === \"deepseek\" || baseUrl.toLowerCase().includes(\"deepseek.com\");\n\n\tconst isNonStandard =\n\t\tprovider === \"cerebras\" ||\n\t\tbaseUrl.includes(\"cerebras.ai\") ||\n\t\tprovider === \"xai\" ||\n\t\tbaseUrl.includes(\"api.x.ai\") ||\n\t\tbaseUrl.includes(\"chutes.ai\") ||\n\t\tisDeepSeek ||\n\t\tisZai ||\n\t\tisMoonshot ||\n\t\tprovider === \"opencode\" ||\n\t\tbaseUrl.includes(\"opencode.ai\") ||\n\t\tisCloudflareWorkersAI ||\n\t\tisCloudflareAiGateway ||\n\t\tisAntLing;\n\n\t// Z.AI ignores max_completion_tokens, so its output cap only applies through max_tokens.\n\tconst isZaiMaxTokensEndpoint = isZai || provider === \"zai-coding-cn\" || baseUrl.includes(\"open.bigmodel.cn\");\n\tconst useMaxTokens =\n\t\tbaseUrl.includes(\"chutes.ai\") ||\n\t\tisDeepSeek ||\n\t\tisMoonshot ||\n\t\tisCloudflareAiGateway ||\n\t\tisAntLing ||\n\t\tisZaiMaxTokensEndpoint;\n\n\tconst isGrok = provider === \"xai\" || baseUrl.includes(\"api.x.ai\");\n\tconst cacheControlFormat = provider === \"openrouter\" && /^~?anthropic\\//.test(model.id) ? \"anthropic\" : undefined;\n\tconst isOpenRouter = provider === \"openrouter\" || baseUrl.includes(\"openrouter.ai\");\n\n\treturn {\n\t\tsupportsStore: !isNonStandard,\n\t\tsupportsDeveloperRole: !isNonStandard,\n\t\tsupportsReasoningEffort: !isGrok && !isZai && !isMoonshot && !isCloudflareAiGateway && !isAntLing,\n\t\tsupportsUsageInStreaming: true,\n\t\tsupportsFinishReason: true,\n\t\tmaxTokensField: useMaxTokens ? \"max_tokens\" : \"max_completion_tokens\",\n\t\trequiresToolResultName: false,\n\t\trequiresAssistantAfterToolResult: false,\n\t\trequiresThinkingAsText: false,\n\t\trequiresReasoningContentOnAssistantMessages: isDeepSeek,\n\t\tthinkingFormat: isMiniMax\n\t\t\t? \"minimax\"\n\t\t\t: isDeepSeek\n\t\t\t\t? \"deepseek\"\n\t\t\t\t: isZai\n\t\t\t\t\t? \"zai\"\n\t\t\t\t\t: isAntLing\n\t\t\t\t\t\t? \"ant-ling\"\n\t\t\t\t\t\t: provider === \"openrouter\" || baseUrl.includes(\"openrouter.ai\")\n\t\t\t\t\t\t\t? \"openrouter\"\n\t\t\t\t\t\t\t: \"openai\",\n\t\topenRouterRouting: {},\n\t\topenRouterImageGeneration: false,\n\t\tvercelGatewayRouting: {},\n\t\tzaiToolStream: false,\n\t\tsupportsStrictMode: !isMoonshot && !isCloudflareAiGateway,\n\t\tcacheControlFormat,\n\t\tsendSessionAffinityHeaders: isOpenRouter,\n\t\tsessionAffinityFormat: isOpenRouter ? \"openrouter\" : \"openai\",\n\t\tsupportsLongCacheRetention: !(isCloudflareWorkersAI || isCloudflareAiGateway || isAntLing),\n\t};\n}\n\n/**\n * Get resolved compatibility settings for a model.\n * Uses explicit model.compat if provided, otherwise auto-detects from provider/URL.\n */\nfunction getCompat(model: Model<\"openai-completions\">): ResolvedOpenAICompletionsCompat {\n\tconst detected = detectCompat(model);\n\tif (!model.compat) return detected;\n\n\treturn {\n\t\tsupportsStore: model.compat.supportsStore ?? detected.supportsStore,\n\t\tsupportsDeveloperRole: model.compat.supportsDeveloperRole ?? detected.supportsDeveloperRole,\n\t\tsupportsReasoningEffort: model.compat.supportsReasoningEffort ?? detected.supportsReasoningEffort,\n\t\tsupportsUsageInStreaming: model.compat.supportsUsageInStreaming ?? detected.supportsUsageInStreaming,\n\t\tsupportsFinishReason: model.compat.supportsFinishReason ?? detected.supportsFinishReason,\n\t\tmaxTokensField: model.compat.maxTokensField ?? detected.maxTokensField,\n\t\trequiresToolResultName: model.compat.requiresToolResultName ?? detected.requiresToolResultName,\n\t\trequiresAssistantAfterToolResult:\n\t\t\tmodel.compat.requiresAssistantAfterToolResult ?? detected.requiresAssistantAfterToolResult,\n\t\trequiresThinkingAsText: model.compat.requiresThinkingAsText ?? detected.requiresThinkingAsText,\n\t\trequiresReasoningContentOnAssistantMessages:\n\t\t\tmodel.compat.requiresReasoningContentOnAssistantMessages ??\n\t\t\tdetected.requiresReasoningContentOnAssistantMessages,\n\t\tthinkingFormat: isMiniMaxModel(model) ? \"minimax\" : (model.compat.thinkingFormat ?? detected.thinkingFormat),\n\t\topenRouterRouting: model.compat.openRouterRouting ?? {},\n\t\topenRouterImageGeneration: model.compat.openRouterImageGeneration ?? detected.openRouterImageGeneration,\n\t\tvercelGatewayRouting: model.compat.vercelGatewayRouting ?? detected.vercelGatewayRouting,\n\t\tzaiToolStream: model.compat.zaiToolStream ?? detected.zaiToolStream,\n\t\tsupportsStrictMode: model.compat.supportsStrictMode ?? detected.supportsStrictMode,\n\t\tcacheControlFormat: model.compat.cacheControlFormat ?? detected.cacheControlFormat,\n\t\tsendSessionAffinityHeaders: model.compat.sendSessionAffinityHeaders ?? detected.sendSessionAffinityHeaders,\n\t\tsessionAffinityFormat: model.compat.sessionAffinityFormat ?? detected.sessionAffinityFormat,\n\t\tsupportsLongCacheRetention: model.compat.supportsLongCacheRetention ?? detected.supportsLongCacheRetention,\n\t};\n}\n"]}
1
+ {"version":3,"file":"openai-completions.d.ts","sourceRoot":"","sources":["../../src/providers/openai-completions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAQX,0BAA0B,EAG1B,MAAM,sCAAsC,CAAC;AAG9C,OAAO,KAAK,EAGX,OAAO,EAGP,KAAK,EACL,uBAAuB,EAEvB,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAMb,MAAM,aAAa,CAAC;AAmIrB,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC9D,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IAC7F,eAAe,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;CAC1E;AAOD,KAAK,+BAA+B,GAAG,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,oBAAoB,CAAC,GAAG;IACtG,kBAAkB,CAAC,EAAE,uBAAuB,CAAC,oBAAoB,CAAC,CAAC;CACnE,CAAC;AAgDF,eAAO,MAAM,uBAAuB,EAAE,cAAc,CAAC,oBAAoB,EAAE,wBAAwB,CAualG,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CAoBnG,CAAC;AAuUF,wBAAgB,eAAe,CAC9B,KAAK,EAAE,KAAK,CAAC,oBAAoB,CAAC,EAClC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,+BAA+B,GACrC,0BAA0B,EAAE,CAsO9B","sourcesContent":["import OpenAI from \"openai\";\nimport type {\n\tChatCompletion,\n\tChatCompletionAssistantMessageParam,\n\tChatCompletionChunk,\n\tChatCompletionContentPart,\n\tChatCompletionContentPartImage,\n\tChatCompletionContentPartText,\n\tChatCompletionDeveloperMessageParam,\n\tChatCompletionMessageParam,\n\tChatCompletionSystemMessageParam,\n\tChatCompletionToolMessageParam,\n} from \"openai/resources/chat/completions.js\";\nimport { getEnvApiKey } from \"../env-api-keys.js\";\nimport { calculateCost, clampThinkingLevel } from \"../models.js\";\nimport type {\n\tAssistantMessage,\n\tCacheRetention,\n\tContext,\n\tImageContent,\n\tMessage,\n\tModel,\n\tOpenAICompletionsCompat,\n\tProviderEnv,\n\tSimpleStreamOptions,\n\tStopReason,\n\tStreamFunction,\n\tStreamOptions,\n\tTextContent,\n\tThinkingContent,\n\tTool,\n\tToolCall,\n\tToolResultMessage,\n} from \"../types.js\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.js\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.js\";\nimport { headersToRecord } from \"../utils/headers.js\";\nimport { finalizeToolCallArguments, parseStreamingJson } from \"../utils/json-parse.js\";\nimport { getProviderEnvValue } from \"../utils/provider-env.js\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.js\";\nimport { createProviderToolCallIdNormalizer } from \"../utils/tool-call-id.js\";\nimport { isCloudflareProvider, resolveCloudflareBaseUrl } from \"./cloudflare.js\";\nimport { buildCopilotDynamicHeaders, hasCopilotVisionInput } from \"./github-copilot-headers.js\";\nimport { clampOpenAIPromptCacheKey } from \"./openai-prompt-cache.js\";\nimport { buildBaseOptions } from \"./simple-options.js\";\nimport { transformMessages } from \"./transform-messages.js\";\n\n/**\n * Check if conversation messages contain tool calls or tool results.\n * This is needed because Anthropic (via proxy) requires the tools param\n * to be present when messages include tool_calls or tool role messages.\n */\nfunction hasToolHistory(messages: Message[]): boolean {\n\tfor (const msg of messages) {\n\t\tif (msg.role === \"toolResult\") {\n\t\t\treturn true;\n\t\t}\n\t\tif (msg.role === \"assistant\") {\n\t\t\tif (msg.content.some((block) => block.type === \"toolCall\")) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction isTextContentBlock(block: { type: string }): block is TextContent {\n\treturn block.type === \"text\";\n}\n\nfunction isThinkingContentBlock(block: { type: string }): block is ThinkingContent {\n\treturn block.type === \"thinking\";\n}\n\nfunction isToolCallBlock(block: { type: string }): block is ToolCall {\n\treturn block.type === \"toolCall\";\n}\n\nfunction isImageContentBlock(block: { type: string }): block is ImageContent {\n\treturn block.type === \"image\";\n}\n\nfunction isMiniMaxModel(model: Model<\"openai-completions\">): boolean {\n\t// Merc-native: shared gateways carry multiple families; infer MiniMax only from the id.\n\treturn model.id.toLowerCase().includes(\"minimax-m3\");\n}\n\nfunction createThinkingTagFilter(enabled: boolean): { push: (chunk: string) => string; flush: () => string } {\n\tlet buffer = \"\";\n\tlet inThinking = false;\n\tconst openingTag = \"<think\";\n\tconst closingTag = \"</think>\";\n\n\tconst consume = (): string => {\n\t\tlet visible = \"\";\n\t\twhile (buffer.length > 0) {\n\t\t\tconst lower = buffer.toLowerCase();\n\t\t\tif (inThinking) {\n\t\t\t\tconst end = lower.indexOf(closingTag);\n\t\t\t\tif (end < 0) {\n\t\t\t\t\tbuffer = \"\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbuffer = buffer.slice(end + closingTag.length);\n\t\t\t\tinThinking = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst start = lower.indexOf(openingTag);\n\t\t\tif (start < 0) {\n\t\t\t\tconst strayClosing = lower.indexOf(closingTag);\n\t\t\t\tif (strayClosing >= 0) {\n\t\t\t\t\tvisible += buffer.slice(0, strayClosing);\n\t\t\t\t\tbuffer = buffer.slice(strayClosing + closingTag.length);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst partialStart = Math.max(0, buffer.length - openingTag.length + 1);\n\t\t\t\tconst partial = buffer.slice(partialStart).toLowerCase();\n\t\t\t\tconst closingPartialStart = Math.max(0, buffer.length - closingTag.length + 1);\n\t\t\t\tconst closingPartial = buffer.slice(closingPartialStart).toLowerCase();\n\t\t\t\tconst partialLength = Math.max(\n\t\t\t\t\tpartial && openingTag.startsWith(partial) ? partial.length : 0,\n\t\t\t\t\tclosingPartial && closingTag.startsWith(closingPartial) ? closingPartial.length : 0,\n\t\t\t\t);\n\t\t\t\tvisible += buffer.slice(0, buffer.length - partialLength);\n\t\t\t\tbuffer = buffer.slice(buffer.length - partialLength);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tvisible += buffer.slice(0, start);\n\t\t\tbuffer = buffer.slice(start);\n\t\t\tconst tagEnd = buffer.indexOf(\">\");\n\t\t\tif (tagEnd < 0) break;\n\t\t\tbuffer = buffer.slice(tagEnd + 1);\n\t\t\tinThinking = true;\n\t\t}\n\t\treturn visible;\n\t};\n\n\treturn {\n\t\tpush: (chunk) => {\n\t\t\tif (!enabled) return chunk;\n\t\t\tbuffer += chunk;\n\t\t\treturn consume();\n\t\t},\n\t\tflush: () => (enabled ? consume() : buffer),\n\t};\n}\n\nfunction isEncryptedReasoningDetail(detail: unknown): detail is OpenAIEncryptedReasoningDetail {\n\tif (typeof detail !== \"object\" || detail === null) {\n\t\treturn false;\n\t}\n\tconst candidate = detail as Record<string, unknown>;\n\treturn (\n\t\tcandidate.type === \"reasoning.encrypted\" &&\n\t\ttypeof candidate.id === \"string\" &&\n\t\tcandidate.id.length > 0 &&\n\t\ttypeof candidate.data === \"string\" &&\n\t\tcandidate.data.length > 0\n\t);\n}\n\nexport interface OpenAICompletionsOptions extends StreamOptions {\n\ttoolChoice?: \"auto\" | \"none\" | \"required\" | { type: \"function\"; function: { name: string } };\n\treasoningEffort?: \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n}\n\ninterface OpenAICompatCacheControl {\n\ttype: \"ephemeral\";\n\tttl?: string;\n}\n\ntype ResolvedOpenAICompletionsCompat = Omit<Required<OpenAICompletionsCompat>, \"cacheControlFormat\"> & {\n\tcacheControlFormat?: OpenAICompletionsCompat[\"cacheControlFormat\"];\n};\n\ntype ChatCompletionInstructionMessageParam = ChatCompletionDeveloperMessageParam | ChatCompletionSystemMessageParam;\n\ntype OpenAIEncryptedReasoningDetail = {\n\ttype: \"reasoning.encrypted\";\n\tid: string;\n\tdata: string;\n};\n\ntype ChatCompletionTextPartWithCacheControl = ChatCompletionContentPartText & {\n\tcache_control?: OpenAICompatCacheControl;\n};\n\ntype ChatCompletionToolWithCacheControl = OpenAI.Chat.Completions.ChatCompletionTool & {\n\tcache_control?: OpenAICompatCacheControl;\n};\n\ninterface OpenRouterGeneratedImage {\n\timage_url?: string | { url?: string };\n}\n\ntype OpenRouterImageGenerationMessage = ChatCompletion[\"choices\"][number][\"message\"] & {\n\timages?: OpenRouterGeneratedImage[];\n};\n\ntype OpenRouterImageGenerationChoice = ChatCompletion[\"choices\"][number] & {\n\tmessage: OpenRouterImageGenerationMessage;\n};\n\ntype OpenRouterImageGenerationResponse = ChatCompletion & {\n\tchoices: OpenRouterImageGenerationChoice[];\n};\n\nfunction isOpenRouterImageGenerationModel(model: Model<\"openai-completions\">): boolean {\n\treturn model.provider === \"openrouter\" && model.compat?.openRouterImageGeneration === true;\n}\n\nfunction resolveCacheRetention(cacheRetention?: CacheRetention, env?: ProviderEnv): CacheRetention {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\tif (getProviderEnvValue(\"MERC_CACHE_RETENTION\", env) === \"long\") {\n\t\treturn \"long\";\n\t}\n\treturn \"short\";\n}\n\nexport const streamOpenAICompletions: StreamFunction<\"openai-completions\", OpenAICompletionsOptions> = (\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\toptions?: OpenAICompletionsOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\ttry {\n\t\t\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider, options?.env) || \"\";\n\t\t\tconst compat = getCompat(model);\n\t\t\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\t\t\tconst cacheSessionId = cacheRetention === \"none\" ? undefined : options?.sessionId;\n\t\t\tconst client = createClient(model, context, apiKey, options?.headers, cacheSessionId, compat, options?.env);\n\t\t\tlet params = buildParams(model, context, options, compat, cacheRetention);\n\t\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\t\tif (nextParams !== undefined) {\n\t\t\t\tparams = nextParams as OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming;\n\t\t\t}\n\t\t\tconst requestOptions = {\n\t\t\t\t...(options?.signal ? { signal: options.signal } : {}),\n\t\t\t\t...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n\t\t\t\tmaxRetries: options?.maxRetries ?? 0,\n\t\t\t};\n\t\t\tif (isOpenRouterImageGenerationModel(model)) {\n\t\t\t\tconst { stream_options: _streamOptions, ...nonStreamingBaseParams } = params;\n\t\t\t\tconst nonStreamingParams = {\n\t\t\t\t\t...nonStreamingBaseParams,\n\t\t\t\t\tstream: false,\n\t\t\t\t} as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming;\n\t\t\t\tconst { data: response, response: rawResponse } = await client.chat.completions\n\t\t\t\t\t.create(nonStreamingParams, requestOptions)\n\t\t\t\t\t.withResponse();\n\t\t\t\tawait options?.onResponse?.(\n\t\t\t\t\t{ status: rawResponse.status, headers: headersToRecord(rawResponse.headers) },\n\t\t\t\t\tmodel,\n\t\t\t\t);\n\t\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\t\tconst imageResponse = response as OpenRouterImageGenerationResponse;\n\t\t\t\toutput.responseId ||= imageResponse.id;\n\t\t\t\toutput.usage = parseChunkUsage(imageResponse.usage ?? {}, model);\n\n\t\t\t\tconst choice = imageResponse.choices[0];\n\t\t\t\tif (choice) {\n\t\t\t\t\tconst text = choice.message.content;\n\t\t\t\t\tif (text) {\n\t\t\t\t\t\tconst textBlock: TextContent = { type: \"text\", text };\n\t\t\t\t\t\toutput.content.push(textBlock);\n\t\t\t\t\t\tconst contentIndex = output.content.length - 1;\n\t\t\t\t\t\tstream.push({ type: \"text_start\", contentIndex, partial: output });\n\t\t\t\t\t\tstream.push({ type: \"text_delta\", contentIndex, delta: text, partial: output });\n\t\t\t\t\t\tstream.push({ type: \"text_end\", contentIndex, content: text, partial: output });\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const image of choice.message.images ?? []) {\n\t\t\t\t\t\tconst imageUrl = typeof image.image_url === \"string\" ? image.image_url : image.image_url?.url;\n\t\t\t\t\t\tif (!imageUrl?.startsWith(\"data:\")) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst matches = imageUrl.match(/^data:([^;]+);base64,(.+)$/);\n\t\t\t\t\t\tif (!matches) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst imageBlock: ImageContent = {\n\t\t\t\t\t\t\ttype: \"image\",\n\t\t\t\t\t\t\tmimeType: matches[1],\n\t\t\t\t\t\t\tdata: matches[2],\n\t\t\t\t\t\t};\n\t\t\t\t\t\toutput.content.push(imageBlock);\n\t\t\t\t\t\tconst contentIndex = output.content.length - 1;\n\t\t\t\t\t\tstream.push({ type: \"image_start\", contentIndex, partial: output });\n\t\t\t\t\t\tstream.push({ type: \"image_end\", contentIndex, image: imageBlock, partial: output });\n\t\t\t\t\t}\n\n\t\t\t\t\tif (choice.finish_reason) {\n\t\t\t\t\t\tconst finishReasonResult = mapStopReason(choice.finish_reason);\n\t\t\t\t\t\toutput.stopReason = finishReasonResult.stopReason;\n\t\t\t\t\t\tif (finishReasonResult.errorMessage) {\n\t\t\t\t\t\t\toutput.errorMessage = finishReasonResult.errorMessage;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (output.stopReason === \"stop\" || output.stopReason === \"length\" || output.stopReason === \"toolUse\") {\n\t\t\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\t\t} else {\n\t\t\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\t\t}\n\t\t\t\tstream.end();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { data: openaiStream, response } = await client.chat.completions\n\t\t\t\t.create(params, requestOptions)\n\t\t\t\t.withResponse();\n\t\t\tawait options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\tinterface StreamingToolCallBlock extends ToolCall {\n\t\t\t\tpartialArgs?: string;\n\t\t\t\tstreamIndex?: number;\n\t\t\t}\n\t\t\ttype StreamingBlock = TextContent | ThinkingContent | StreamingToolCallBlock;\n\t\t\ttype StreamingToolCallDelta = NonNullable<ChatCompletionChunk.Choice.Delta[\"tool_calls\"]>[number];\n\n\t\t\tlet textBlock: TextContent | null = null;\n\t\t\tlet thinkingBlock: ThinkingContent | null = null;\n\t\t\tlet hasFinishReason = false;\n\t\t\tlet hasIncompleteToolCallArguments = false;\n\t\t\tconst toolCallBlocksByIndex = new Map<number, StreamingToolCallBlock>();\n\t\t\tconst toolCallBlocksById = new Map<string, StreamingToolCallBlock>();\n\t\t\tconst pendingReasoningDetailsByToolCallId = new Map<string, string>();\n\t\t\tconst blocks = output.content as StreamingBlock[];\n\t\t\tconst thinkingTagFilter = createThinkingTagFilter(compat.thinkingFormat === \"minimax\");\n\t\t\tconst getContentIndex = (block: StreamingBlock) => blocks.indexOf(block);\n\t\t\tconst finishBlock = (block: StreamingBlock) => {\n\t\t\t\tconst contentIndex = getContentIndex(block);\n\t\t\t\tif (contentIndex === -1) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (block.type === \"text\") {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\tcontentIndex,\n\t\t\t\t\t\tcontent: block.text,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t} else if (block.type === \"thinking\") {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\tcontentIndex,\n\t\t\t\t\t\tcontent: block.thinking,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\t// Without finish_reason, only strictly valid raw arguments prove the call was not cut off.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tJSON.parse(block.partialArgs ?? \"\");\n\t\t\t\t\t} catch {\n\t\t\t\t\t\thasIncompleteToolCallArguments = true;\n\t\t\t\t\t}\n\t\t\t\t\tfinalizeToolCallArguments(block, block.partialArgs);\n\t\t\t\t\t// Finalize in-place and strip the scratch buffers so replay only\n\t\t\t\t\t// carries parsed arguments.\n\t\t\t\t\tdelete block.partialArgs;\n\t\t\t\t\tdelete block.streamIndex;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\t\tcontentIndex,\n\t\t\t\t\t\ttoolCall: block,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst ensureTextBlock = () => {\n\t\t\t\tif (!textBlock) {\n\t\t\t\t\ttextBlock = { type: \"text\", text: \"\" };\n\t\t\t\t\tblocks.push(textBlock);\n\t\t\t\t\tstream.push({ type: \"text_start\", contentIndex: getContentIndex(textBlock), partial: output });\n\t\t\t\t}\n\t\t\t\treturn textBlock;\n\t\t\t};\n\t\t\tconst appendTextDelta = (delta: string) => {\n\t\t\t\tif (!delta) return;\n\t\t\t\tconst block = ensureTextBlock();\n\t\t\t\tblock.text += delta;\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\tdelta,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t};\n\t\t\tconst ensureThinkingBlock = (thinkingSignature: string) => {\n\t\t\t\tif (!thinkingBlock) {\n\t\t\t\t\tthinkingBlock = {\n\t\t\t\t\t\ttype: \"thinking\",\n\t\t\t\t\t\tthinking: \"\",\n\t\t\t\t\t\tthinkingSignature,\n\t\t\t\t\t};\n\t\t\t\t\tblocks.push(thinkingBlock);\n\t\t\t\t\tstream.push({ type: \"thinking_start\", contentIndex: getContentIndex(thinkingBlock), partial: output });\n\t\t\t\t}\n\t\t\t\treturn thinkingBlock;\n\t\t\t};\n\t\t\tconst applyPendingReasoningDetail = (block: StreamingToolCallBlock) => {\n\t\t\t\tif (!block.id) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst pendingReasoningDetail = pendingReasoningDetailsByToolCallId.get(block.id);\n\t\t\t\tif (pendingReasoningDetail) {\n\t\t\t\t\tblock.thoughtSignature = pendingReasoningDetail;\n\t\t\t\t\tpendingReasoningDetailsByToolCallId.delete(block.id);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst ensureToolCallBlock = (toolCall: StreamingToolCallDelta) => {\n\t\t\t\tconst streamIndex = typeof toolCall.index === \"number\" ? toolCall.index : undefined;\n\t\t\t\tlet block = streamIndex !== undefined ? toolCallBlocksByIndex.get(streamIndex) : undefined;\n\t\t\t\tif (!block && toolCall.id) {\n\t\t\t\t\tblock = toolCallBlocksById.get(toolCall.id);\n\t\t\t\t}\n\t\t\t\tif (!block) {\n\t\t\t\t\tblock = {\n\t\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\t\tid: toolCall.id || \"\",\n\t\t\t\t\t\tname: toolCall.function?.name || \"\",\n\t\t\t\t\t\targuments: {},\n\t\t\t\t\t\tpartialArgs: \"\",\n\t\t\t\t\t\tstreamIndex,\n\t\t\t\t\t};\n\t\t\t\t\tif (streamIndex !== undefined) {\n\t\t\t\t\t\ttoolCallBlocksByIndex.set(streamIndex, block);\n\t\t\t\t\t}\n\t\t\t\t\tif (toolCall.id) {\n\t\t\t\t\t\ttoolCallBlocksById.set(toolCall.id, block);\n\t\t\t\t\t}\n\t\t\t\t\tblocks.push(block);\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"toolcall_start\",\n\t\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (streamIndex !== undefined && block.streamIndex === undefined) {\n\t\t\t\t\tblock.streamIndex = streamIndex;\n\t\t\t\t\ttoolCallBlocksByIndex.set(streamIndex, block);\n\t\t\t\t}\n\t\t\t\tif (toolCall.id) {\n\t\t\t\t\ttoolCallBlocksById.set(toolCall.id, block);\n\t\t\t\t}\n\t\t\t\tapplyPendingReasoningDetail(block);\n\t\t\t\treturn block;\n\t\t\t};\n\n\t\t\tfor await (const chunk of openaiStream) {\n\t\t\t\tif (!chunk || typeof chunk !== \"object\") continue;\n\n\t\t\t\t// OpenAI documents ChatCompletionChunk.id as the unique chat completion identifier,\n\t\t\t\t// and each chunk in a streamed completion carries the same id.\n\t\t\t\toutput.responseId ||= chunk.id;\n\t\t\t\tif (typeof chunk.model === \"string\" && chunk.model.length > 0 && chunk.model !== model.id) {\n\t\t\t\t\toutput.responseModel ||= chunk.model;\n\t\t\t\t}\n\t\t\t\tif (chunk.usage) {\n\t\t\t\t\toutput.usage = parseChunkUsage(chunk.usage, model);\n\t\t\t\t}\n\n\t\t\t\tconst choice = Array.isArray(chunk.choices) ? chunk.choices[0] : undefined;\n\t\t\t\tif (!choice) continue;\n\n\t\t\t\t// Fallback: some providers (e.g., Moonshot) return usage\n\t\t\t\t// in choice.usage instead of the standard chunk.usage\n\t\t\t\tif (!chunk.usage && (choice as any).usage) {\n\t\t\t\t\toutput.usage = parseChunkUsage((choice as any).usage, model);\n\t\t\t\t}\n\n\t\t\t\tif (choice.finish_reason) {\n\t\t\t\t\tconst finishReasonResult = mapStopReason(choice.finish_reason);\n\t\t\t\t\toutput.stopReason = finishReasonResult.stopReason;\n\t\t\t\t\tif (finishReasonResult.errorMessage) {\n\t\t\t\t\t\toutput.errorMessage = finishReasonResult.errorMessage;\n\t\t\t\t\t}\n\t\t\t\t\thasFinishReason = true;\n\t\t\t\t}\n\n\t\t\t\tif (choice.delta) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tchoice.delta.content !== null &&\n\t\t\t\t\t\tchoice.delta.content !== undefined &&\n\t\t\t\t\t\tchoice.delta.content.length > 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tappendTextDelta(thinkingTagFilter.push(choice.delta.content));\n\t\t\t\t\t}\n\n\t\t\t\t\t// Some endpoints return reasoning in reasoning_content (llama.cpp),\n\t\t\t\t\t// or reasoning (other openai compatible endpoints)\n\t\t\t\t\t// Use the first non-empty reasoning field to avoid duplication\n\t\t\t\t\t// (e.g., chutes.ai returns both reasoning_content and reasoning with same content)\n\t\t\t\t\tconst reasoningFields = [\"reasoning_content\", \"reasoning\", \"reasoning_text\"];\n\t\t\t\t\tconst deltaFields = choice.delta as Record<string, unknown>;\n\t\t\t\t\tlet foundReasoningField: string | null = null;\n\t\t\t\t\tfor (const field of reasoningFields) {\n\t\t\t\t\t\tconst value = deltaFields[field];\n\t\t\t\t\t\tif (typeof value === \"string\" && value.length > 0) {\n\t\t\t\t\t\t\tfoundReasoningField = field;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tfoundReasoningField &&\n\t\t\t\t\t\t!(compat.thinkingFormat === \"minimax\" && (!options?.reasoningEffort || model.reasoning === false))\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst delta = deltaFields[foundReasoningField];\n\t\t\t\t\t\tif (typeof delta === \"string\" && delta.length > 0) {\n\t\t\t\t\t\t\tconst thinkingSignature =\n\t\t\t\t\t\t\t\tmodel.provider === \"opencode-go\" && foundReasoningField === \"reasoning\"\n\t\t\t\t\t\t\t\t\t? \"reasoning_content\"\n\t\t\t\t\t\t\t\t\t: foundReasoningField;\n\t\t\t\t\t\t\tconst block = ensureThinkingBlock(thinkingSignature);\n\t\t\t\t\t\t\tblock.thinking += delta;\n\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\t\t\t\tdelta,\n\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (choice?.delta?.tool_calls) {\n\t\t\t\t\t\tfor (const toolCall of choice.delta.tool_calls) {\n\t\t\t\t\t\t\tconst block = ensureToolCallBlock(toolCall);\n\t\t\t\t\t\t\tif (!block.id && toolCall.id) {\n\t\t\t\t\t\t\t\tblock.id = toolCall.id;\n\t\t\t\t\t\t\t\ttoolCallBlocksById.set(toolCall.id, block);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!block.name && toolCall.function?.name) {\n\t\t\t\t\t\t\t\tblock.name = toolCall.function.name;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlet delta = \"\";\n\t\t\t\t\t\t\tif (toolCall.function?.arguments) {\n\t\t\t\t\t\t\t\tdelta = toolCall.function.arguments;\n\t\t\t\t\t\t\t\tblock.partialArgs = (block.partialArgs ?? \"\") + toolCall.function.arguments;\n\t\t\t\t\t\t\t\tblock.arguments = parseStreamingJson(block.partialArgs);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\t\t\t\tdelta,\n\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst reasoningDetails = (choice.delta as { reasoning_details?: unknown }).reasoning_details;\n\t\t\t\t\tif (Array.isArray(reasoningDetails)) {\n\t\t\t\t\t\tfor (const detail of reasoningDetails) {\n\t\t\t\t\t\t\tif (isEncryptedReasoningDetail(detail)) {\n\t\t\t\t\t\t\t\tconst serializedDetail = JSON.stringify(detail);\n\t\t\t\t\t\t\t\tconst matchingToolCall = toolCallBlocksById.get(detail.id);\n\t\t\t\t\t\t\t\tif (matchingToolCall) {\n\t\t\t\t\t\t\t\t\tmatchingToolCall.thoughtSignature = serializedDetail;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tpendingReasoningDetailsByToolCallId.set(detail.id, serializedDetail);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tappendTextDelta(thinkingTagFilter.flush());\n\n\t\t\tfor (const block of blocks) {\n\t\t\t\tfinishBlock(block);\n\t\t\t}\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"aborted\") {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\t\t\tif (!hasFinishReason && !compat.supportsFinishReason) {\n\t\t\t\tif (hasIncompleteToolCallArguments) {\n\t\t\t\t\tthrow new Error(\"Stream ended without finish_reason and with incomplete tool call arguments\");\n\t\t\t\t}\n\t\t\t\toutput.stopReason = output.content.some((block) => block.type === \"toolCall\") ? \"toolUse\" : \"stop\";\n\t\t\t}\n\t\t\tif (output.stopReason === \"error\") {\n\t\t\t\tthrow new Error(output.errorMessage || \"Provider returned an error stop reason\");\n\t\t\t}\n\t\t\tif (compat.supportsFinishReason && !hasFinishReason) {\n\t\t\t\tthrow new Error(\"Stream ended without finish_reason\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tdelete (block as { index?: number }).index;\n\t\t\t\t// Streaming scratch buffers are only used during parsing; never persist them.\n\t\t\t\tdelete (block as { partialArgs?: string }).partialArgs;\n\t\t\t\tdelete (block as { streamIndex?: number }).streamIndex;\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tconst normalized = normalizeProviderError(error);\n\t\t\toutput.errorMetadata = normalized.errorMetadata;\n\t\t\toutput.errorMessage = formatProviderError(normalized);\n\t\t\t// Some providers via OpenRouter give additional information in this field.\n\t\t\t// normalizeProviderError already stringifies the parsed body (error.error)\n\t\t\t// into errorMessage, so only append the raw metadata when it is not already\n\t\t\t// present to avoid double-printing it.\n\t\t\tconst rawMetadata = (error as any)?.error?.metadata?.raw;\n\t\t\tif (rawMetadata && !output.errorMessage.includes(String(rawMetadata))) {\n\t\t\t\toutput.errorMessage += `\\n${rawMetadata}`;\n\t\t\t}\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimpleOpenAICompletions: StreamFunction<\"openai-completions\", SimpleStreamOptions> = (\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider, options?.env);\n\tif (!apiKey && model.authHeader !== false) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\n\tconst base = buildBaseOptions(model, context, options, apiKey ?? \"\");\n\tconst clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;\n\tconst reasoningEffort = clampedReasoning === \"off\" ? undefined : clampedReasoning;\n\tconst toolChoice = (options as OpenAICompletionsOptions | undefined)?.toolChoice;\n\n\treturn streamOpenAICompletions(model, context, {\n\t\t...base,\n\t\treasoningEffort,\n\t\ttoolChoice,\n\t} satisfies OpenAICompletionsOptions);\n};\n\nfunction createClient(\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\tapiKey?: string,\n\toptionsHeaders?: Record<string, string>,\n\tsessionId?: string,\n\tcompat: ResolvedOpenAICompletionsCompat = getCompat(model),\n\tenv?: ProviderEnv,\n) {\n\tconst noAuth = model.authHeader === false;\n\tif (!apiKey && !noAuth) {\n\t\tconst configuredApiKey = getProviderEnvValue(\"OPENAI_API_KEY\", env);\n\t\tif (!configuredApiKey) {\n\t\t\tthrow new Error(\n\t\t\t\t\"OpenAI API key is required. Set OPENAI_API_KEY environment variable or pass it as an argument.\",\n\t\t\t);\n\t\t}\n\t\tapiKey = configuredApiKey;\n\t}\n\tif (!apiKey) apiKey = \"merc-no-auth\";\n\n\tconst headers = { ...model.headers };\n\tif (model.provider === \"github-copilot\") {\n\t\tconst hasImages = hasCopilotVisionInput(context.messages);\n\t\tconst copilotHeaders = buildCopilotDynamicHeaders({\n\t\t\tmessages: context.messages,\n\t\t\thasImages,\n\t\t});\n\t\tObject.assign(headers, copilotHeaders);\n\t}\n\n\tif (sessionId && compat.sendSessionAffinityHeaders) {\n\t\tif (compat.sessionAffinityFormat === \"openrouter\") {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t} else {\n\t\t\tif (compat.sessionAffinityFormat === \"openai\") headers.session_id = sessionId;\n\t\t\theaders[\"x-client-request-id\"] = sessionId;\n\t\t\theaders[\"x-session-affinity\"] = sessionId;\n\t\t}\n\t}\n\n\t// Merge options headers last so they can override defaults\n\tif (optionsHeaders) {\n\t\tObject.assign(headers, optionsHeaders);\n\t}\n\n\tconst defaultHeaders = noAuth\n\t\t? { ...headers, Authorization: null }\n\t\t: model.provider === \"cloudflare-ai-gateway\"\n\t\t\t? {\n\t\t\t\t\t...headers,\n\t\t\t\t\tAuthorization: headers.Authorization ?? null,\n\t\t\t\t\t\"cf-aig-authorization\": `Bearer ${apiKey}`,\n\t\t\t\t}\n\t\t\t: headers;\n\n\treturn new OpenAI({\n\t\tapiKey,\n\t\tbaseURL: isCloudflareProvider(model.provider) ? resolveCloudflareBaseUrl(model, env) : model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tdefaultHeaders,\n\t});\n}\n\nfunction buildParams(\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\toptions?: OpenAICompletionsOptions,\n\tcompat: ResolvedOpenAICompletionsCompat = getCompat(model),\n\tcacheRetention: CacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env),\n) {\n\tconst messages = convertMessages(model, context, compat);\n\tconst cacheControl = getCompatCacheControl(compat, cacheRetention);\n\n\tconst params: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {\n\t\tmodel: model.id,\n\t\tmessages,\n\t\tstream: true,\n\t\tprompt_cache_key:\n\t\t\t(model.baseUrl.includes(\"api.openai.com\") && cacheRetention !== \"none\") ||\n\t\t\t(cacheRetention === \"long\" && compat.supportsLongCacheRetention)\n\t\t\t\t? clampOpenAIPromptCacheKey(options?.sessionId)\n\t\t\t\t: undefined,\n\t\tprompt_cache_retention: cacheRetention === \"long\" && compat.supportsLongCacheRetention ? \"24h\" : undefined,\n\t};\n\n\tif (isOpenRouterImageGenerationModel(model)) {\n\t\tReflect.set(params, \"modalities\", [\"image\"]);\n\t}\n\n\tif (compat.supportsUsageInStreaming !== false) {\n\t\t(params as any).stream_options = { include_usage: true };\n\t}\n\n\tif (compat.supportsStore) {\n\t\tparams.store = false;\n\t}\n\n\tif (options?.maxTokens) {\n\t\tif (compat.maxTokensField === \"max_tokens\") {\n\t\t\t(params as any).max_tokens = options.maxTokens;\n\t\t} else {\n\t\t\tparams.max_completion_tokens = options.maxTokens;\n\t\t}\n\t}\n\n\tif (options?.temperature !== undefined) {\n\t\tparams.temperature = options.temperature;\n\t}\n\n\tif (!isOpenRouterImageGenerationModel(model) && context.tools && context.tools.length > 0) {\n\t\tparams.tools = convertTools(context.tools, compat);\n\t\tif (compat.zaiToolStream) {\n\t\t\t(params as any).tool_stream = true;\n\t\t}\n\t} else if (!isOpenRouterImageGenerationModel(model) && hasToolHistory(context.messages)) {\n\t\t// Anthropic (via LiteLLM/proxy) requires tools param when conversation has tool_calls/tool_results\n\t\tparams.tools = [];\n\t}\n\n\tif (cacheControl) {\n\t\tapplyAnthropicCacheControl(messages, params.tools, cacheControl);\n\t}\n\n\tif (options?.toolChoice && params.tools?.length) {\n\t\tparams.tool_choice = options.toolChoice;\n\t}\n\n\tif (compat.thinkingFormat === \"zai\" && model.reasoning) {\n\t\tconst zaiParams = params as Omit<typeof params, \"reasoning_effort\"> & {\n\t\t\tthinking?: { type: \"enabled\" | \"disabled\"; clear_thinking?: boolean };\n\t\t\treasoning_effort?: string;\n\t\t};\n\t\tzaiParams.thinking = options?.reasoningEffort ? { type: \"enabled\", clear_thinking: false } : { type: \"disabled\" };\n\t\tif (options?.reasoningEffort && compat.supportsReasoningEffort) {\n\t\t\tconst mappedEffort = model.thinkingLevelMap?.[options.reasoningEffort];\n\t\t\tconst effort = mappedEffort === undefined ? options.reasoningEffort : mappedEffort;\n\t\t\tif (typeof effort === \"string\") {\n\t\t\t\tzaiParams.reasoning_effort = effort;\n\t\t\t}\n\t\t}\n\t} else if (compat.thinkingFormat === \"minimax\") {\n\t\tconst minimaxParams = params as typeof params & {\n\t\t\tthinking?: { type: \"adaptive\" | \"disabled\" };\n\t\t\treasoning_split?: boolean;\n\t\t};\n\t\tminimaxParams.thinking = { type: options?.reasoningEffort ? \"adaptive\" : \"disabled\" };\n\t\tminimaxParams.reasoning_split = true;\n\t} else if (compat.thinkingFormat === \"qwen\" && model.reasoning) {\n\t\t(params as any).enable_thinking = !!options?.reasoningEffort;\n\t} else if (compat.thinkingFormat === \"qwen-chat-template\" && model.reasoning) {\n\t\t(params as any).chat_template_kwargs = {\n\t\t\tenable_thinking: !!options?.reasoningEffort,\n\t\t\tpreserve_thinking: true,\n\t\t};\n\t} else if (compat.thinkingFormat === \"deepseek\" && model.reasoning) {\n\t\tif (options?.reasoningEffort) {\n\t\t\t(params as any).thinking = { type: \"enabled\" };\n\t\t} else if (model.thinkingLevelMap?.off !== null) {\n\t\t\t(params as any).thinking = { type: \"disabled\" };\n\t\t}\n\t\tif (options?.reasoningEffort && compat.supportsReasoningEffort) {\n\t\t\t(params as any).reasoning_effort =\n\t\t\t\tmodel.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n\t\t}\n\t} else if (compat.thinkingFormat === \"ant-ling\" && model.reasoning && options?.reasoningEffort) {\n\t\tconst effort = model.thinkingLevelMap?.[options.reasoningEffort];\n\t\tif (typeof effort === \"string\") {\n\t\t\t(params as typeof params & { reasoning?: { effort: string } }).reasoning = { effort };\n\t\t}\n\t} else if (compat.thinkingFormat === \"openrouter\" && model.reasoning) {\n\t\t// OpenRouter normalizes reasoning across providers via a nested reasoning object.\n\t\tconst openRouterParams = params as typeof params & { reasoning?: { effort?: string } };\n\t\tif (options?.reasoningEffort) {\n\t\t\topenRouterParams.reasoning = {\n\t\t\t\teffort: model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort,\n\t\t\t};\n\t\t} else if (model.thinkingLevelMap?.off !== null) {\n\t\t\topenRouterParams.reasoning = { effort: model.thinkingLevelMap?.off ?? \"none\" };\n\t\t}\n\t} else if (options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {\n\t\t// OpenAI-style reasoning_effort\n\t\t(params as any).reasoning_effort = model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n\t} else if (!options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {\n\t\tconst offValue = model.thinkingLevelMap?.off;\n\t\tif (typeof offValue === \"string\") {\n\t\t\t(params as any).reasoning_effort = offValue;\n\t\t}\n\t}\n\n\t// OpenRouter provider routing preferences\n\tif (model.baseUrl.includes(\"openrouter.ai\") && model.compat?.openRouterRouting) {\n\t\t(params as any).provider = model.compat.openRouterRouting;\n\t}\n\n\t// Vercel AI Gateway provider routing preferences\n\tif (model.baseUrl.includes(\"ai-gateway.vercel.sh\") && model.compat?.vercelGatewayRouting) {\n\t\tconst routing = model.compat.vercelGatewayRouting;\n\t\tif (routing.only || routing.order) {\n\t\t\tconst gatewayOptions: Record<string, string[]> = {};\n\t\t\tif (routing.only) gatewayOptions.only = routing.only;\n\t\t\tif (routing.order) gatewayOptions.order = routing.order;\n\t\t\t(params as any).providerOptions = { gateway: gatewayOptions };\n\t\t}\n\t}\n\n\treturn params;\n}\n\nfunction getCompatCacheControl(\n\tcompat: ResolvedOpenAICompletionsCompat,\n\tcacheRetention: CacheRetention,\n): OpenAICompatCacheControl | undefined {\n\tif (compat.cacheControlFormat !== \"anthropic\" || cacheRetention === \"none\") {\n\t\treturn undefined;\n\t}\n\n\tconst ttl = cacheRetention === \"long\" && compat.supportsLongCacheRetention ? \"1h\" : undefined;\n\treturn { type: \"ephemeral\", ...(ttl ? { ttl } : {}) };\n}\n\nfunction applyAnthropicCacheControl(\n\tmessages: ChatCompletionMessageParam[],\n\ttools: OpenAI.Chat.Completions.ChatCompletionTool[] | undefined,\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\taddCacheControlToSystemPrompt(messages, cacheControl);\n\taddCacheControlToLastTool(tools, cacheControl);\n\taddCacheControlToLastConversationMessage(messages, cacheControl);\n}\n\nfunction addCacheControlToSystemPrompt(\n\tmessages: ChatCompletionMessageParam[],\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\tfor (const message of messages) {\n\t\tif (message.role === \"system\" || message.role === \"developer\") {\n\t\t\taddCacheControlToInstructionMessage(message, cacheControl);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nfunction addCacheControlToLastConversationMessage(\n\tmessages: ChatCompletionMessageParam[],\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst message = messages[i];\n\t\tif (message.role === \"user\" || message.role === \"assistant\" || message.role === \"tool\") {\n\t\t\tif (addCacheControlToMessage(message, cacheControl)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction addCacheControlToLastTool(\n\ttools: OpenAI.Chat.Completions.ChatCompletionTool[] | undefined,\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\tif (!tools || tools.length === 0) {\n\t\treturn;\n\t}\n\n\tconst lastTool = tools[tools.length - 1] as ChatCompletionToolWithCacheControl;\n\tlastTool.cache_control = cacheControl;\n}\n\nfunction addCacheControlToInstructionMessage(\n\tmessage: ChatCompletionInstructionMessageParam,\n\tcacheControl: OpenAICompatCacheControl,\n): boolean {\n\treturn addCacheControlToTextContent(message, cacheControl);\n}\n\nfunction addCacheControlToMessage(\n\tmessage: ChatCompletionMessageParam,\n\tcacheControl: OpenAICompatCacheControl,\n): boolean {\n\tif (message.role === \"user\" || message.role === \"assistant\" || message.role === \"tool\") {\n\t\treturn addCacheControlToTextContent(message, cacheControl);\n\t}\n\treturn false;\n}\n\nfunction addCacheControlToTextContent(\n\tmessage:\n\t\t| ChatCompletionInstructionMessageParam\n\t\t| ChatCompletionAssistantMessageParam\n\t\t| ChatCompletionToolMessageParam\n\t\t| Extract<ChatCompletionMessageParam, { role: \"user\" }>,\n\tcacheControl: OpenAICompatCacheControl,\n): boolean {\n\tconst content = message.content;\n\tif (typeof content === \"string\") {\n\t\tif (content.length === 0) {\n\t\t\treturn false;\n\t\t}\n\t\tmessage.content = [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: content,\n\t\t\t\tcache_control: cacheControl,\n\t\t\t},\n\t\t] as ChatCompletionTextPartWithCacheControl[];\n\t\treturn true;\n\t}\n\n\tif (!Array.isArray(content)) {\n\t\treturn false;\n\t}\n\n\tfor (let i = content.length - 1; i >= 0; i--) {\n\t\tconst part = content[i];\n\t\tif (part?.type === \"text\") {\n\t\t\tconst textPart = part as ChatCompletionTextPartWithCacheControl;\n\t\t\ttextPart.cache_control = cacheControl;\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nexport function convertMessages(\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\tcompat: ResolvedOpenAICompletionsCompat,\n): ChatCompletionMessageParam[] {\n\tconst params: ChatCompletionMessageParam[] = [];\n\n\tconst normalizeToolCallId = createProviderToolCallIdNormalizer(model);\n\n\tconst transformedMessages = transformMessages(context.messages, model, (id) => normalizeToolCallId(id));\n\n\tif (context.systemPrompt) {\n\t\tconst useDeveloperRole = model.reasoning && compat.supportsDeveloperRole;\n\t\tconst role = useDeveloperRole ? \"developer\" : \"system\";\n\t\tparams.push({ role: role, content: sanitizeSurrogates(context.systemPrompt) });\n\t}\n\n\tlet lastRole: string | null = null;\n\n\tfor (let i = 0; i < transformedMessages.length; i++) {\n\t\tconst msg = transformedMessages[i];\n\t\t// Some providers don't allow user messages directly after tool results\n\t\t// Insert a synthetic assistant message to bridge the gap\n\t\tif (compat.requiresAssistantAfterToolResult && lastRole === \"toolResult\" && msg.role === \"user\") {\n\t\t\tparams.push({\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: \"I have processed the tool results.\",\n\t\t\t});\n\t\t}\n\n\t\tif (msg.role === \"user\") {\n\t\t\tif (typeof msg.content === \"string\") {\n\t\t\t\tparams.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: sanitizeSurrogates(msg.content),\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst content: ChatCompletionContentPart[] = msg.content\n\t\t\t\t\t.filter((item) => item.type !== \"text\" || item.text.length > 0)\n\t\t\t\t\t.map((item): ChatCompletionContentPart => {\n\t\t\t\t\t\tif (item.type === \"text\") {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\ttext: sanitizeSurrogates(item.text),\n\t\t\t\t\t\t\t} satisfies ChatCompletionContentPartText;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\ttype: \"image_url\",\n\t\t\t\t\t\t\t\timage_url: {\n\t\t\t\t\t\t\t\t\turl: `data:${item.mimeType};base64,${item.data}`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t} satisfies ChatCompletionContentPartImage;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tif (content.length === 0) continue;\n\t\t\t\tparams.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (msg.role === \"assistant\") {\n\t\t\t// Some providers don't accept null content, use empty string instead\n\t\t\tconst assistantMsg: ChatCompletionAssistantMessageParam = {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: compat.requiresAssistantAfterToolResult ? \"\" : null,\n\t\t\t};\n\n\t\t\tconst assistantTextParts = msg.content\n\t\t\t\t.filter(isTextContentBlock)\n\t\t\t\t.filter((block) => block.text.trim().length > 0)\n\t\t\t\t.map(\n\t\t\t\t\t(block) =>\n\t\t\t\t\t\t({\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: sanitizeSurrogates(block.text),\n\t\t\t\t\t\t}) satisfies ChatCompletionContentPartText,\n\t\t\t\t);\n\t\t\tconst assistantText = assistantTextParts.map((part) => part.text).join(\"\");\n\n\t\t\tconst nonEmptyThinkingBlocks = msg.content\n\t\t\t\t.filter(isThinkingContentBlock)\n\t\t\t\t.filter((block) => block.thinking.trim().length > 0);\n\t\t\tif (nonEmptyThinkingBlocks.length > 0) {\n\t\t\t\tif (compat.requiresThinkingAsText) {\n\t\t\t\t\t// Convert thinking blocks to plain text (no tags to avoid model mimicking them)\n\t\t\t\t\tconst thinkingText = nonEmptyThinkingBlocks\n\t\t\t\t\t\t.map((block) => sanitizeSurrogates(block.thinking))\n\t\t\t\t\t\t.join(\"\\n\\n\");\n\t\t\t\t\tassistantMsg.content = [{ type: \"text\", text: thinkingText }, ...assistantTextParts];\n\t\t\t\t} else {\n\t\t\t\t\t// Always send assistant content as a plain string (OpenAI Chat Completions\n\t\t\t\t\t// API standard format). Sending as an array of {type:\"text\", text:\"...\"}\n\t\t\t\t\t// objects is non-standard and causes some models (e.g. DeepSeek V3.2 via\n\t\t\t\t\t// NVIDIA NIM) to mirror the content-block structure literally in their\n\t\t\t\t\t// output, producing recursive nesting like [{'type':'text','text':'[{...}]'}].\n\t\t\t\t\tif (assistantText.length > 0) {\n\t\t\t\t\t\tassistantMsg.content = assistantText;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Use the signature from the first thinking block if available (for llama.cpp server + gpt-oss)\n\t\t\t\t\tlet signature = nonEmptyThinkingBlocks[0].thinkingSignature;\n\t\t\t\t\tif (model.provider === \"opencode-go\" && signature === \"reasoning\") {\n\t\t\t\t\t\tsignature = \"reasoning_content\";\n\t\t\t\t\t}\n\t\t\t\t\tif (signature && signature.length > 0) {\n\t\t\t\t\t\t(assistantMsg as any)[signature] = nonEmptyThinkingBlocks.map((block) => block.thinking).join(\"\\n\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (assistantText.length > 0) {\n\t\t\t\t// Always send assistant content as a plain string (OpenAI Chat Completions\n\t\t\t\t// API standard format). Sending as an array of {type:\"text\", text:\"...\"}\n\t\t\t\t// objects is non-standard and causes some models (e.g. DeepSeek V3.2 via\n\t\t\t\t// NVIDIA NIM) to mirror the content-block structure literally in their\n\t\t\t\t// output, producing recursive nesting like [{'type':'text','text':'[{...}]'}].\n\t\t\t\tassistantMsg.content = assistantText;\n\t\t\t}\n\n\t\t\tconst toolCalls = msg.content.filter(isToolCallBlock);\n\t\t\tif (toolCalls.length > 0) {\n\t\t\t\tassistantMsg.tool_calls = toolCalls.map((tc) => ({\n\t\t\t\t\tid: tc.id,\n\t\t\t\t\ttype: \"function\" as const,\n\t\t\t\t\tfunction: {\n\t\t\t\t\t\tname: tc.name,\n\t\t\t\t\t\targuments: JSON.stringify(tc.arguments),\n\t\t\t\t\t},\n\t\t\t\t}));\n\t\t\t\tconst reasoningDetails = toolCalls\n\t\t\t\t\t.filter((tc) => tc.thoughtSignature)\n\t\t\t\t\t.map((tc) => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\treturn JSON.parse(tc.thoughtSignature!);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.filter(Boolean);\n\t\t\t\tif (reasoningDetails.length > 0) {\n\t\t\t\t\t(assistantMsg as any).reasoning_details = reasoningDetails;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (\n\t\t\t\tcompat.requiresReasoningContentOnAssistantMessages &&\n\t\t\t\tmodel.reasoning &&\n\t\t\t\t(assistantMsg as { reasoning_content?: string }).reasoning_content === undefined\n\t\t\t) {\n\t\t\t\t(assistantMsg as { reasoning_content?: string }).reasoning_content = \"\";\n\t\t\t}\n\t\t\t// Skip assistant messages that have no content and no tool calls.\n\t\t\t// Some providers require \"either content or tool_calls, but not none\".\n\t\t\t// Other providers also don't accept empty assistant messages.\n\t\t\t// This handles aborted assistant responses that got no content.\n\t\t\tconst content = assistantMsg.content;\n\t\t\tconst hasContent =\n\t\t\t\tcontent !== null &&\n\t\t\t\tcontent !== undefined &&\n\t\t\t\t(typeof content === \"string\" ? content.length > 0 : content.length > 0);\n\t\t\tif (!hasContent && !assistantMsg.tool_calls) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tparams.push(assistantMsg);\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\tconst imageBlocks: Array<{ type: \"image_url\"; image_url: { url: string } }> = [];\n\t\t\tlet j = i;\n\n\t\t\tfor (; j < transformedMessages.length && transformedMessages[j].role === \"toolResult\"; j++) {\n\t\t\t\tconst toolMsg = transformedMessages[j] as ToolResultMessage;\n\n\t\t\t\t// Extract text and image content\n\t\t\t\tconst textResult = toolMsg.content\n\t\t\t\t\t.filter(isTextContentBlock)\n\t\t\t\t\t.map((block) => block.text)\n\t\t\t\t\t.join(\"\\n\");\n\t\t\t\tconst hasImages = toolMsg.content.some((c) => c.type === \"image\");\n\n\t\t\t\t// Always send tool result with text (or placeholder if only images)\n\t\t\t\tconst hasText = textResult.length > 0;\n\t\t\t\tconst toolResultText = hasText ? textResult : hasImages ? \"(see attached image)\" : \"(no tool output)\";\n\t\t\t\t// Some providers require the 'name' field in tool results\n\t\t\t\tconst toolResultMsg: ChatCompletionToolMessageParam = {\n\t\t\t\t\trole: \"tool\",\n\t\t\t\t\tcontent: sanitizeSurrogates(toolResultText),\n\t\t\t\t\ttool_call_id: toolMsg.toolCallId,\n\t\t\t\t};\n\t\t\t\tif (compat.requiresToolResultName && toolMsg.toolName) {\n\t\t\t\t\t(toolResultMsg as any).name = toolMsg.toolName;\n\t\t\t\t}\n\t\t\t\tparams.push(toolResultMsg);\n\n\t\t\t\tif (hasImages && model.input.includes(\"image\")) {\n\t\t\t\t\tfor (const block of toolMsg.content) {\n\t\t\t\t\t\tif (isImageContentBlock(block)) {\n\t\t\t\t\t\t\timageBlocks.push({\n\t\t\t\t\t\t\t\ttype: \"image_url\",\n\t\t\t\t\t\t\t\timage_url: {\n\t\t\t\t\t\t\t\t\turl: `data:${block.mimeType};base64,${block.data}`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ti = j - 1;\n\n\t\t\tif (imageBlocks.length > 0) {\n\t\t\t\tif (compat.requiresAssistantAfterToolResult) {\n\t\t\t\t\tparams.push({\n\t\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\t\tcontent: \"I have processed the tool results.\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tparams.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: \"Attached image(s) from tool result:\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...imageBlocks,\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\tlastRole = \"user\";\n\t\t\t} else {\n\t\t\t\tlastRole = \"toolResult\";\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tlastRole = msg.role;\n\t}\n\n\treturn params;\n}\n\nfunction convertTools(\n\ttools: Tool[],\n\tcompat: ResolvedOpenAICompletionsCompat,\n): OpenAI.Chat.Completions.ChatCompletionTool[] {\n\treturn tools.map((tool) => ({\n\t\ttype: \"function\",\n\t\tfunction: {\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: tool.parameters as any, // TypeBox already generates JSON Schema\n\t\t\t// Only include strict if provider supports it. Some reject unknown fields.\n\t\t\t...(compat.supportsStrictMode !== false && { strict: false }),\n\t\t},\n\t}));\n}\n\nfunction parseChunkUsage(\n\trawUsage: {\n\t\tprompt_tokens?: number;\n\t\tcompletion_tokens?: number;\n\t\tcached_tokens?: number;\n\t\tprompt_cache_hit_tokens?: number;\n\t\tprompt_tokens_details?: { cached_tokens?: number; cache_write_tokens?: number };\n\t},\n\tmodel: Model<\"openai-completions\">,\n): AssistantMessage[\"usage\"] {\n\tconst promptTokens = rawUsage.prompt_tokens || 0;\n\tconst cacheReadTokens =\n\t\trawUsage.prompt_tokens_details?.cached_tokens ?? rawUsage.prompt_cache_hit_tokens ?? rawUsage.cached_tokens ?? 0;\n\tconst cacheWriteTokens = rawUsage.prompt_tokens_details?.cache_write_tokens || 0;\n\n\t// Follow documented OpenAI/OpenRouter semantics: cached_tokens is cache-read\n\t// tokens (hits). Providers disagree on placement: OpenAI/OpenRouter use\n\t// prompt_tokens_details.cached_tokens, DeepSeek uses prompt_cache_hit_tokens,\n\t// and Kimi documents top-level usage.cached_tokens on the final usage chunk.\n\t// OpenAI does not document or emit cache_write_tokens, but\n\t// OpenRouter-compatible providers can include it as a separate write count.\n\t// OpenRouter's own provider/tests affirm the separate mapping:\n\t// https://github.com/OpenRouterTeam/ai-sdk-provider/pull/409\n\t// Do not subtract writes from cached_tokens, otherwise spec-compliant\n\t// providers are under-reported. DS4 mirrors this contract too:\n\t// https://github.com/antirez/ds4/pull/29\n\tconst input = Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens);\n\t// OpenAI completion_tokens already includes reasoning_tokens.\n\tconst outputTokens = rawUsage.completion_tokens || 0;\n\tconst usage: AssistantMessage[\"usage\"] = {\n\t\tinput,\n\t\toutput: outputTokens,\n\t\tcacheRead: cacheReadTokens,\n\t\tcacheWrite: cacheWriteTokens,\n\t\ttotalTokens: input + outputTokens + cacheReadTokens + cacheWriteTokens,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n\tcalculateCost(model, usage);\n\treturn usage;\n}\n\nfunction mapStopReason(reason: ChatCompletionChunk.Choice[\"finish_reason\"] | string): {\n\tstopReason: StopReason;\n\terrorMessage?: string;\n} {\n\tif (reason === null) return { stopReason: \"stop\" };\n\tswitch (reason) {\n\t\tcase \"stop\":\n\t\tcase \"end\":\n\t\t\treturn { stopReason: \"stop\" };\n\t\tcase \"length\":\n\t\t\treturn { stopReason: \"length\" };\n\t\tcase \"function_call\":\n\t\tcase \"tool_calls\":\n\t\t\treturn { stopReason: \"toolUse\" };\n\t\tcase \"content_filter\":\n\t\t\treturn { stopReason: \"error\", errorMessage: \"Provider finish_reason: content_filter\" };\n\t\tcase \"network_error\":\n\t\t\treturn { stopReason: \"error\", errorMessage: \"Provider finish_reason: network_error\" };\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tstopReason: \"error\",\n\t\t\t\terrorMessage: `Provider finish_reason: ${reason}`,\n\t\t\t};\n\t}\n}\n\n/**\n * Detect compatibility settings from provider and baseUrl for known providers.\n * Provider takes precedence over URL-based detection since it's explicitly configured.\n * Returns a fully resolved OpenAICompletionsCompat object with all fields set.\n */\nfunction detectCompat(model: Model<\"openai-completions\">): ResolvedOpenAICompletionsCompat {\n\tconst provider = model.provider;\n\tconst baseUrl = model.baseUrl;\n\n\tconst isZai = provider === \"zai\" || baseUrl.includes(\"api.z.ai\");\n\tconst isMoonshot = provider === \"moonshotai\" || provider === \"moonshotai-cn\" || baseUrl.includes(\"api.moonshot.\");\n\tconst isCloudflareWorkersAI = provider === \"cloudflare-workers-ai\" || baseUrl.includes(\"api.cloudflare.com\");\n\tconst isCloudflareAiGateway = provider === \"cloudflare-ai-gateway\" || baseUrl.includes(\"gateway.ai.cloudflare.com\");\n\tconst isAntLing = provider === \"ant-ling\" || baseUrl.includes(\"api.ant-ling.com\");\n\tconst isMiniMax = isMiniMaxModel(model);\n\tconst isDeepSeek = provider === \"deepseek\" || baseUrl.toLowerCase().includes(\"deepseek.com\");\n\n\tconst isNonStandard =\n\t\tprovider === \"cerebras\" ||\n\t\tbaseUrl.includes(\"cerebras.ai\") ||\n\t\tprovider === \"xai\" ||\n\t\tbaseUrl.includes(\"api.x.ai\") ||\n\t\tbaseUrl.includes(\"chutes.ai\") ||\n\t\tisDeepSeek ||\n\t\tisZai ||\n\t\tisMoonshot ||\n\t\tprovider === \"opencode\" ||\n\t\tbaseUrl.includes(\"opencode.ai\") ||\n\t\tisCloudflareWorkersAI ||\n\t\tisCloudflareAiGateway ||\n\t\tisAntLing;\n\n\t// Z.AI ignores max_completion_tokens, so its output cap only applies through max_tokens.\n\tconst isZaiMaxTokensEndpoint = isZai || provider === \"zai-coding-cn\" || baseUrl.includes(\"open.bigmodel.cn\");\n\tconst useMaxTokens =\n\t\tbaseUrl.includes(\"chutes.ai\") ||\n\t\tisDeepSeek ||\n\t\tisMoonshot ||\n\t\tisCloudflareAiGateway ||\n\t\tisAntLing ||\n\t\tisZaiMaxTokensEndpoint;\n\n\tconst isGrok = provider === \"xai\" || baseUrl.includes(\"api.x.ai\");\n\tconst cacheControlFormat = provider === \"openrouter\" && /^~?anthropic\\//.test(model.id) ? \"anthropic\" : undefined;\n\tconst isOpenRouter = provider === \"openrouter\" || baseUrl.includes(\"openrouter.ai\");\n\n\treturn {\n\t\tsupportsStore: !isNonStandard,\n\t\tsupportsDeveloperRole: !isNonStandard,\n\t\tsupportsReasoningEffort: !isGrok && !isZai && !isMoonshot && !isCloudflareAiGateway && !isAntLing,\n\t\tsupportsUsageInStreaming: true,\n\t\tsupportsFinishReason: true,\n\t\tmaxTokensField: useMaxTokens ? \"max_tokens\" : \"max_completion_tokens\",\n\t\trequiresToolResultName: false,\n\t\trequiresAssistantAfterToolResult: false,\n\t\trequiresThinkingAsText: false,\n\t\trequiresReasoningContentOnAssistantMessages: isDeepSeek,\n\t\tthinkingFormat: isMiniMax\n\t\t\t? \"minimax\"\n\t\t\t: isDeepSeek\n\t\t\t\t? \"deepseek\"\n\t\t\t\t: isZai\n\t\t\t\t\t? \"zai\"\n\t\t\t\t\t: isAntLing\n\t\t\t\t\t\t? \"ant-ling\"\n\t\t\t\t\t\t: provider === \"openrouter\" || baseUrl.includes(\"openrouter.ai\")\n\t\t\t\t\t\t\t? \"openrouter\"\n\t\t\t\t\t\t\t: \"openai\",\n\t\topenRouterRouting: {},\n\t\topenRouterImageGeneration: false,\n\t\tvercelGatewayRouting: {},\n\t\tzaiToolStream: false,\n\t\tsupportsStrictMode: !isMoonshot && !isCloudflareAiGateway,\n\t\tcacheControlFormat,\n\t\tsendSessionAffinityHeaders: isOpenRouter,\n\t\tsessionAffinityFormat: isOpenRouter ? \"openrouter\" : \"openai\",\n\t\tsupportsLongCacheRetention: !(isCloudflareWorkersAI || isCloudflareAiGateway || isAntLing),\n\t};\n}\n\n/**\n * Get resolved compatibility settings for a model.\n * Uses explicit model.compat if provided, otherwise auto-detects from provider/URL.\n */\nfunction getCompat(model: Model<\"openai-completions\">): ResolvedOpenAICompletionsCompat {\n\tconst detected = detectCompat(model);\n\tif (!model.compat) return detected;\n\n\treturn {\n\t\tsupportsStore: model.compat.supportsStore ?? detected.supportsStore,\n\t\tsupportsDeveloperRole: model.compat.supportsDeveloperRole ?? detected.supportsDeveloperRole,\n\t\tsupportsReasoningEffort: model.compat.supportsReasoningEffort ?? detected.supportsReasoningEffort,\n\t\tsupportsUsageInStreaming: model.compat.supportsUsageInStreaming ?? detected.supportsUsageInStreaming,\n\t\tsupportsFinishReason: model.compat.supportsFinishReason ?? detected.supportsFinishReason,\n\t\tmaxTokensField: model.compat.maxTokensField ?? detected.maxTokensField,\n\t\trequiresToolResultName: model.compat.requiresToolResultName ?? detected.requiresToolResultName,\n\t\trequiresAssistantAfterToolResult:\n\t\t\tmodel.compat.requiresAssistantAfterToolResult ?? detected.requiresAssistantAfterToolResult,\n\t\trequiresThinkingAsText: model.compat.requiresThinkingAsText ?? detected.requiresThinkingAsText,\n\t\trequiresReasoningContentOnAssistantMessages:\n\t\t\tmodel.compat.requiresReasoningContentOnAssistantMessages ??\n\t\t\tdetected.requiresReasoningContentOnAssistantMessages,\n\t\tthinkingFormat: model.compat.thinkingFormat ?? detected.thinkingFormat,\n\t\topenRouterRouting: model.compat.openRouterRouting ?? {},\n\t\topenRouterImageGeneration: model.compat.openRouterImageGeneration ?? detected.openRouterImageGeneration,\n\t\tvercelGatewayRouting: model.compat.vercelGatewayRouting ?? detected.vercelGatewayRouting,\n\t\tzaiToolStream: model.compat.zaiToolStream ?? detected.zaiToolStream,\n\t\tsupportsStrictMode: model.compat.supportsStrictMode ?? detected.supportsStrictMode,\n\t\tcacheControlFormat: model.compat.cacheControlFormat ?? detected.cacheControlFormat,\n\t\tsendSessionAffinityHeaders: model.compat.sendSessionAffinityHeaders ?? detected.sendSessionAffinityHeaders,\n\t\tsessionAffinityFormat: model.compat.sessionAffinityFormat ?? detected.sessionAffinityFormat,\n\t\tsupportsLongCacheRetention: model.compat.supportsLongCacheRetention ?? detected.supportsLongCacheRetention,\n\t};\n}\n"]}
@@ -44,9 +44,8 @@ function isImageContentBlock(block) {
44
44
  return block.type === "image";
45
45
  }
46
46
  function isMiniMaxModel(model) {
47
- // LLM Dynamix is currently allowlisted to MiniMax-M3 on the local runtime;
48
- // retain the provider match when discovery normalizes the model ID.
49
- return model.provider === "llmdynamix" || model.id.toLowerCase().includes("minimax-m3");
47
+ // Merc-native: shared gateways carry multiple families; infer MiniMax only from the id.
48
+ return model.id.toLowerCase().includes("minimax-m3");
50
49
  }
51
50
  function createThinkingTagFilter(enabled) {
52
51
  let buffer = "";
@@ -237,7 +236,7 @@ export const streamOpenAICompletions = (model, context, options) => {
237
236
  const toolCallBlocksById = new Map();
238
237
  const pendingReasoningDetailsByToolCallId = new Map();
239
238
  const blocks = output.content;
240
- const thinkingTagFilter = createThinkingTagFilter(isMiniMaxModel(model) || compat.thinkingFormat === "minimax");
239
+ const thinkingTagFilter = createThinkingTagFilter(compat.thinkingFormat === "minimax");
241
240
  const getContentIndex = (block) => blocks.indexOf(block);
242
241
  const finishBlock = (block) => {
243
242
  const contentIndex = getContentIndex(block);
@@ -410,8 +409,7 @@ export const streamOpenAICompletions = (model, context, options) => {
410
409
  }
411
410
  }
412
411
  if (foundReasoningField &&
413
- !((isMiniMaxModel(model) || compat.thinkingFormat === "minimax") &&
414
- (!options?.reasoningEffort || model.reasoning === false))) {
412
+ !(compat.thinkingFormat === "minimax" && (!options?.reasoningEffort || model.reasoning === false))) {
415
413
  const delta = deltaFields[foundReasoningField];
416
414
  if (typeof delta === "string" && delta.length > 0) {
417
415
  const thinkingSignature = model.provider === "opencode-go" && foundReasoningField === "reasoning"
@@ -644,7 +642,7 @@ function buildParams(model, context, options, compat = getCompat(model), cacheRe
644
642
  }
645
643
  }
646
644
  }
647
- else if (compat.thinkingFormat === "minimax" || isMiniMaxModel(model)) {
645
+ else if (compat.thinkingFormat === "minimax") {
648
646
  const minimaxParams = params;
649
647
  minimaxParams.thinking = { type: options?.reasoningEffort ? "adaptive" : "disabled" };
650
648
  minimaxParams.reasoning_split = true;
@@ -1161,7 +1159,7 @@ function getCompat(model) {
1161
1159
  requiresThinkingAsText: model.compat.requiresThinkingAsText ?? detected.requiresThinkingAsText,
1162
1160
  requiresReasoningContentOnAssistantMessages: model.compat.requiresReasoningContentOnAssistantMessages ??
1163
1161
  detected.requiresReasoningContentOnAssistantMessages,
1164
- thinkingFormat: isMiniMaxModel(model) ? "minimax" : (model.compat.thinkingFormat ?? detected.thinkingFormat),
1162
+ thinkingFormat: model.compat.thinkingFormat ?? detected.thinkingFormat,
1165
1163
  openRouterRouting: model.compat.openRouterRouting ?? {},
1166
1164
  openRouterImageGeneration: model.compat.openRouterImageGeneration ?? detected.openRouterImageGeneration,
1167
1165
  vercelGatewayRouting: model.compat.vercelGatewayRouting ?? detected.vercelGatewayRouting,
@@ -1 +1 @@
1
- {"version":3,"file":"openai-completions.js","sourceRoot":"","sources":["../../src/providers/openai-completions.ts"],"names":[],"mappings":"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","sourcesContent":["import OpenAI from \"openai\";\nimport type {\n\tChatCompletion,\n\tChatCompletionAssistantMessageParam,\n\tChatCompletionChunk,\n\tChatCompletionContentPart,\n\tChatCompletionContentPartImage,\n\tChatCompletionContentPartText,\n\tChatCompletionDeveloperMessageParam,\n\tChatCompletionMessageParam,\n\tChatCompletionSystemMessageParam,\n\tChatCompletionToolMessageParam,\n} from \"openai/resources/chat/completions.js\";\nimport { getEnvApiKey } from \"../env-api-keys.js\";\nimport { calculateCost, clampThinkingLevel } from \"../models.js\";\nimport type {\n\tAssistantMessage,\n\tCacheRetention,\n\tContext,\n\tImageContent,\n\tMessage,\n\tModel,\n\tOpenAICompletionsCompat,\n\tProviderEnv,\n\tSimpleStreamOptions,\n\tStopReason,\n\tStreamFunction,\n\tStreamOptions,\n\tTextContent,\n\tThinkingContent,\n\tTool,\n\tToolCall,\n\tToolResultMessage,\n} from \"../types.js\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.js\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.js\";\nimport { headersToRecord } from \"../utils/headers.js\";\nimport { finalizeToolCallArguments, parseStreamingJson } from \"../utils/json-parse.js\";\nimport { getProviderEnvValue } from \"../utils/provider-env.js\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.js\";\nimport { createProviderToolCallIdNormalizer } from \"../utils/tool-call-id.js\";\nimport { isCloudflareProvider, resolveCloudflareBaseUrl } from \"./cloudflare.js\";\nimport { buildCopilotDynamicHeaders, hasCopilotVisionInput } from \"./github-copilot-headers.js\";\nimport { clampOpenAIPromptCacheKey } from \"./openai-prompt-cache.js\";\nimport { buildBaseOptions } from \"./simple-options.js\";\nimport { transformMessages } from \"./transform-messages.js\";\n\n/**\n * Check if conversation messages contain tool calls or tool results.\n * This is needed because Anthropic (via proxy) requires the tools param\n * to be present when messages include tool_calls or tool role messages.\n */\nfunction hasToolHistory(messages: Message[]): boolean {\n\tfor (const msg of messages) {\n\t\tif (msg.role === \"toolResult\") {\n\t\t\treturn true;\n\t\t}\n\t\tif (msg.role === \"assistant\") {\n\t\t\tif (msg.content.some((block) => block.type === \"toolCall\")) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction isTextContentBlock(block: { type: string }): block is TextContent {\n\treturn block.type === \"text\";\n}\n\nfunction isThinkingContentBlock(block: { type: string }): block is ThinkingContent {\n\treturn block.type === \"thinking\";\n}\n\nfunction isToolCallBlock(block: { type: string }): block is ToolCall {\n\treturn block.type === \"toolCall\";\n}\n\nfunction isImageContentBlock(block: { type: string }): block is ImageContent {\n\treturn block.type === \"image\";\n}\n\nfunction isMiniMaxModel(model: Model<\"openai-completions\">): boolean {\n\t// LLM Dynamix is currently allowlisted to MiniMax-M3 on the local runtime;\n\t// retain the provider match when discovery normalizes the model ID.\n\treturn model.provider === \"llmdynamix\" || model.id.toLowerCase().includes(\"minimax-m3\");\n}\n\nfunction createThinkingTagFilter(enabled: boolean): { push: (chunk: string) => string; flush: () => string } {\n\tlet buffer = \"\";\n\tlet inThinking = false;\n\tconst openingTag = \"<think\";\n\tconst closingTag = \"</think>\";\n\n\tconst consume = (): string => {\n\t\tlet visible = \"\";\n\t\twhile (buffer.length > 0) {\n\t\t\tconst lower = buffer.toLowerCase();\n\t\t\tif (inThinking) {\n\t\t\t\tconst end = lower.indexOf(closingTag);\n\t\t\t\tif (end < 0) {\n\t\t\t\t\tbuffer = \"\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbuffer = buffer.slice(end + closingTag.length);\n\t\t\t\tinThinking = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst start = lower.indexOf(openingTag);\n\t\t\tif (start < 0) {\n\t\t\t\tconst strayClosing = lower.indexOf(closingTag);\n\t\t\t\tif (strayClosing >= 0) {\n\t\t\t\t\tvisible += buffer.slice(0, strayClosing);\n\t\t\t\t\tbuffer = buffer.slice(strayClosing + closingTag.length);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst partialStart = Math.max(0, buffer.length - openingTag.length + 1);\n\t\t\t\tconst partial = buffer.slice(partialStart).toLowerCase();\n\t\t\t\tconst closingPartialStart = Math.max(0, buffer.length - closingTag.length + 1);\n\t\t\t\tconst closingPartial = buffer.slice(closingPartialStart).toLowerCase();\n\t\t\t\tconst partialLength = Math.max(\n\t\t\t\t\tpartial && openingTag.startsWith(partial) ? partial.length : 0,\n\t\t\t\t\tclosingPartial && closingTag.startsWith(closingPartial) ? closingPartial.length : 0,\n\t\t\t\t);\n\t\t\t\tvisible += buffer.slice(0, buffer.length - partialLength);\n\t\t\t\tbuffer = buffer.slice(buffer.length - partialLength);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tvisible += buffer.slice(0, start);\n\t\t\tbuffer = buffer.slice(start);\n\t\t\tconst tagEnd = buffer.indexOf(\">\");\n\t\t\tif (tagEnd < 0) break;\n\t\t\tbuffer = buffer.slice(tagEnd + 1);\n\t\t\tinThinking = true;\n\t\t}\n\t\treturn visible;\n\t};\n\n\treturn {\n\t\tpush: (chunk) => {\n\t\t\tif (!enabled) return chunk;\n\t\t\tbuffer += chunk;\n\t\t\treturn consume();\n\t\t},\n\t\tflush: () => (enabled ? consume() : buffer),\n\t};\n}\n\nfunction isEncryptedReasoningDetail(detail: unknown): detail is OpenAIEncryptedReasoningDetail {\n\tif (typeof detail !== \"object\" || detail === null) {\n\t\treturn false;\n\t}\n\tconst candidate = detail as Record<string, unknown>;\n\treturn (\n\t\tcandidate.type === \"reasoning.encrypted\" &&\n\t\ttypeof candidate.id === \"string\" &&\n\t\tcandidate.id.length > 0 &&\n\t\ttypeof candidate.data === \"string\" &&\n\t\tcandidate.data.length > 0\n\t);\n}\n\nexport interface OpenAICompletionsOptions extends StreamOptions {\n\ttoolChoice?: \"auto\" | \"none\" | \"required\" | { type: \"function\"; function: { name: string } };\n\treasoningEffort?: \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n}\n\ninterface OpenAICompatCacheControl {\n\ttype: \"ephemeral\";\n\tttl?: string;\n}\n\ntype ResolvedOpenAICompletionsCompat = Omit<Required<OpenAICompletionsCompat>, \"cacheControlFormat\"> & {\n\tcacheControlFormat?: OpenAICompletionsCompat[\"cacheControlFormat\"];\n};\n\ntype ChatCompletionInstructionMessageParam = ChatCompletionDeveloperMessageParam | ChatCompletionSystemMessageParam;\n\ntype OpenAIEncryptedReasoningDetail = {\n\ttype: \"reasoning.encrypted\";\n\tid: string;\n\tdata: string;\n};\n\ntype ChatCompletionTextPartWithCacheControl = ChatCompletionContentPartText & {\n\tcache_control?: OpenAICompatCacheControl;\n};\n\ntype ChatCompletionToolWithCacheControl = OpenAI.Chat.Completions.ChatCompletionTool & {\n\tcache_control?: OpenAICompatCacheControl;\n};\n\ninterface OpenRouterGeneratedImage {\n\timage_url?: string | { url?: string };\n}\n\ntype OpenRouterImageGenerationMessage = ChatCompletion[\"choices\"][number][\"message\"] & {\n\timages?: OpenRouterGeneratedImage[];\n};\n\ntype OpenRouterImageGenerationChoice = ChatCompletion[\"choices\"][number] & {\n\tmessage: OpenRouterImageGenerationMessage;\n};\n\ntype OpenRouterImageGenerationResponse = ChatCompletion & {\n\tchoices: OpenRouterImageGenerationChoice[];\n};\n\nfunction isOpenRouterImageGenerationModel(model: Model<\"openai-completions\">): boolean {\n\treturn model.provider === \"openrouter\" && model.compat?.openRouterImageGeneration === true;\n}\n\nfunction resolveCacheRetention(cacheRetention?: CacheRetention, env?: ProviderEnv): CacheRetention {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\tif (getProviderEnvValue(\"MERC_CACHE_RETENTION\", env) === \"long\") {\n\t\treturn \"long\";\n\t}\n\treturn \"short\";\n}\n\nexport const streamOpenAICompletions: StreamFunction<\"openai-completions\", OpenAICompletionsOptions> = (\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\toptions?: OpenAICompletionsOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\ttry {\n\t\t\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider, options?.env) || \"\";\n\t\t\tconst compat = getCompat(model);\n\t\t\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\t\t\tconst cacheSessionId = cacheRetention === \"none\" ? undefined : options?.sessionId;\n\t\t\tconst client = createClient(model, context, apiKey, options?.headers, cacheSessionId, compat, options?.env);\n\t\t\tlet params = buildParams(model, context, options, compat, cacheRetention);\n\t\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\t\tif (nextParams !== undefined) {\n\t\t\t\tparams = nextParams as OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming;\n\t\t\t}\n\t\t\tconst requestOptions = {\n\t\t\t\t...(options?.signal ? { signal: options.signal } : {}),\n\t\t\t\t...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n\t\t\t\tmaxRetries: options?.maxRetries ?? 0,\n\t\t\t};\n\t\t\tif (isOpenRouterImageGenerationModel(model)) {\n\t\t\t\tconst { stream_options: _streamOptions, ...nonStreamingBaseParams } = params;\n\t\t\t\tconst nonStreamingParams = {\n\t\t\t\t\t...nonStreamingBaseParams,\n\t\t\t\t\tstream: false,\n\t\t\t\t} as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming;\n\t\t\t\tconst { data: response, response: rawResponse } = await client.chat.completions\n\t\t\t\t\t.create(nonStreamingParams, requestOptions)\n\t\t\t\t\t.withResponse();\n\t\t\t\tawait options?.onResponse?.(\n\t\t\t\t\t{ status: rawResponse.status, headers: headersToRecord(rawResponse.headers) },\n\t\t\t\t\tmodel,\n\t\t\t\t);\n\t\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\t\tconst imageResponse = response as OpenRouterImageGenerationResponse;\n\t\t\t\toutput.responseId ||= imageResponse.id;\n\t\t\t\toutput.usage = parseChunkUsage(imageResponse.usage ?? {}, model);\n\n\t\t\t\tconst choice = imageResponse.choices[0];\n\t\t\t\tif (choice) {\n\t\t\t\t\tconst text = choice.message.content;\n\t\t\t\t\tif (text) {\n\t\t\t\t\t\tconst textBlock: TextContent = { type: \"text\", text };\n\t\t\t\t\t\toutput.content.push(textBlock);\n\t\t\t\t\t\tconst contentIndex = output.content.length - 1;\n\t\t\t\t\t\tstream.push({ type: \"text_start\", contentIndex, partial: output });\n\t\t\t\t\t\tstream.push({ type: \"text_delta\", contentIndex, delta: text, partial: output });\n\t\t\t\t\t\tstream.push({ type: \"text_end\", contentIndex, content: text, partial: output });\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const image of choice.message.images ?? []) {\n\t\t\t\t\t\tconst imageUrl = typeof image.image_url === \"string\" ? image.image_url : image.image_url?.url;\n\t\t\t\t\t\tif (!imageUrl?.startsWith(\"data:\")) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst matches = imageUrl.match(/^data:([^;]+);base64,(.+)$/);\n\t\t\t\t\t\tif (!matches) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst imageBlock: ImageContent = {\n\t\t\t\t\t\t\ttype: \"image\",\n\t\t\t\t\t\t\tmimeType: matches[1],\n\t\t\t\t\t\t\tdata: matches[2],\n\t\t\t\t\t\t};\n\t\t\t\t\t\toutput.content.push(imageBlock);\n\t\t\t\t\t\tconst contentIndex = output.content.length - 1;\n\t\t\t\t\t\tstream.push({ type: \"image_start\", contentIndex, partial: output });\n\t\t\t\t\t\tstream.push({ type: \"image_end\", contentIndex, image: imageBlock, partial: output });\n\t\t\t\t\t}\n\n\t\t\t\t\tif (choice.finish_reason) {\n\t\t\t\t\t\tconst finishReasonResult = mapStopReason(choice.finish_reason);\n\t\t\t\t\t\toutput.stopReason = finishReasonResult.stopReason;\n\t\t\t\t\t\tif (finishReasonResult.errorMessage) {\n\t\t\t\t\t\t\toutput.errorMessage = finishReasonResult.errorMessage;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (output.stopReason === \"stop\" || output.stopReason === \"length\" || output.stopReason === \"toolUse\") {\n\t\t\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\t\t} else {\n\t\t\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\t\t}\n\t\t\t\tstream.end();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { data: openaiStream, response } = await client.chat.completions\n\t\t\t\t.create(params, requestOptions)\n\t\t\t\t.withResponse();\n\t\t\tawait options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\tinterface StreamingToolCallBlock extends ToolCall {\n\t\t\t\tpartialArgs?: string;\n\t\t\t\tstreamIndex?: number;\n\t\t\t}\n\t\t\ttype StreamingBlock = TextContent | ThinkingContent | StreamingToolCallBlock;\n\t\t\ttype StreamingToolCallDelta = NonNullable<ChatCompletionChunk.Choice.Delta[\"tool_calls\"]>[number];\n\n\t\t\tlet textBlock: TextContent | null = null;\n\t\t\tlet thinkingBlock: ThinkingContent | null = null;\n\t\t\tlet hasFinishReason = false;\n\t\t\tlet hasIncompleteToolCallArguments = false;\n\t\t\tconst toolCallBlocksByIndex = new Map<number, StreamingToolCallBlock>();\n\t\t\tconst toolCallBlocksById = new Map<string, StreamingToolCallBlock>();\n\t\t\tconst pendingReasoningDetailsByToolCallId = new Map<string, string>();\n\t\t\tconst blocks = output.content as StreamingBlock[];\n\t\t\tconst thinkingTagFilter = createThinkingTagFilter(\n\t\t\t\tisMiniMaxModel(model) || compat.thinkingFormat === \"minimax\",\n\t\t\t);\n\t\t\tconst getContentIndex = (block: StreamingBlock) => blocks.indexOf(block);\n\t\t\tconst finishBlock = (block: StreamingBlock) => {\n\t\t\t\tconst contentIndex = getContentIndex(block);\n\t\t\t\tif (contentIndex === -1) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (block.type === \"text\") {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\tcontentIndex,\n\t\t\t\t\t\tcontent: block.text,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t} else if (block.type === \"thinking\") {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\tcontentIndex,\n\t\t\t\t\t\tcontent: block.thinking,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\t// Without finish_reason, only strictly valid raw arguments prove the call was not cut off.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tJSON.parse(block.partialArgs ?? \"\");\n\t\t\t\t\t} catch {\n\t\t\t\t\t\thasIncompleteToolCallArguments = true;\n\t\t\t\t\t}\n\t\t\t\t\tfinalizeToolCallArguments(block, block.partialArgs);\n\t\t\t\t\t// Finalize in-place and strip the scratch buffers so replay only\n\t\t\t\t\t// carries parsed arguments.\n\t\t\t\t\tdelete block.partialArgs;\n\t\t\t\t\tdelete block.streamIndex;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\t\tcontentIndex,\n\t\t\t\t\t\ttoolCall: block,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst ensureTextBlock = () => {\n\t\t\t\tif (!textBlock) {\n\t\t\t\t\ttextBlock = { type: \"text\", text: \"\" };\n\t\t\t\t\tblocks.push(textBlock);\n\t\t\t\t\tstream.push({ type: \"text_start\", contentIndex: getContentIndex(textBlock), partial: output });\n\t\t\t\t}\n\t\t\t\treturn textBlock;\n\t\t\t};\n\t\t\tconst appendTextDelta = (delta: string) => {\n\t\t\t\tif (!delta) return;\n\t\t\t\tconst block = ensureTextBlock();\n\t\t\t\tblock.text += delta;\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\tdelta,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t};\n\t\t\tconst ensureThinkingBlock = (thinkingSignature: string) => {\n\t\t\t\tif (!thinkingBlock) {\n\t\t\t\t\tthinkingBlock = {\n\t\t\t\t\t\ttype: \"thinking\",\n\t\t\t\t\t\tthinking: \"\",\n\t\t\t\t\t\tthinkingSignature,\n\t\t\t\t\t};\n\t\t\t\t\tblocks.push(thinkingBlock);\n\t\t\t\t\tstream.push({ type: \"thinking_start\", contentIndex: getContentIndex(thinkingBlock), partial: output });\n\t\t\t\t}\n\t\t\t\treturn thinkingBlock;\n\t\t\t};\n\t\t\tconst applyPendingReasoningDetail = (block: StreamingToolCallBlock) => {\n\t\t\t\tif (!block.id) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst pendingReasoningDetail = pendingReasoningDetailsByToolCallId.get(block.id);\n\t\t\t\tif (pendingReasoningDetail) {\n\t\t\t\t\tblock.thoughtSignature = pendingReasoningDetail;\n\t\t\t\t\tpendingReasoningDetailsByToolCallId.delete(block.id);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst ensureToolCallBlock = (toolCall: StreamingToolCallDelta) => {\n\t\t\t\tconst streamIndex = typeof toolCall.index === \"number\" ? toolCall.index : undefined;\n\t\t\t\tlet block = streamIndex !== undefined ? toolCallBlocksByIndex.get(streamIndex) : undefined;\n\t\t\t\tif (!block && toolCall.id) {\n\t\t\t\t\tblock = toolCallBlocksById.get(toolCall.id);\n\t\t\t\t}\n\t\t\t\tif (!block) {\n\t\t\t\t\tblock = {\n\t\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\t\tid: toolCall.id || \"\",\n\t\t\t\t\t\tname: toolCall.function?.name || \"\",\n\t\t\t\t\t\targuments: {},\n\t\t\t\t\t\tpartialArgs: \"\",\n\t\t\t\t\t\tstreamIndex,\n\t\t\t\t\t};\n\t\t\t\t\tif (streamIndex !== undefined) {\n\t\t\t\t\t\ttoolCallBlocksByIndex.set(streamIndex, block);\n\t\t\t\t\t}\n\t\t\t\t\tif (toolCall.id) {\n\t\t\t\t\t\ttoolCallBlocksById.set(toolCall.id, block);\n\t\t\t\t\t}\n\t\t\t\t\tblocks.push(block);\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"toolcall_start\",\n\t\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (streamIndex !== undefined && block.streamIndex === undefined) {\n\t\t\t\t\tblock.streamIndex = streamIndex;\n\t\t\t\t\ttoolCallBlocksByIndex.set(streamIndex, block);\n\t\t\t\t}\n\t\t\t\tif (toolCall.id) {\n\t\t\t\t\ttoolCallBlocksById.set(toolCall.id, block);\n\t\t\t\t}\n\t\t\t\tapplyPendingReasoningDetail(block);\n\t\t\t\treturn block;\n\t\t\t};\n\n\t\t\tfor await (const chunk of openaiStream) {\n\t\t\t\tif (!chunk || typeof chunk !== \"object\") continue;\n\n\t\t\t\t// OpenAI documents ChatCompletionChunk.id as the unique chat completion identifier,\n\t\t\t\t// and each chunk in a streamed completion carries the same id.\n\t\t\t\toutput.responseId ||= chunk.id;\n\t\t\t\tif (typeof chunk.model === \"string\" && chunk.model.length > 0 && chunk.model !== model.id) {\n\t\t\t\t\toutput.responseModel ||= chunk.model;\n\t\t\t\t}\n\t\t\t\tif (chunk.usage) {\n\t\t\t\t\toutput.usage = parseChunkUsage(chunk.usage, model);\n\t\t\t\t}\n\n\t\t\t\tconst choice = Array.isArray(chunk.choices) ? chunk.choices[0] : undefined;\n\t\t\t\tif (!choice) continue;\n\n\t\t\t\t// Fallback: some providers (e.g., Moonshot) return usage\n\t\t\t\t// in choice.usage instead of the standard chunk.usage\n\t\t\t\tif (!chunk.usage && (choice as any).usage) {\n\t\t\t\t\toutput.usage = parseChunkUsage((choice as any).usage, model);\n\t\t\t\t}\n\n\t\t\t\tif (choice.finish_reason) {\n\t\t\t\t\tconst finishReasonResult = mapStopReason(choice.finish_reason);\n\t\t\t\t\toutput.stopReason = finishReasonResult.stopReason;\n\t\t\t\t\tif (finishReasonResult.errorMessage) {\n\t\t\t\t\t\toutput.errorMessage = finishReasonResult.errorMessage;\n\t\t\t\t\t}\n\t\t\t\t\thasFinishReason = true;\n\t\t\t\t}\n\n\t\t\t\tif (choice.delta) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tchoice.delta.content !== null &&\n\t\t\t\t\t\tchoice.delta.content !== undefined &&\n\t\t\t\t\t\tchoice.delta.content.length > 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tappendTextDelta(thinkingTagFilter.push(choice.delta.content));\n\t\t\t\t\t}\n\n\t\t\t\t\t// Some endpoints return reasoning in reasoning_content (llama.cpp),\n\t\t\t\t\t// or reasoning (other openai compatible endpoints)\n\t\t\t\t\t// Use the first non-empty reasoning field to avoid duplication\n\t\t\t\t\t// (e.g., chutes.ai returns both reasoning_content and reasoning with same content)\n\t\t\t\t\tconst reasoningFields = [\"reasoning_content\", \"reasoning\", \"reasoning_text\"];\n\t\t\t\t\tconst deltaFields = choice.delta as Record<string, unknown>;\n\t\t\t\t\tlet foundReasoningField: string | null = null;\n\t\t\t\t\tfor (const field of reasoningFields) {\n\t\t\t\t\t\tconst value = deltaFields[field];\n\t\t\t\t\t\tif (typeof value === \"string\" && value.length > 0) {\n\t\t\t\t\t\t\tfoundReasoningField = field;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tfoundReasoningField &&\n\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t(isMiniMaxModel(model) || compat.thinkingFormat === \"minimax\") &&\n\t\t\t\t\t\t\t(!options?.reasoningEffort || model.reasoning === false)\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst delta = deltaFields[foundReasoningField];\n\t\t\t\t\t\tif (typeof delta === \"string\" && delta.length > 0) {\n\t\t\t\t\t\t\tconst thinkingSignature =\n\t\t\t\t\t\t\t\tmodel.provider === \"opencode-go\" && foundReasoningField === \"reasoning\"\n\t\t\t\t\t\t\t\t\t? \"reasoning_content\"\n\t\t\t\t\t\t\t\t\t: foundReasoningField;\n\t\t\t\t\t\t\tconst block = ensureThinkingBlock(thinkingSignature);\n\t\t\t\t\t\t\tblock.thinking += delta;\n\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\t\t\t\tdelta,\n\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (choice?.delta?.tool_calls) {\n\t\t\t\t\t\tfor (const toolCall of choice.delta.tool_calls) {\n\t\t\t\t\t\t\tconst block = ensureToolCallBlock(toolCall);\n\t\t\t\t\t\t\tif (!block.id && toolCall.id) {\n\t\t\t\t\t\t\t\tblock.id = toolCall.id;\n\t\t\t\t\t\t\t\ttoolCallBlocksById.set(toolCall.id, block);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!block.name && toolCall.function?.name) {\n\t\t\t\t\t\t\t\tblock.name = toolCall.function.name;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlet delta = \"\";\n\t\t\t\t\t\t\tif (toolCall.function?.arguments) {\n\t\t\t\t\t\t\t\tdelta = toolCall.function.arguments;\n\t\t\t\t\t\t\t\tblock.partialArgs = (block.partialArgs ?? \"\") + toolCall.function.arguments;\n\t\t\t\t\t\t\t\tblock.arguments = parseStreamingJson(block.partialArgs);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\t\t\t\tdelta,\n\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst reasoningDetails = (choice.delta as { reasoning_details?: unknown }).reasoning_details;\n\t\t\t\t\tif (Array.isArray(reasoningDetails)) {\n\t\t\t\t\t\tfor (const detail of reasoningDetails) {\n\t\t\t\t\t\t\tif (isEncryptedReasoningDetail(detail)) {\n\t\t\t\t\t\t\t\tconst serializedDetail = JSON.stringify(detail);\n\t\t\t\t\t\t\t\tconst matchingToolCall = toolCallBlocksById.get(detail.id);\n\t\t\t\t\t\t\t\tif (matchingToolCall) {\n\t\t\t\t\t\t\t\t\tmatchingToolCall.thoughtSignature = serializedDetail;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tpendingReasoningDetailsByToolCallId.set(detail.id, serializedDetail);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tappendTextDelta(thinkingTagFilter.flush());\n\n\t\t\tfor (const block of blocks) {\n\t\t\t\tfinishBlock(block);\n\t\t\t}\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"aborted\") {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\t\t\tif (!hasFinishReason && !compat.supportsFinishReason) {\n\t\t\t\tif (hasIncompleteToolCallArguments) {\n\t\t\t\t\tthrow new Error(\"Stream ended without finish_reason and with incomplete tool call arguments\");\n\t\t\t\t}\n\t\t\t\toutput.stopReason = output.content.some((block) => block.type === \"toolCall\") ? \"toolUse\" : \"stop\";\n\t\t\t}\n\t\t\tif (output.stopReason === \"error\") {\n\t\t\t\tthrow new Error(output.errorMessage || \"Provider returned an error stop reason\");\n\t\t\t}\n\t\t\tif (compat.supportsFinishReason && !hasFinishReason) {\n\t\t\t\tthrow new Error(\"Stream ended without finish_reason\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tdelete (block as { index?: number }).index;\n\t\t\t\t// Streaming scratch buffers are only used during parsing; never persist them.\n\t\t\t\tdelete (block as { partialArgs?: string }).partialArgs;\n\t\t\t\tdelete (block as { streamIndex?: number }).streamIndex;\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tconst normalized = normalizeProviderError(error);\n\t\t\toutput.errorMetadata = normalized.errorMetadata;\n\t\t\toutput.errorMessage = formatProviderError(normalized);\n\t\t\t// Some providers via OpenRouter give additional information in this field.\n\t\t\t// normalizeProviderError already stringifies the parsed body (error.error)\n\t\t\t// into errorMessage, so only append the raw metadata when it is not already\n\t\t\t// present to avoid double-printing it.\n\t\t\tconst rawMetadata = (error as any)?.error?.metadata?.raw;\n\t\t\tif (rawMetadata && !output.errorMessage.includes(String(rawMetadata))) {\n\t\t\t\toutput.errorMessage += `\\n${rawMetadata}`;\n\t\t\t}\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimpleOpenAICompletions: StreamFunction<\"openai-completions\", SimpleStreamOptions> = (\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider, options?.env);\n\tif (!apiKey && model.authHeader !== false) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\n\tconst base = buildBaseOptions(model, context, options, apiKey ?? \"\");\n\tconst clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;\n\tconst reasoningEffort = clampedReasoning === \"off\" ? undefined : clampedReasoning;\n\tconst toolChoice = (options as OpenAICompletionsOptions | undefined)?.toolChoice;\n\n\treturn streamOpenAICompletions(model, context, {\n\t\t...base,\n\t\treasoningEffort,\n\t\ttoolChoice,\n\t} satisfies OpenAICompletionsOptions);\n};\n\nfunction createClient(\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\tapiKey?: string,\n\toptionsHeaders?: Record<string, string>,\n\tsessionId?: string,\n\tcompat: ResolvedOpenAICompletionsCompat = getCompat(model),\n\tenv?: ProviderEnv,\n) {\n\tconst noAuth = model.authHeader === false;\n\tif (!apiKey && !noAuth) {\n\t\tconst configuredApiKey = getProviderEnvValue(\"OPENAI_API_KEY\", env);\n\t\tif (!configuredApiKey) {\n\t\t\tthrow new Error(\n\t\t\t\t\"OpenAI API key is required. Set OPENAI_API_KEY environment variable or pass it as an argument.\",\n\t\t\t);\n\t\t}\n\t\tapiKey = configuredApiKey;\n\t}\n\tif (!apiKey) apiKey = \"merc-no-auth\";\n\n\tconst headers = { ...model.headers };\n\tif (model.provider === \"github-copilot\") {\n\t\tconst hasImages = hasCopilotVisionInput(context.messages);\n\t\tconst copilotHeaders = buildCopilotDynamicHeaders({\n\t\t\tmessages: context.messages,\n\t\t\thasImages,\n\t\t});\n\t\tObject.assign(headers, copilotHeaders);\n\t}\n\n\tif (sessionId && compat.sendSessionAffinityHeaders) {\n\t\tif (compat.sessionAffinityFormat === \"openrouter\") {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t} else {\n\t\t\tif (compat.sessionAffinityFormat === \"openai\") headers.session_id = sessionId;\n\t\t\theaders[\"x-client-request-id\"] = sessionId;\n\t\t\theaders[\"x-session-affinity\"] = sessionId;\n\t\t}\n\t}\n\n\t// Merge options headers last so they can override defaults\n\tif (optionsHeaders) {\n\t\tObject.assign(headers, optionsHeaders);\n\t}\n\n\tconst defaultHeaders = noAuth\n\t\t? { ...headers, Authorization: null }\n\t\t: model.provider === \"cloudflare-ai-gateway\"\n\t\t\t? {\n\t\t\t\t\t...headers,\n\t\t\t\t\tAuthorization: headers.Authorization ?? null,\n\t\t\t\t\t\"cf-aig-authorization\": `Bearer ${apiKey}`,\n\t\t\t\t}\n\t\t\t: headers;\n\n\treturn new OpenAI({\n\t\tapiKey,\n\t\tbaseURL: isCloudflareProvider(model.provider) ? resolveCloudflareBaseUrl(model, env) : model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tdefaultHeaders,\n\t});\n}\n\nfunction buildParams(\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\toptions?: OpenAICompletionsOptions,\n\tcompat: ResolvedOpenAICompletionsCompat = getCompat(model),\n\tcacheRetention: CacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env),\n) {\n\tconst messages = convertMessages(model, context, compat);\n\tconst cacheControl = getCompatCacheControl(compat, cacheRetention);\n\n\tconst params: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {\n\t\tmodel: model.id,\n\t\tmessages,\n\t\tstream: true,\n\t\tprompt_cache_key:\n\t\t\t(model.baseUrl.includes(\"api.openai.com\") && cacheRetention !== \"none\") ||\n\t\t\t(cacheRetention === \"long\" && compat.supportsLongCacheRetention)\n\t\t\t\t? clampOpenAIPromptCacheKey(options?.sessionId)\n\t\t\t\t: undefined,\n\t\tprompt_cache_retention: cacheRetention === \"long\" && compat.supportsLongCacheRetention ? \"24h\" : undefined,\n\t};\n\n\tif (isOpenRouterImageGenerationModel(model)) {\n\t\tReflect.set(params, \"modalities\", [\"image\"]);\n\t}\n\n\tif (compat.supportsUsageInStreaming !== false) {\n\t\t(params as any).stream_options = { include_usage: true };\n\t}\n\n\tif (compat.supportsStore) {\n\t\tparams.store = false;\n\t}\n\n\tif (options?.maxTokens) {\n\t\tif (compat.maxTokensField === \"max_tokens\") {\n\t\t\t(params as any).max_tokens = options.maxTokens;\n\t\t} else {\n\t\t\tparams.max_completion_tokens = options.maxTokens;\n\t\t}\n\t}\n\n\tif (options?.temperature !== undefined) {\n\t\tparams.temperature = options.temperature;\n\t}\n\n\tif (!isOpenRouterImageGenerationModel(model) && context.tools && context.tools.length > 0) {\n\t\tparams.tools = convertTools(context.tools, compat);\n\t\tif (compat.zaiToolStream) {\n\t\t\t(params as any).tool_stream = true;\n\t\t}\n\t} else if (!isOpenRouterImageGenerationModel(model) && hasToolHistory(context.messages)) {\n\t\t// Anthropic (via LiteLLM/proxy) requires tools param when conversation has tool_calls/tool_results\n\t\tparams.tools = [];\n\t}\n\n\tif (cacheControl) {\n\t\tapplyAnthropicCacheControl(messages, params.tools, cacheControl);\n\t}\n\n\tif (options?.toolChoice && params.tools?.length) {\n\t\tparams.tool_choice = options.toolChoice;\n\t}\n\n\tif (compat.thinkingFormat === \"zai\" && model.reasoning) {\n\t\tconst zaiParams = params as Omit<typeof params, \"reasoning_effort\"> & {\n\t\t\tthinking?: { type: \"enabled\" | \"disabled\"; clear_thinking?: boolean };\n\t\t\treasoning_effort?: string;\n\t\t};\n\t\tzaiParams.thinking = options?.reasoningEffort ? { type: \"enabled\", clear_thinking: false } : { type: \"disabled\" };\n\t\tif (options?.reasoningEffort && compat.supportsReasoningEffort) {\n\t\t\tconst mappedEffort = model.thinkingLevelMap?.[options.reasoningEffort];\n\t\t\tconst effort = mappedEffort === undefined ? options.reasoningEffort : mappedEffort;\n\t\t\tif (typeof effort === \"string\") {\n\t\t\t\tzaiParams.reasoning_effort = effort;\n\t\t\t}\n\t\t}\n\t} else if (compat.thinkingFormat === \"minimax\" || isMiniMaxModel(model)) {\n\t\tconst minimaxParams = params as typeof params & {\n\t\t\tthinking?: { type: \"adaptive\" | \"disabled\" };\n\t\t\treasoning_split?: boolean;\n\t\t};\n\t\tminimaxParams.thinking = { type: options?.reasoningEffort ? \"adaptive\" : \"disabled\" };\n\t\tminimaxParams.reasoning_split = true;\n\t} else if (compat.thinkingFormat === \"qwen\" && model.reasoning) {\n\t\t(params as any).enable_thinking = !!options?.reasoningEffort;\n\t} else if (compat.thinkingFormat === \"qwen-chat-template\" && model.reasoning) {\n\t\t(params as any).chat_template_kwargs = {\n\t\t\tenable_thinking: !!options?.reasoningEffort,\n\t\t\tpreserve_thinking: true,\n\t\t};\n\t} else if (compat.thinkingFormat === \"deepseek\" && model.reasoning) {\n\t\tif (options?.reasoningEffort) {\n\t\t\t(params as any).thinking = { type: \"enabled\" };\n\t\t} else if (model.thinkingLevelMap?.off !== null) {\n\t\t\t(params as any).thinking = { type: \"disabled\" };\n\t\t}\n\t\tif (options?.reasoningEffort && compat.supportsReasoningEffort) {\n\t\t\t(params as any).reasoning_effort =\n\t\t\t\tmodel.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n\t\t}\n\t} else if (compat.thinkingFormat === \"ant-ling\" && model.reasoning && options?.reasoningEffort) {\n\t\tconst effort = model.thinkingLevelMap?.[options.reasoningEffort];\n\t\tif (typeof effort === \"string\") {\n\t\t\t(params as typeof params & { reasoning?: { effort: string } }).reasoning = { effort };\n\t\t}\n\t} else if (compat.thinkingFormat === \"openrouter\" && model.reasoning) {\n\t\t// OpenRouter normalizes reasoning across providers via a nested reasoning object.\n\t\tconst openRouterParams = params as typeof params & { reasoning?: { effort?: string } };\n\t\tif (options?.reasoningEffort) {\n\t\t\topenRouterParams.reasoning = {\n\t\t\t\teffort: model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort,\n\t\t\t};\n\t\t} else if (model.thinkingLevelMap?.off !== null) {\n\t\t\topenRouterParams.reasoning = { effort: model.thinkingLevelMap?.off ?? \"none\" };\n\t\t}\n\t} else if (options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {\n\t\t// OpenAI-style reasoning_effort\n\t\t(params as any).reasoning_effort = model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n\t} else if (!options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {\n\t\tconst offValue = model.thinkingLevelMap?.off;\n\t\tif (typeof offValue === \"string\") {\n\t\t\t(params as any).reasoning_effort = offValue;\n\t\t}\n\t}\n\n\t// OpenRouter provider routing preferences\n\tif (model.baseUrl.includes(\"openrouter.ai\") && model.compat?.openRouterRouting) {\n\t\t(params as any).provider = model.compat.openRouterRouting;\n\t}\n\n\t// Vercel AI Gateway provider routing preferences\n\tif (model.baseUrl.includes(\"ai-gateway.vercel.sh\") && model.compat?.vercelGatewayRouting) {\n\t\tconst routing = model.compat.vercelGatewayRouting;\n\t\tif (routing.only || routing.order) {\n\t\t\tconst gatewayOptions: Record<string, string[]> = {};\n\t\t\tif (routing.only) gatewayOptions.only = routing.only;\n\t\t\tif (routing.order) gatewayOptions.order = routing.order;\n\t\t\t(params as any).providerOptions = { gateway: gatewayOptions };\n\t\t}\n\t}\n\n\treturn params;\n}\n\nfunction getCompatCacheControl(\n\tcompat: ResolvedOpenAICompletionsCompat,\n\tcacheRetention: CacheRetention,\n): OpenAICompatCacheControl | undefined {\n\tif (compat.cacheControlFormat !== \"anthropic\" || cacheRetention === \"none\") {\n\t\treturn undefined;\n\t}\n\n\tconst ttl = cacheRetention === \"long\" && compat.supportsLongCacheRetention ? \"1h\" : undefined;\n\treturn { type: \"ephemeral\", ...(ttl ? { ttl } : {}) };\n}\n\nfunction applyAnthropicCacheControl(\n\tmessages: ChatCompletionMessageParam[],\n\ttools: OpenAI.Chat.Completions.ChatCompletionTool[] | undefined,\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\taddCacheControlToSystemPrompt(messages, cacheControl);\n\taddCacheControlToLastTool(tools, cacheControl);\n\taddCacheControlToLastConversationMessage(messages, cacheControl);\n}\n\nfunction addCacheControlToSystemPrompt(\n\tmessages: ChatCompletionMessageParam[],\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\tfor (const message of messages) {\n\t\tif (message.role === \"system\" || message.role === \"developer\") {\n\t\t\taddCacheControlToInstructionMessage(message, cacheControl);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nfunction addCacheControlToLastConversationMessage(\n\tmessages: ChatCompletionMessageParam[],\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst message = messages[i];\n\t\tif (message.role === \"user\" || message.role === \"assistant\" || message.role === \"tool\") {\n\t\t\tif (addCacheControlToMessage(message, cacheControl)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction addCacheControlToLastTool(\n\ttools: OpenAI.Chat.Completions.ChatCompletionTool[] | undefined,\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\tif (!tools || tools.length === 0) {\n\t\treturn;\n\t}\n\n\tconst lastTool = tools[tools.length - 1] as ChatCompletionToolWithCacheControl;\n\tlastTool.cache_control = cacheControl;\n}\n\nfunction addCacheControlToInstructionMessage(\n\tmessage: ChatCompletionInstructionMessageParam,\n\tcacheControl: OpenAICompatCacheControl,\n): boolean {\n\treturn addCacheControlToTextContent(message, cacheControl);\n}\n\nfunction addCacheControlToMessage(\n\tmessage: ChatCompletionMessageParam,\n\tcacheControl: OpenAICompatCacheControl,\n): boolean {\n\tif (message.role === \"user\" || message.role === \"assistant\" || message.role === \"tool\") {\n\t\treturn addCacheControlToTextContent(message, cacheControl);\n\t}\n\treturn false;\n}\n\nfunction addCacheControlToTextContent(\n\tmessage:\n\t\t| ChatCompletionInstructionMessageParam\n\t\t| ChatCompletionAssistantMessageParam\n\t\t| ChatCompletionToolMessageParam\n\t\t| Extract<ChatCompletionMessageParam, { role: \"user\" }>,\n\tcacheControl: OpenAICompatCacheControl,\n): boolean {\n\tconst content = message.content;\n\tif (typeof content === \"string\") {\n\t\tif (content.length === 0) {\n\t\t\treturn false;\n\t\t}\n\t\tmessage.content = [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: content,\n\t\t\t\tcache_control: cacheControl,\n\t\t\t},\n\t\t] as ChatCompletionTextPartWithCacheControl[];\n\t\treturn true;\n\t}\n\n\tif (!Array.isArray(content)) {\n\t\treturn false;\n\t}\n\n\tfor (let i = content.length - 1; i >= 0; i--) {\n\t\tconst part = content[i];\n\t\tif (part?.type === \"text\") {\n\t\t\tconst textPart = part as ChatCompletionTextPartWithCacheControl;\n\t\t\ttextPart.cache_control = cacheControl;\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nexport function convertMessages(\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\tcompat: ResolvedOpenAICompletionsCompat,\n): ChatCompletionMessageParam[] {\n\tconst params: ChatCompletionMessageParam[] = [];\n\n\tconst normalizeToolCallId = createProviderToolCallIdNormalizer(model);\n\n\tconst transformedMessages = transformMessages(context.messages, model, (id) => normalizeToolCallId(id));\n\n\tif (context.systemPrompt) {\n\t\tconst useDeveloperRole = model.reasoning && compat.supportsDeveloperRole;\n\t\tconst role = useDeveloperRole ? \"developer\" : \"system\";\n\t\tparams.push({ role: role, content: sanitizeSurrogates(context.systemPrompt) });\n\t}\n\n\tlet lastRole: string | null = null;\n\n\tfor (let i = 0; i < transformedMessages.length; i++) {\n\t\tconst msg = transformedMessages[i];\n\t\t// Some providers don't allow user messages directly after tool results\n\t\t// Insert a synthetic assistant message to bridge the gap\n\t\tif (compat.requiresAssistantAfterToolResult && lastRole === \"toolResult\" && msg.role === \"user\") {\n\t\t\tparams.push({\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: \"I have processed the tool results.\",\n\t\t\t});\n\t\t}\n\n\t\tif (msg.role === \"user\") {\n\t\t\tif (typeof msg.content === \"string\") {\n\t\t\t\tparams.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: sanitizeSurrogates(msg.content),\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst content: ChatCompletionContentPart[] = msg.content\n\t\t\t\t\t.filter((item) => item.type !== \"text\" || item.text.length > 0)\n\t\t\t\t\t.map((item): ChatCompletionContentPart => {\n\t\t\t\t\t\tif (item.type === \"text\") {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\ttext: sanitizeSurrogates(item.text),\n\t\t\t\t\t\t\t} satisfies ChatCompletionContentPartText;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\ttype: \"image_url\",\n\t\t\t\t\t\t\t\timage_url: {\n\t\t\t\t\t\t\t\t\turl: `data:${item.mimeType};base64,${item.data}`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t} satisfies ChatCompletionContentPartImage;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tif (content.length === 0) continue;\n\t\t\t\tparams.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (msg.role === \"assistant\") {\n\t\t\t// Some providers don't accept null content, use empty string instead\n\t\t\tconst assistantMsg: ChatCompletionAssistantMessageParam = {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: compat.requiresAssistantAfterToolResult ? \"\" : null,\n\t\t\t};\n\n\t\t\tconst assistantTextParts = msg.content\n\t\t\t\t.filter(isTextContentBlock)\n\t\t\t\t.filter((block) => block.text.trim().length > 0)\n\t\t\t\t.map(\n\t\t\t\t\t(block) =>\n\t\t\t\t\t\t({\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: sanitizeSurrogates(block.text),\n\t\t\t\t\t\t}) satisfies ChatCompletionContentPartText,\n\t\t\t\t);\n\t\t\tconst assistantText = assistantTextParts.map((part) => part.text).join(\"\");\n\n\t\t\tconst nonEmptyThinkingBlocks = msg.content\n\t\t\t\t.filter(isThinkingContentBlock)\n\t\t\t\t.filter((block) => block.thinking.trim().length > 0);\n\t\t\tif (nonEmptyThinkingBlocks.length > 0) {\n\t\t\t\tif (compat.requiresThinkingAsText) {\n\t\t\t\t\t// Convert thinking blocks to plain text (no tags to avoid model mimicking them)\n\t\t\t\t\tconst thinkingText = nonEmptyThinkingBlocks\n\t\t\t\t\t\t.map((block) => sanitizeSurrogates(block.thinking))\n\t\t\t\t\t\t.join(\"\\n\\n\");\n\t\t\t\t\tassistantMsg.content = [{ type: \"text\", text: thinkingText }, ...assistantTextParts];\n\t\t\t\t} else {\n\t\t\t\t\t// Always send assistant content as a plain string (OpenAI Chat Completions\n\t\t\t\t\t// API standard format). Sending as an array of {type:\"text\", text:\"...\"}\n\t\t\t\t\t// objects is non-standard and causes some models (e.g. DeepSeek V3.2 via\n\t\t\t\t\t// NVIDIA NIM) to mirror the content-block structure literally in their\n\t\t\t\t\t// output, producing recursive nesting like [{'type':'text','text':'[{...}]'}].\n\t\t\t\t\tif (assistantText.length > 0) {\n\t\t\t\t\t\tassistantMsg.content = assistantText;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Use the signature from the first thinking block if available (for llama.cpp server + gpt-oss)\n\t\t\t\t\tlet signature = nonEmptyThinkingBlocks[0].thinkingSignature;\n\t\t\t\t\tif (model.provider === \"opencode-go\" && signature === \"reasoning\") {\n\t\t\t\t\t\tsignature = \"reasoning_content\";\n\t\t\t\t\t}\n\t\t\t\t\tif (signature && signature.length > 0) {\n\t\t\t\t\t\t(assistantMsg as any)[signature] = nonEmptyThinkingBlocks.map((block) => block.thinking).join(\"\\n\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (assistantText.length > 0) {\n\t\t\t\t// Always send assistant content as a plain string (OpenAI Chat Completions\n\t\t\t\t// API standard format). Sending as an array of {type:\"text\", text:\"...\"}\n\t\t\t\t// objects is non-standard and causes some models (e.g. DeepSeek V3.2 via\n\t\t\t\t// NVIDIA NIM) to mirror the content-block structure literally in their\n\t\t\t\t// output, producing recursive nesting like [{'type':'text','text':'[{...}]'}].\n\t\t\t\tassistantMsg.content = assistantText;\n\t\t\t}\n\n\t\t\tconst toolCalls = msg.content.filter(isToolCallBlock);\n\t\t\tif (toolCalls.length > 0) {\n\t\t\t\tassistantMsg.tool_calls = toolCalls.map((tc) => ({\n\t\t\t\t\tid: tc.id,\n\t\t\t\t\ttype: \"function\" as const,\n\t\t\t\t\tfunction: {\n\t\t\t\t\t\tname: tc.name,\n\t\t\t\t\t\targuments: JSON.stringify(tc.arguments),\n\t\t\t\t\t},\n\t\t\t\t}));\n\t\t\t\tconst reasoningDetails = toolCalls\n\t\t\t\t\t.filter((tc) => tc.thoughtSignature)\n\t\t\t\t\t.map((tc) => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\treturn JSON.parse(tc.thoughtSignature!);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.filter(Boolean);\n\t\t\t\tif (reasoningDetails.length > 0) {\n\t\t\t\t\t(assistantMsg as any).reasoning_details = reasoningDetails;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (\n\t\t\t\tcompat.requiresReasoningContentOnAssistantMessages &&\n\t\t\t\tmodel.reasoning &&\n\t\t\t\t(assistantMsg as { reasoning_content?: string }).reasoning_content === undefined\n\t\t\t) {\n\t\t\t\t(assistantMsg as { reasoning_content?: string }).reasoning_content = \"\";\n\t\t\t}\n\t\t\t// Skip assistant messages that have no content and no tool calls.\n\t\t\t// Some providers require \"either content or tool_calls, but not none\".\n\t\t\t// Other providers also don't accept empty assistant messages.\n\t\t\t// This handles aborted assistant responses that got no content.\n\t\t\tconst content = assistantMsg.content;\n\t\t\tconst hasContent =\n\t\t\t\tcontent !== null &&\n\t\t\t\tcontent !== undefined &&\n\t\t\t\t(typeof content === \"string\" ? content.length > 0 : content.length > 0);\n\t\t\tif (!hasContent && !assistantMsg.tool_calls) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tparams.push(assistantMsg);\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\tconst imageBlocks: Array<{ type: \"image_url\"; image_url: { url: string } }> = [];\n\t\t\tlet j = i;\n\n\t\t\tfor (; j < transformedMessages.length && transformedMessages[j].role === \"toolResult\"; j++) {\n\t\t\t\tconst toolMsg = transformedMessages[j] as ToolResultMessage;\n\n\t\t\t\t// Extract text and image content\n\t\t\t\tconst textResult = toolMsg.content\n\t\t\t\t\t.filter(isTextContentBlock)\n\t\t\t\t\t.map((block) => block.text)\n\t\t\t\t\t.join(\"\\n\");\n\t\t\t\tconst hasImages = toolMsg.content.some((c) => c.type === \"image\");\n\n\t\t\t\t// Always send tool result with text (or placeholder if only images)\n\t\t\t\tconst hasText = textResult.length > 0;\n\t\t\t\tconst toolResultText = hasText ? textResult : hasImages ? \"(see attached image)\" : \"(no tool output)\";\n\t\t\t\t// Some providers require the 'name' field in tool results\n\t\t\t\tconst toolResultMsg: ChatCompletionToolMessageParam = {\n\t\t\t\t\trole: \"tool\",\n\t\t\t\t\tcontent: sanitizeSurrogates(toolResultText),\n\t\t\t\t\ttool_call_id: toolMsg.toolCallId,\n\t\t\t\t};\n\t\t\t\tif (compat.requiresToolResultName && toolMsg.toolName) {\n\t\t\t\t\t(toolResultMsg as any).name = toolMsg.toolName;\n\t\t\t\t}\n\t\t\t\tparams.push(toolResultMsg);\n\n\t\t\t\tif (hasImages && model.input.includes(\"image\")) {\n\t\t\t\t\tfor (const block of toolMsg.content) {\n\t\t\t\t\t\tif (isImageContentBlock(block)) {\n\t\t\t\t\t\t\timageBlocks.push({\n\t\t\t\t\t\t\t\ttype: \"image_url\",\n\t\t\t\t\t\t\t\timage_url: {\n\t\t\t\t\t\t\t\t\turl: `data:${block.mimeType};base64,${block.data}`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ti = j - 1;\n\n\t\t\tif (imageBlocks.length > 0) {\n\t\t\t\tif (compat.requiresAssistantAfterToolResult) {\n\t\t\t\t\tparams.push({\n\t\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\t\tcontent: \"I have processed the tool results.\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tparams.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: \"Attached image(s) from tool result:\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...imageBlocks,\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\tlastRole = \"user\";\n\t\t\t} else {\n\t\t\t\tlastRole = \"toolResult\";\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tlastRole = msg.role;\n\t}\n\n\treturn params;\n}\n\nfunction convertTools(\n\ttools: Tool[],\n\tcompat: ResolvedOpenAICompletionsCompat,\n): OpenAI.Chat.Completions.ChatCompletionTool[] {\n\treturn tools.map((tool) => ({\n\t\ttype: \"function\",\n\t\tfunction: {\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: tool.parameters as any, // TypeBox already generates JSON Schema\n\t\t\t// Only include strict if provider supports it. Some reject unknown fields.\n\t\t\t...(compat.supportsStrictMode !== false && { strict: false }),\n\t\t},\n\t}));\n}\n\nfunction parseChunkUsage(\n\trawUsage: {\n\t\tprompt_tokens?: number;\n\t\tcompletion_tokens?: number;\n\t\tcached_tokens?: number;\n\t\tprompt_cache_hit_tokens?: number;\n\t\tprompt_tokens_details?: { cached_tokens?: number; cache_write_tokens?: number };\n\t},\n\tmodel: Model<\"openai-completions\">,\n): AssistantMessage[\"usage\"] {\n\tconst promptTokens = rawUsage.prompt_tokens || 0;\n\tconst cacheReadTokens =\n\t\trawUsage.prompt_tokens_details?.cached_tokens ?? rawUsage.prompt_cache_hit_tokens ?? rawUsage.cached_tokens ?? 0;\n\tconst cacheWriteTokens = rawUsage.prompt_tokens_details?.cache_write_tokens || 0;\n\n\t// Follow documented OpenAI/OpenRouter semantics: cached_tokens is cache-read\n\t// tokens (hits). Providers disagree on placement: OpenAI/OpenRouter use\n\t// prompt_tokens_details.cached_tokens, DeepSeek uses prompt_cache_hit_tokens,\n\t// and Kimi documents top-level usage.cached_tokens on the final usage chunk.\n\t// OpenAI does not document or emit cache_write_tokens, but\n\t// OpenRouter-compatible providers can include it as a separate write count.\n\t// OpenRouter's own provider/tests affirm the separate mapping:\n\t// https://github.com/OpenRouterTeam/ai-sdk-provider/pull/409\n\t// Do not subtract writes from cached_tokens, otherwise spec-compliant\n\t// providers are under-reported. DS4 mirrors this contract too:\n\t// https://github.com/antirez/ds4/pull/29\n\tconst input = Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens);\n\t// OpenAI completion_tokens already includes reasoning_tokens.\n\tconst outputTokens = rawUsage.completion_tokens || 0;\n\tconst usage: AssistantMessage[\"usage\"] = {\n\t\tinput,\n\t\toutput: outputTokens,\n\t\tcacheRead: cacheReadTokens,\n\t\tcacheWrite: cacheWriteTokens,\n\t\ttotalTokens: input + outputTokens + cacheReadTokens + cacheWriteTokens,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n\tcalculateCost(model, usage);\n\treturn usage;\n}\n\nfunction mapStopReason(reason: ChatCompletionChunk.Choice[\"finish_reason\"] | string): {\n\tstopReason: StopReason;\n\terrorMessage?: string;\n} {\n\tif (reason === null) return { stopReason: \"stop\" };\n\tswitch (reason) {\n\t\tcase \"stop\":\n\t\tcase \"end\":\n\t\t\treturn { stopReason: \"stop\" };\n\t\tcase \"length\":\n\t\t\treturn { stopReason: \"length\" };\n\t\tcase \"function_call\":\n\t\tcase \"tool_calls\":\n\t\t\treturn { stopReason: \"toolUse\" };\n\t\tcase \"content_filter\":\n\t\t\treturn { stopReason: \"error\", errorMessage: \"Provider finish_reason: content_filter\" };\n\t\tcase \"network_error\":\n\t\t\treturn { stopReason: \"error\", errorMessage: \"Provider finish_reason: network_error\" };\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tstopReason: \"error\",\n\t\t\t\terrorMessage: `Provider finish_reason: ${reason}`,\n\t\t\t};\n\t}\n}\n\n/**\n * Detect compatibility settings from provider and baseUrl for known providers.\n * Provider takes precedence over URL-based detection since it's explicitly configured.\n * Returns a fully resolved OpenAICompletionsCompat object with all fields set.\n */\nfunction detectCompat(model: Model<\"openai-completions\">): ResolvedOpenAICompletionsCompat {\n\tconst provider = model.provider;\n\tconst baseUrl = model.baseUrl;\n\n\tconst isZai = provider === \"zai\" || baseUrl.includes(\"api.z.ai\");\n\tconst isMoonshot = provider === \"moonshotai\" || provider === \"moonshotai-cn\" || baseUrl.includes(\"api.moonshot.\");\n\tconst isCloudflareWorkersAI = provider === \"cloudflare-workers-ai\" || baseUrl.includes(\"api.cloudflare.com\");\n\tconst isCloudflareAiGateway = provider === \"cloudflare-ai-gateway\" || baseUrl.includes(\"gateway.ai.cloudflare.com\");\n\tconst isAntLing = provider === \"ant-ling\" || baseUrl.includes(\"api.ant-ling.com\");\n\tconst isMiniMax = isMiniMaxModel(model);\n\tconst isDeepSeek = provider === \"deepseek\" || baseUrl.toLowerCase().includes(\"deepseek.com\");\n\n\tconst isNonStandard =\n\t\tprovider === \"cerebras\" ||\n\t\tbaseUrl.includes(\"cerebras.ai\") ||\n\t\tprovider === \"xai\" ||\n\t\tbaseUrl.includes(\"api.x.ai\") ||\n\t\tbaseUrl.includes(\"chutes.ai\") ||\n\t\tisDeepSeek ||\n\t\tisZai ||\n\t\tisMoonshot ||\n\t\tprovider === \"opencode\" ||\n\t\tbaseUrl.includes(\"opencode.ai\") ||\n\t\tisCloudflareWorkersAI ||\n\t\tisCloudflareAiGateway ||\n\t\tisAntLing;\n\n\t// Z.AI ignores max_completion_tokens, so its output cap only applies through max_tokens.\n\tconst isZaiMaxTokensEndpoint = isZai || provider === \"zai-coding-cn\" || baseUrl.includes(\"open.bigmodel.cn\");\n\tconst useMaxTokens =\n\t\tbaseUrl.includes(\"chutes.ai\") ||\n\t\tisDeepSeek ||\n\t\tisMoonshot ||\n\t\tisCloudflareAiGateway ||\n\t\tisAntLing ||\n\t\tisZaiMaxTokensEndpoint;\n\n\tconst isGrok = provider === \"xai\" || baseUrl.includes(\"api.x.ai\");\n\tconst cacheControlFormat = provider === \"openrouter\" && /^~?anthropic\\//.test(model.id) ? \"anthropic\" : undefined;\n\tconst isOpenRouter = provider === \"openrouter\" || baseUrl.includes(\"openrouter.ai\");\n\n\treturn {\n\t\tsupportsStore: !isNonStandard,\n\t\tsupportsDeveloperRole: !isNonStandard,\n\t\tsupportsReasoningEffort: !isGrok && !isZai && !isMoonshot && !isCloudflareAiGateway && !isAntLing,\n\t\tsupportsUsageInStreaming: true,\n\t\tsupportsFinishReason: true,\n\t\tmaxTokensField: useMaxTokens ? \"max_tokens\" : \"max_completion_tokens\",\n\t\trequiresToolResultName: false,\n\t\trequiresAssistantAfterToolResult: false,\n\t\trequiresThinkingAsText: false,\n\t\trequiresReasoningContentOnAssistantMessages: isDeepSeek,\n\t\tthinkingFormat: isMiniMax\n\t\t\t? \"minimax\"\n\t\t\t: isDeepSeek\n\t\t\t\t? \"deepseek\"\n\t\t\t\t: isZai\n\t\t\t\t\t? \"zai\"\n\t\t\t\t\t: isAntLing\n\t\t\t\t\t\t? \"ant-ling\"\n\t\t\t\t\t\t: provider === \"openrouter\" || baseUrl.includes(\"openrouter.ai\")\n\t\t\t\t\t\t\t? \"openrouter\"\n\t\t\t\t\t\t\t: \"openai\",\n\t\topenRouterRouting: {},\n\t\topenRouterImageGeneration: false,\n\t\tvercelGatewayRouting: {},\n\t\tzaiToolStream: false,\n\t\tsupportsStrictMode: !isMoonshot && !isCloudflareAiGateway,\n\t\tcacheControlFormat,\n\t\tsendSessionAffinityHeaders: isOpenRouter,\n\t\tsessionAffinityFormat: isOpenRouter ? \"openrouter\" : \"openai\",\n\t\tsupportsLongCacheRetention: !(isCloudflareWorkersAI || isCloudflareAiGateway || isAntLing),\n\t};\n}\n\n/**\n * Get resolved compatibility settings for a model.\n * Uses explicit model.compat if provided, otherwise auto-detects from provider/URL.\n */\nfunction getCompat(model: Model<\"openai-completions\">): ResolvedOpenAICompletionsCompat {\n\tconst detected = detectCompat(model);\n\tif (!model.compat) return detected;\n\n\treturn {\n\t\tsupportsStore: model.compat.supportsStore ?? detected.supportsStore,\n\t\tsupportsDeveloperRole: model.compat.supportsDeveloperRole ?? detected.supportsDeveloperRole,\n\t\tsupportsReasoningEffort: model.compat.supportsReasoningEffort ?? detected.supportsReasoningEffort,\n\t\tsupportsUsageInStreaming: model.compat.supportsUsageInStreaming ?? detected.supportsUsageInStreaming,\n\t\tsupportsFinishReason: model.compat.supportsFinishReason ?? detected.supportsFinishReason,\n\t\tmaxTokensField: model.compat.maxTokensField ?? detected.maxTokensField,\n\t\trequiresToolResultName: model.compat.requiresToolResultName ?? detected.requiresToolResultName,\n\t\trequiresAssistantAfterToolResult:\n\t\t\tmodel.compat.requiresAssistantAfterToolResult ?? detected.requiresAssistantAfterToolResult,\n\t\trequiresThinkingAsText: model.compat.requiresThinkingAsText ?? detected.requiresThinkingAsText,\n\t\trequiresReasoningContentOnAssistantMessages:\n\t\t\tmodel.compat.requiresReasoningContentOnAssistantMessages ??\n\t\t\tdetected.requiresReasoningContentOnAssistantMessages,\n\t\tthinkingFormat: isMiniMaxModel(model) ? \"minimax\" : (model.compat.thinkingFormat ?? detected.thinkingFormat),\n\t\topenRouterRouting: model.compat.openRouterRouting ?? {},\n\t\topenRouterImageGeneration: model.compat.openRouterImageGeneration ?? detected.openRouterImageGeneration,\n\t\tvercelGatewayRouting: model.compat.vercelGatewayRouting ?? detected.vercelGatewayRouting,\n\t\tzaiToolStream: model.compat.zaiToolStream ?? detected.zaiToolStream,\n\t\tsupportsStrictMode: model.compat.supportsStrictMode ?? detected.supportsStrictMode,\n\t\tcacheControlFormat: model.compat.cacheControlFormat ?? detected.cacheControlFormat,\n\t\tsendSessionAffinityHeaders: model.compat.sendSessionAffinityHeaders ?? detected.sendSessionAffinityHeaders,\n\t\tsessionAffinityFormat: model.compat.sessionAffinityFormat ?? detected.sessionAffinityFormat,\n\t\tsupportsLongCacheRetention: model.compat.supportsLongCacheRetention ?? detected.supportsLongCacheRetention,\n\t};\n}\n"]}
1
+ {"version":3,"file":"openai-completions.js","sourceRoot":"","sources":["../../src/providers/openai-completions.ts"],"names":[],"mappings":"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","sourcesContent":["import OpenAI from \"openai\";\nimport type {\n\tChatCompletion,\n\tChatCompletionAssistantMessageParam,\n\tChatCompletionChunk,\n\tChatCompletionContentPart,\n\tChatCompletionContentPartImage,\n\tChatCompletionContentPartText,\n\tChatCompletionDeveloperMessageParam,\n\tChatCompletionMessageParam,\n\tChatCompletionSystemMessageParam,\n\tChatCompletionToolMessageParam,\n} from \"openai/resources/chat/completions.js\";\nimport { getEnvApiKey } from \"../env-api-keys.js\";\nimport { calculateCost, clampThinkingLevel } from \"../models.js\";\nimport type {\n\tAssistantMessage,\n\tCacheRetention,\n\tContext,\n\tImageContent,\n\tMessage,\n\tModel,\n\tOpenAICompletionsCompat,\n\tProviderEnv,\n\tSimpleStreamOptions,\n\tStopReason,\n\tStreamFunction,\n\tStreamOptions,\n\tTextContent,\n\tThinkingContent,\n\tTool,\n\tToolCall,\n\tToolResultMessage,\n} from \"../types.js\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.js\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.js\";\nimport { headersToRecord } from \"../utils/headers.js\";\nimport { finalizeToolCallArguments, parseStreamingJson } from \"../utils/json-parse.js\";\nimport { getProviderEnvValue } from \"../utils/provider-env.js\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.js\";\nimport { createProviderToolCallIdNormalizer } from \"../utils/tool-call-id.js\";\nimport { isCloudflareProvider, resolveCloudflareBaseUrl } from \"./cloudflare.js\";\nimport { buildCopilotDynamicHeaders, hasCopilotVisionInput } from \"./github-copilot-headers.js\";\nimport { clampOpenAIPromptCacheKey } from \"./openai-prompt-cache.js\";\nimport { buildBaseOptions } from \"./simple-options.js\";\nimport { transformMessages } from \"./transform-messages.js\";\n\n/**\n * Check if conversation messages contain tool calls or tool results.\n * This is needed because Anthropic (via proxy) requires the tools param\n * to be present when messages include tool_calls or tool role messages.\n */\nfunction hasToolHistory(messages: Message[]): boolean {\n\tfor (const msg of messages) {\n\t\tif (msg.role === \"toolResult\") {\n\t\t\treturn true;\n\t\t}\n\t\tif (msg.role === \"assistant\") {\n\t\t\tif (msg.content.some((block) => block.type === \"toolCall\")) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction isTextContentBlock(block: { type: string }): block is TextContent {\n\treturn block.type === \"text\";\n}\n\nfunction isThinkingContentBlock(block: { type: string }): block is ThinkingContent {\n\treturn block.type === \"thinking\";\n}\n\nfunction isToolCallBlock(block: { type: string }): block is ToolCall {\n\treturn block.type === \"toolCall\";\n}\n\nfunction isImageContentBlock(block: { type: string }): block is ImageContent {\n\treturn block.type === \"image\";\n}\n\nfunction isMiniMaxModel(model: Model<\"openai-completions\">): boolean {\n\t// Merc-native: shared gateways carry multiple families; infer MiniMax only from the id.\n\treturn model.id.toLowerCase().includes(\"minimax-m3\");\n}\n\nfunction createThinkingTagFilter(enabled: boolean): { push: (chunk: string) => string; flush: () => string } {\n\tlet buffer = \"\";\n\tlet inThinking = false;\n\tconst openingTag = \"<think\";\n\tconst closingTag = \"</think>\";\n\n\tconst consume = (): string => {\n\t\tlet visible = \"\";\n\t\twhile (buffer.length > 0) {\n\t\t\tconst lower = buffer.toLowerCase();\n\t\t\tif (inThinking) {\n\t\t\t\tconst end = lower.indexOf(closingTag);\n\t\t\t\tif (end < 0) {\n\t\t\t\t\tbuffer = \"\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbuffer = buffer.slice(end + closingTag.length);\n\t\t\t\tinThinking = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst start = lower.indexOf(openingTag);\n\t\t\tif (start < 0) {\n\t\t\t\tconst strayClosing = lower.indexOf(closingTag);\n\t\t\t\tif (strayClosing >= 0) {\n\t\t\t\t\tvisible += buffer.slice(0, strayClosing);\n\t\t\t\t\tbuffer = buffer.slice(strayClosing + closingTag.length);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst partialStart = Math.max(0, buffer.length - openingTag.length + 1);\n\t\t\t\tconst partial = buffer.slice(partialStart).toLowerCase();\n\t\t\t\tconst closingPartialStart = Math.max(0, buffer.length - closingTag.length + 1);\n\t\t\t\tconst closingPartial = buffer.slice(closingPartialStart).toLowerCase();\n\t\t\t\tconst partialLength = Math.max(\n\t\t\t\t\tpartial && openingTag.startsWith(partial) ? partial.length : 0,\n\t\t\t\t\tclosingPartial && closingTag.startsWith(closingPartial) ? closingPartial.length : 0,\n\t\t\t\t);\n\t\t\t\tvisible += buffer.slice(0, buffer.length - partialLength);\n\t\t\t\tbuffer = buffer.slice(buffer.length - partialLength);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tvisible += buffer.slice(0, start);\n\t\t\tbuffer = buffer.slice(start);\n\t\t\tconst tagEnd = buffer.indexOf(\">\");\n\t\t\tif (tagEnd < 0) break;\n\t\t\tbuffer = buffer.slice(tagEnd + 1);\n\t\t\tinThinking = true;\n\t\t}\n\t\treturn visible;\n\t};\n\n\treturn {\n\t\tpush: (chunk) => {\n\t\t\tif (!enabled) return chunk;\n\t\t\tbuffer += chunk;\n\t\t\treturn consume();\n\t\t},\n\t\tflush: () => (enabled ? consume() : buffer),\n\t};\n}\n\nfunction isEncryptedReasoningDetail(detail: unknown): detail is OpenAIEncryptedReasoningDetail {\n\tif (typeof detail !== \"object\" || detail === null) {\n\t\treturn false;\n\t}\n\tconst candidate = detail as Record<string, unknown>;\n\treturn (\n\t\tcandidate.type === \"reasoning.encrypted\" &&\n\t\ttypeof candidate.id === \"string\" &&\n\t\tcandidate.id.length > 0 &&\n\t\ttypeof candidate.data === \"string\" &&\n\t\tcandidate.data.length > 0\n\t);\n}\n\nexport interface OpenAICompletionsOptions extends StreamOptions {\n\ttoolChoice?: \"auto\" | \"none\" | \"required\" | { type: \"function\"; function: { name: string } };\n\treasoningEffort?: \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n}\n\ninterface OpenAICompatCacheControl {\n\ttype: \"ephemeral\";\n\tttl?: string;\n}\n\ntype ResolvedOpenAICompletionsCompat = Omit<Required<OpenAICompletionsCompat>, \"cacheControlFormat\"> & {\n\tcacheControlFormat?: OpenAICompletionsCompat[\"cacheControlFormat\"];\n};\n\ntype ChatCompletionInstructionMessageParam = ChatCompletionDeveloperMessageParam | ChatCompletionSystemMessageParam;\n\ntype OpenAIEncryptedReasoningDetail = {\n\ttype: \"reasoning.encrypted\";\n\tid: string;\n\tdata: string;\n};\n\ntype ChatCompletionTextPartWithCacheControl = ChatCompletionContentPartText & {\n\tcache_control?: OpenAICompatCacheControl;\n};\n\ntype ChatCompletionToolWithCacheControl = OpenAI.Chat.Completions.ChatCompletionTool & {\n\tcache_control?: OpenAICompatCacheControl;\n};\n\ninterface OpenRouterGeneratedImage {\n\timage_url?: string | { url?: string };\n}\n\ntype OpenRouterImageGenerationMessage = ChatCompletion[\"choices\"][number][\"message\"] & {\n\timages?: OpenRouterGeneratedImage[];\n};\n\ntype OpenRouterImageGenerationChoice = ChatCompletion[\"choices\"][number] & {\n\tmessage: OpenRouterImageGenerationMessage;\n};\n\ntype OpenRouterImageGenerationResponse = ChatCompletion & {\n\tchoices: OpenRouterImageGenerationChoice[];\n};\n\nfunction isOpenRouterImageGenerationModel(model: Model<\"openai-completions\">): boolean {\n\treturn model.provider === \"openrouter\" && model.compat?.openRouterImageGeneration === true;\n}\n\nfunction resolveCacheRetention(cacheRetention?: CacheRetention, env?: ProviderEnv): CacheRetention {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\tif (getProviderEnvValue(\"MERC_CACHE_RETENTION\", env) === \"long\") {\n\t\treturn \"long\";\n\t}\n\treturn \"short\";\n}\n\nexport const streamOpenAICompletions: StreamFunction<\"openai-completions\", OpenAICompletionsOptions> = (\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\toptions?: OpenAICompletionsOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\ttry {\n\t\t\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider, options?.env) || \"\";\n\t\t\tconst compat = getCompat(model);\n\t\t\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\t\t\tconst cacheSessionId = cacheRetention === \"none\" ? undefined : options?.sessionId;\n\t\t\tconst client = createClient(model, context, apiKey, options?.headers, cacheSessionId, compat, options?.env);\n\t\t\tlet params = buildParams(model, context, options, compat, cacheRetention);\n\t\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\t\tif (nextParams !== undefined) {\n\t\t\t\tparams = nextParams as OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming;\n\t\t\t}\n\t\t\tconst requestOptions = {\n\t\t\t\t...(options?.signal ? { signal: options.signal } : {}),\n\t\t\t\t...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n\t\t\t\tmaxRetries: options?.maxRetries ?? 0,\n\t\t\t};\n\t\t\tif (isOpenRouterImageGenerationModel(model)) {\n\t\t\t\tconst { stream_options: _streamOptions, ...nonStreamingBaseParams } = params;\n\t\t\t\tconst nonStreamingParams = {\n\t\t\t\t\t...nonStreamingBaseParams,\n\t\t\t\t\tstream: false,\n\t\t\t\t} as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming;\n\t\t\t\tconst { data: response, response: rawResponse } = await client.chat.completions\n\t\t\t\t\t.create(nonStreamingParams, requestOptions)\n\t\t\t\t\t.withResponse();\n\t\t\t\tawait options?.onResponse?.(\n\t\t\t\t\t{ status: rawResponse.status, headers: headersToRecord(rawResponse.headers) },\n\t\t\t\t\tmodel,\n\t\t\t\t);\n\t\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\t\tconst imageResponse = response as OpenRouterImageGenerationResponse;\n\t\t\t\toutput.responseId ||= imageResponse.id;\n\t\t\t\toutput.usage = parseChunkUsage(imageResponse.usage ?? {}, model);\n\n\t\t\t\tconst choice = imageResponse.choices[0];\n\t\t\t\tif (choice) {\n\t\t\t\t\tconst text = choice.message.content;\n\t\t\t\t\tif (text) {\n\t\t\t\t\t\tconst textBlock: TextContent = { type: \"text\", text };\n\t\t\t\t\t\toutput.content.push(textBlock);\n\t\t\t\t\t\tconst contentIndex = output.content.length - 1;\n\t\t\t\t\t\tstream.push({ type: \"text_start\", contentIndex, partial: output });\n\t\t\t\t\t\tstream.push({ type: \"text_delta\", contentIndex, delta: text, partial: output });\n\t\t\t\t\t\tstream.push({ type: \"text_end\", contentIndex, content: text, partial: output });\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const image of choice.message.images ?? []) {\n\t\t\t\t\t\tconst imageUrl = typeof image.image_url === \"string\" ? image.image_url : image.image_url?.url;\n\t\t\t\t\t\tif (!imageUrl?.startsWith(\"data:\")) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst matches = imageUrl.match(/^data:([^;]+);base64,(.+)$/);\n\t\t\t\t\t\tif (!matches) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst imageBlock: ImageContent = {\n\t\t\t\t\t\t\ttype: \"image\",\n\t\t\t\t\t\t\tmimeType: matches[1],\n\t\t\t\t\t\t\tdata: matches[2],\n\t\t\t\t\t\t};\n\t\t\t\t\t\toutput.content.push(imageBlock);\n\t\t\t\t\t\tconst contentIndex = output.content.length - 1;\n\t\t\t\t\t\tstream.push({ type: \"image_start\", contentIndex, partial: output });\n\t\t\t\t\t\tstream.push({ type: \"image_end\", contentIndex, image: imageBlock, partial: output });\n\t\t\t\t\t}\n\n\t\t\t\t\tif (choice.finish_reason) {\n\t\t\t\t\t\tconst finishReasonResult = mapStopReason(choice.finish_reason);\n\t\t\t\t\t\toutput.stopReason = finishReasonResult.stopReason;\n\t\t\t\t\t\tif (finishReasonResult.errorMessage) {\n\t\t\t\t\t\t\toutput.errorMessage = finishReasonResult.errorMessage;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (output.stopReason === \"stop\" || output.stopReason === \"length\" || output.stopReason === \"toolUse\") {\n\t\t\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\t\t} else {\n\t\t\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\t\t}\n\t\t\t\tstream.end();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { data: openaiStream, response } = await client.chat.completions\n\t\t\t\t.create(params, requestOptions)\n\t\t\t\t.withResponse();\n\t\t\tawait options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\tinterface StreamingToolCallBlock extends ToolCall {\n\t\t\t\tpartialArgs?: string;\n\t\t\t\tstreamIndex?: number;\n\t\t\t}\n\t\t\ttype StreamingBlock = TextContent | ThinkingContent | StreamingToolCallBlock;\n\t\t\ttype StreamingToolCallDelta = NonNullable<ChatCompletionChunk.Choice.Delta[\"tool_calls\"]>[number];\n\n\t\t\tlet textBlock: TextContent | null = null;\n\t\t\tlet thinkingBlock: ThinkingContent | null = null;\n\t\t\tlet hasFinishReason = false;\n\t\t\tlet hasIncompleteToolCallArguments = false;\n\t\t\tconst toolCallBlocksByIndex = new Map<number, StreamingToolCallBlock>();\n\t\t\tconst toolCallBlocksById = new Map<string, StreamingToolCallBlock>();\n\t\t\tconst pendingReasoningDetailsByToolCallId = new Map<string, string>();\n\t\t\tconst blocks = output.content as StreamingBlock[];\n\t\t\tconst thinkingTagFilter = createThinkingTagFilter(compat.thinkingFormat === \"minimax\");\n\t\t\tconst getContentIndex = (block: StreamingBlock) => blocks.indexOf(block);\n\t\t\tconst finishBlock = (block: StreamingBlock) => {\n\t\t\t\tconst contentIndex = getContentIndex(block);\n\t\t\t\tif (contentIndex === -1) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (block.type === \"text\") {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\tcontentIndex,\n\t\t\t\t\t\tcontent: block.text,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t} else if (block.type === \"thinking\") {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\tcontentIndex,\n\t\t\t\t\t\tcontent: block.thinking,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\t// Without finish_reason, only strictly valid raw arguments prove the call was not cut off.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tJSON.parse(block.partialArgs ?? \"\");\n\t\t\t\t\t} catch {\n\t\t\t\t\t\thasIncompleteToolCallArguments = true;\n\t\t\t\t\t}\n\t\t\t\t\tfinalizeToolCallArguments(block, block.partialArgs);\n\t\t\t\t\t// Finalize in-place and strip the scratch buffers so replay only\n\t\t\t\t\t// carries parsed arguments.\n\t\t\t\t\tdelete block.partialArgs;\n\t\t\t\t\tdelete block.streamIndex;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\t\tcontentIndex,\n\t\t\t\t\t\ttoolCall: block,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst ensureTextBlock = () => {\n\t\t\t\tif (!textBlock) {\n\t\t\t\t\ttextBlock = { type: \"text\", text: \"\" };\n\t\t\t\t\tblocks.push(textBlock);\n\t\t\t\t\tstream.push({ type: \"text_start\", contentIndex: getContentIndex(textBlock), partial: output });\n\t\t\t\t}\n\t\t\t\treturn textBlock;\n\t\t\t};\n\t\t\tconst appendTextDelta = (delta: string) => {\n\t\t\t\tif (!delta) return;\n\t\t\t\tconst block = ensureTextBlock();\n\t\t\t\tblock.text += delta;\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\tdelta,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t};\n\t\t\tconst ensureThinkingBlock = (thinkingSignature: string) => {\n\t\t\t\tif (!thinkingBlock) {\n\t\t\t\t\tthinkingBlock = {\n\t\t\t\t\t\ttype: \"thinking\",\n\t\t\t\t\t\tthinking: \"\",\n\t\t\t\t\t\tthinkingSignature,\n\t\t\t\t\t};\n\t\t\t\t\tblocks.push(thinkingBlock);\n\t\t\t\t\tstream.push({ type: \"thinking_start\", contentIndex: getContentIndex(thinkingBlock), partial: output });\n\t\t\t\t}\n\t\t\t\treturn thinkingBlock;\n\t\t\t};\n\t\t\tconst applyPendingReasoningDetail = (block: StreamingToolCallBlock) => {\n\t\t\t\tif (!block.id) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst pendingReasoningDetail = pendingReasoningDetailsByToolCallId.get(block.id);\n\t\t\t\tif (pendingReasoningDetail) {\n\t\t\t\t\tblock.thoughtSignature = pendingReasoningDetail;\n\t\t\t\t\tpendingReasoningDetailsByToolCallId.delete(block.id);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst ensureToolCallBlock = (toolCall: StreamingToolCallDelta) => {\n\t\t\t\tconst streamIndex = typeof toolCall.index === \"number\" ? toolCall.index : undefined;\n\t\t\t\tlet block = streamIndex !== undefined ? toolCallBlocksByIndex.get(streamIndex) : undefined;\n\t\t\t\tif (!block && toolCall.id) {\n\t\t\t\t\tblock = toolCallBlocksById.get(toolCall.id);\n\t\t\t\t}\n\t\t\t\tif (!block) {\n\t\t\t\t\tblock = {\n\t\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\t\tid: toolCall.id || \"\",\n\t\t\t\t\t\tname: toolCall.function?.name || \"\",\n\t\t\t\t\t\targuments: {},\n\t\t\t\t\t\tpartialArgs: \"\",\n\t\t\t\t\t\tstreamIndex,\n\t\t\t\t\t};\n\t\t\t\t\tif (streamIndex !== undefined) {\n\t\t\t\t\t\ttoolCallBlocksByIndex.set(streamIndex, block);\n\t\t\t\t\t}\n\t\t\t\t\tif (toolCall.id) {\n\t\t\t\t\t\ttoolCallBlocksById.set(toolCall.id, block);\n\t\t\t\t\t}\n\t\t\t\t\tblocks.push(block);\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"toolcall_start\",\n\t\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (streamIndex !== undefined && block.streamIndex === undefined) {\n\t\t\t\t\tblock.streamIndex = streamIndex;\n\t\t\t\t\ttoolCallBlocksByIndex.set(streamIndex, block);\n\t\t\t\t}\n\t\t\t\tif (toolCall.id) {\n\t\t\t\t\ttoolCallBlocksById.set(toolCall.id, block);\n\t\t\t\t}\n\t\t\t\tapplyPendingReasoningDetail(block);\n\t\t\t\treturn block;\n\t\t\t};\n\n\t\t\tfor await (const chunk of openaiStream) {\n\t\t\t\tif (!chunk || typeof chunk !== \"object\") continue;\n\n\t\t\t\t// OpenAI documents ChatCompletionChunk.id as the unique chat completion identifier,\n\t\t\t\t// and each chunk in a streamed completion carries the same id.\n\t\t\t\toutput.responseId ||= chunk.id;\n\t\t\t\tif (typeof chunk.model === \"string\" && chunk.model.length > 0 && chunk.model !== model.id) {\n\t\t\t\t\toutput.responseModel ||= chunk.model;\n\t\t\t\t}\n\t\t\t\tif (chunk.usage) {\n\t\t\t\t\toutput.usage = parseChunkUsage(chunk.usage, model);\n\t\t\t\t}\n\n\t\t\t\tconst choice = Array.isArray(chunk.choices) ? chunk.choices[0] : undefined;\n\t\t\t\tif (!choice) continue;\n\n\t\t\t\t// Fallback: some providers (e.g., Moonshot) return usage\n\t\t\t\t// in choice.usage instead of the standard chunk.usage\n\t\t\t\tif (!chunk.usage && (choice as any).usage) {\n\t\t\t\t\toutput.usage = parseChunkUsage((choice as any).usage, model);\n\t\t\t\t}\n\n\t\t\t\tif (choice.finish_reason) {\n\t\t\t\t\tconst finishReasonResult = mapStopReason(choice.finish_reason);\n\t\t\t\t\toutput.stopReason = finishReasonResult.stopReason;\n\t\t\t\t\tif (finishReasonResult.errorMessage) {\n\t\t\t\t\t\toutput.errorMessage = finishReasonResult.errorMessage;\n\t\t\t\t\t}\n\t\t\t\t\thasFinishReason = true;\n\t\t\t\t}\n\n\t\t\t\tif (choice.delta) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tchoice.delta.content !== null &&\n\t\t\t\t\t\tchoice.delta.content !== undefined &&\n\t\t\t\t\t\tchoice.delta.content.length > 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tappendTextDelta(thinkingTagFilter.push(choice.delta.content));\n\t\t\t\t\t}\n\n\t\t\t\t\t// Some endpoints return reasoning in reasoning_content (llama.cpp),\n\t\t\t\t\t// or reasoning (other openai compatible endpoints)\n\t\t\t\t\t// Use the first non-empty reasoning field to avoid duplication\n\t\t\t\t\t// (e.g., chutes.ai returns both reasoning_content and reasoning with same content)\n\t\t\t\t\tconst reasoningFields = [\"reasoning_content\", \"reasoning\", \"reasoning_text\"];\n\t\t\t\t\tconst deltaFields = choice.delta as Record<string, unknown>;\n\t\t\t\t\tlet foundReasoningField: string | null = null;\n\t\t\t\t\tfor (const field of reasoningFields) {\n\t\t\t\t\t\tconst value = deltaFields[field];\n\t\t\t\t\t\tif (typeof value === \"string\" && value.length > 0) {\n\t\t\t\t\t\t\tfoundReasoningField = field;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tfoundReasoningField &&\n\t\t\t\t\t\t!(compat.thinkingFormat === \"minimax\" && (!options?.reasoningEffort || model.reasoning === false))\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst delta = deltaFields[foundReasoningField];\n\t\t\t\t\t\tif (typeof delta === \"string\" && delta.length > 0) {\n\t\t\t\t\t\t\tconst thinkingSignature =\n\t\t\t\t\t\t\t\tmodel.provider === \"opencode-go\" && foundReasoningField === \"reasoning\"\n\t\t\t\t\t\t\t\t\t? \"reasoning_content\"\n\t\t\t\t\t\t\t\t\t: foundReasoningField;\n\t\t\t\t\t\t\tconst block = ensureThinkingBlock(thinkingSignature);\n\t\t\t\t\t\t\tblock.thinking += delta;\n\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\t\t\t\tdelta,\n\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (choice?.delta?.tool_calls) {\n\t\t\t\t\t\tfor (const toolCall of choice.delta.tool_calls) {\n\t\t\t\t\t\t\tconst block = ensureToolCallBlock(toolCall);\n\t\t\t\t\t\t\tif (!block.id && toolCall.id) {\n\t\t\t\t\t\t\t\tblock.id = toolCall.id;\n\t\t\t\t\t\t\t\ttoolCallBlocksById.set(toolCall.id, block);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!block.name && toolCall.function?.name) {\n\t\t\t\t\t\t\t\tblock.name = toolCall.function.name;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlet delta = \"\";\n\t\t\t\t\t\t\tif (toolCall.function?.arguments) {\n\t\t\t\t\t\t\t\tdelta = toolCall.function.arguments;\n\t\t\t\t\t\t\t\tblock.partialArgs = (block.partialArgs ?? \"\") + toolCall.function.arguments;\n\t\t\t\t\t\t\t\tblock.arguments = parseStreamingJson(block.partialArgs);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\t\t\t\tcontentIndex: getContentIndex(block),\n\t\t\t\t\t\t\t\tdelta,\n\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst reasoningDetails = (choice.delta as { reasoning_details?: unknown }).reasoning_details;\n\t\t\t\t\tif (Array.isArray(reasoningDetails)) {\n\t\t\t\t\t\tfor (const detail of reasoningDetails) {\n\t\t\t\t\t\t\tif (isEncryptedReasoningDetail(detail)) {\n\t\t\t\t\t\t\t\tconst serializedDetail = JSON.stringify(detail);\n\t\t\t\t\t\t\t\tconst matchingToolCall = toolCallBlocksById.get(detail.id);\n\t\t\t\t\t\t\t\tif (matchingToolCall) {\n\t\t\t\t\t\t\t\t\tmatchingToolCall.thoughtSignature = serializedDetail;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tpendingReasoningDetailsByToolCallId.set(detail.id, serializedDetail);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tappendTextDelta(thinkingTagFilter.flush());\n\n\t\t\tfor (const block of blocks) {\n\t\t\t\tfinishBlock(block);\n\t\t\t}\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"aborted\") {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\t\t\tif (!hasFinishReason && !compat.supportsFinishReason) {\n\t\t\t\tif (hasIncompleteToolCallArguments) {\n\t\t\t\t\tthrow new Error(\"Stream ended without finish_reason and with incomplete tool call arguments\");\n\t\t\t\t}\n\t\t\t\toutput.stopReason = output.content.some((block) => block.type === \"toolCall\") ? \"toolUse\" : \"stop\";\n\t\t\t}\n\t\t\tif (output.stopReason === \"error\") {\n\t\t\t\tthrow new Error(output.errorMessage || \"Provider returned an error stop reason\");\n\t\t\t}\n\t\t\tif (compat.supportsFinishReason && !hasFinishReason) {\n\t\t\t\tthrow new Error(\"Stream ended without finish_reason\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tdelete (block as { index?: number }).index;\n\t\t\t\t// Streaming scratch buffers are only used during parsing; never persist them.\n\t\t\t\tdelete (block as { partialArgs?: string }).partialArgs;\n\t\t\t\tdelete (block as { streamIndex?: number }).streamIndex;\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tconst normalized = normalizeProviderError(error);\n\t\t\toutput.errorMetadata = normalized.errorMetadata;\n\t\t\toutput.errorMessage = formatProviderError(normalized);\n\t\t\t// Some providers via OpenRouter give additional information in this field.\n\t\t\t// normalizeProviderError already stringifies the parsed body (error.error)\n\t\t\t// into errorMessage, so only append the raw metadata when it is not already\n\t\t\t// present to avoid double-printing it.\n\t\t\tconst rawMetadata = (error as any)?.error?.metadata?.raw;\n\t\t\tif (rawMetadata && !output.errorMessage.includes(String(rawMetadata))) {\n\t\t\t\toutput.errorMessage += `\\n${rawMetadata}`;\n\t\t\t}\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimpleOpenAICompletions: StreamFunction<\"openai-completions\", SimpleStreamOptions> = (\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider, options?.env);\n\tif (!apiKey && model.authHeader !== false) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\n\tconst base = buildBaseOptions(model, context, options, apiKey ?? \"\");\n\tconst clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;\n\tconst reasoningEffort = clampedReasoning === \"off\" ? undefined : clampedReasoning;\n\tconst toolChoice = (options as OpenAICompletionsOptions | undefined)?.toolChoice;\n\n\treturn streamOpenAICompletions(model, context, {\n\t\t...base,\n\t\treasoningEffort,\n\t\ttoolChoice,\n\t} satisfies OpenAICompletionsOptions);\n};\n\nfunction createClient(\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\tapiKey?: string,\n\toptionsHeaders?: Record<string, string>,\n\tsessionId?: string,\n\tcompat: ResolvedOpenAICompletionsCompat = getCompat(model),\n\tenv?: ProviderEnv,\n) {\n\tconst noAuth = model.authHeader === false;\n\tif (!apiKey && !noAuth) {\n\t\tconst configuredApiKey = getProviderEnvValue(\"OPENAI_API_KEY\", env);\n\t\tif (!configuredApiKey) {\n\t\t\tthrow new Error(\n\t\t\t\t\"OpenAI API key is required. Set OPENAI_API_KEY environment variable or pass it as an argument.\",\n\t\t\t);\n\t\t}\n\t\tapiKey = configuredApiKey;\n\t}\n\tif (!apiKey) apiKey = \"merc-no-auth\";\n\n\tconst headers = { ...model.headers };\n\tif (model.provider === \"github-copilot\") {\n\t\tconst hasImages = hasCopilotVisionInput(context.messages);\n\t\tconst copilotHeaders = buildCopilotDynamicHeaders({\n\t\t\tmessages: context.messages,\n\t\t\thasImages,\n\t\t});\n\t\tObject.assign(headers, copilotHeaders);\n\t}\n\n\tif (sessionId && compat.sendSessionAffinityHeaders) {\n\t\tif (compat.sessionAffinityFormat === \"openrouter\") {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t} else {\n\t\t\tif (compat.sessionAffinityFormat === \"openai\") headers.session_id = sessionId;\n\t\t\theaders[\"x-client-request-id\"] = sessionId;\n\t\t\theaders[\"x-session-affinity\"] = sessionId;\n\t\t}\n\t}\n\n\t// Merge options headers last so they can override defaults\n\tif (optionsHeaders) {\n\t\tObject.assign(headers, optionsHeaders);\n\t}\n\n\tconst defaultHeaders = noAuth\n\t\t? { ...headers, Authorization: null }\n\t\t: model.provider === \"cloudflare-ai-gateway\"\n\t\t\t? {\n\t\t\t\t\t...headers,\n\t\t\t\t\tAuthorization: headers.Authorization ?? null,\n\t\t\t\t\t\"cf-aig-authorization\": `Bearer ${apiKey}`,\n\t\t\t\t}\n\t\t\t: headers;\n\n\treturn new OpenAI({\n\t\tapiKey,\n\t\tbaseURL: isCloudflareProvider(model.provider) ? resolveCloudflareBaseUrl(model, env) : model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tdefaultHeaders,\n\t});\n}\n\nfunction buildParams(\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\toptions?: OpenAICompletionsOptions,\n\tcompat: ResolvedOpenAICompletionsCompat = getCompat(model),\n\tcacheRetention: CacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env),\n) {\n\tconst messages = convertMessages(model, context, compat);\n\tconst cacheControl = getCompatCacheControl(compat, cacheRetention);\n\n\tconst params: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {\n\t\tmodel: model.id,\n\t\tmessages,\n\t\tstream: true,\n\t\tprompt_cache_key:\n\t\t\t(model.baseUrl.includes(\"api.openai.com\") && cacheRetention !== \"none\") ||\n\t\t\t(cacheRetention === \"long\" && compat.supportsLongCacheRetention)\n\t\t\t\t? clampOpenAIPromptCacheKey(options?.sessionId)\n\t\t\t\t: undefined,\n\t\tprompt_cache_retention: cacheRetention === \"long\" && compat.supportsLongCacheRetention ? \"24h\" : undefined,\n\t};\n\n\tif (isOpenRouterImageGenerationModel(model)) {\n\t\tReflect.set(params, \"modalities\", [\"image\"]);\n\t}\n\n\tif (compat.supportsUsageInStreaming !== false) {\n\t\t(params as any).stream_options = { include_usage: true };\n\t}\n\n\tif (compat.supportsStore) {\n\t\tparams.store = false;\n\t}\n\n\tif (options?.maxTokens) {\n\t\tif (compat.maxTokensField === \"max_tokens\") {\n\t\t\t(params as any).max_tokens = options.maxTokens;\n\t\t} else {\n\t\t\tparams.max_completion_tokens = options.maxTokens;\n\t\t}\n\t}\n\n\tif (options?.temperature !== undefined) {\n\t\tparams.temperature = options.temperature;\n\t}\n\n\tif (!isOpenRouterImageGenerationModel(model) && context.tools && context.tools.length > 0) {\n\t\tparams.tools = convertTools(context.tools, compat);\n\t\tif (compat.zaiToolStream) {\n\t\t\t(params as any).tool_stream = true;\n\t\t}\n\t} else if (!isOpenRouterImageGenerationModel(model) && hasToolHistory(context.messages)) {\n\t\t// Anthropic (via LiteLLM/proxy) requires tools param when conversation has tool_calls/tool_results\n\t\tparams.tools = [];\n\t}\n\n\tif (cacheControl) {\n\t\tapplyAnthropicCacheControl(messages, params.tools, cacheControl);\n\t}\n\n\tif (options?.toolChoice && params.tools?.length) {\n\t\tparams.tool_choice = options.toolChoice;\n\t}\n\n\tif (compat.thinkingFormat === \"zai\" && model.reasoning) {\n\t\tconst zaiParams = params as Omit<typeof params, \"reasoning_effort\"> & {\n\t\t\tthinking?: { type: \"enabled\" | \"disabled\"; clear_thinking?: boolean };\n\t\t\treasoning_effort?: string;\n\t\t};\n\t\tzaiParams.thinking = options?.reasoningEffort ? { type: \"enabled\", clear_thinking: false } : { type: \"disabled\" };\n\t\tif (options?.reasoningEffort && compat.supportsReasoningEffort) {\n\t\t\tconst mappedEffort = model.thinkingLevelMap?.[options.reasoningEffort];\n\t\t\tconst effort = mappedEffort === undefined ? options.reasoningEffort : mappedEffort;\n\t\t\tif (typeof effort === \"string\") {\n\t\t\t\tzaiParams.reasoning_effort = effort;\n\t\t\t}\n\t\t}\n\t} else if (compat.thinkingFormat === \"minimax\") {\n\t\tconst minimaxParams = params as typeof params & {\n\t\t\tthinking?: { type: \"adaptive\" | \"disabled\" };\n\t\t\treasoning_split?: boolean;\n\t\t};\n\t\tminimaxParams.thinking = { type: options?.reasoningEffort ? \"adaptive\" : \"disabled\" };\n\t\tminimaxParams.reasoning_split = true;\n\t} else if (compat.thinkingFormat === \"qwen\" && model.reasoning) {\n\t\t(params as any).enable_thinking = !!options?.reasoningEffort;\n\t} else if (compat.thinkingFormat === \"qwen-chat-template\" && model.reasoning) {\n\t\t(params as any).chat_template_kwargs = {\n\t\t\tenable_thinking: !!options?.reasoningEffort,\n\t\t\tpreserve_thinking: true,\n\t\t};\n\t} else if (compat.thinkingFormat === \"deepseek\" && model.reasoning) {\n\t\tif (options?.reasoningEffort) {\n\t\t\t(params as any).thinking = { type: \"enabled\" };\n\t\t} else if (model.thinkingLevelMap?.off !== null) {\n\t\t\t(params as any).thinking = { type: \"disabled\" };\n\t\t}\n\t\tif (options?.reasoningEffort && compat.supportsReasoningEffort) {\n\t\t\t(params as any).reasoning_effort =\n\t\t\t\tmodel.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n\t\t}\n\t} else if (compat.thinkingFormat === \"ant-ling\" && model.reasoning && options?.reasoningEffort) {\n\t\tconst effort = model.thinkingLevelMap?.[options.reasoningEffort];\n\t\tif (typeof effort === \"string\") {\n\t\t\t(params as typeof params & { reasoning?: { effort: string } }).reasoning = { effort };\n\t\t}\n\t} else if (compat.thinkingFormat === \"openrouter\" && model.reasoning) {\n\t\t// OpenRouter normalizes reasoning across providers via a nested reasoning object.\n\t\tconst openRouterParams = params as typeof params & { reasoning?: { effort?: string } };\n\t\tif (options?.reasoningEffort) {\n\t\t\topenRouterParams.reasoning = {\n\t\t\t\teffort: model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort,\n\t\t\t};\n\t\t} else if (model.thinkingLevelMap?.off !== null) {\n\t\t\topenRouterParams.reasoning = { effort: model.thinkingLevelMap?.off ?? \"none\" };\n\t\t}\n\t} else if (options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {\n\t\t// OpenAI-style reasoning_effort\n\t\t(params as any).reasoning_effort = model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;\n\t} else if (!options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {\n\t\tconst offValue = model.thinkingLevelMap?.off;\n\t\tif (typeof offValue === \"string\") {\n\t\t\t(params as any).reasoning_effort = offValue;\n\t\t}\n\t}\n\n\t// OpenRouter provider routing preferences\n\tif (model.baseUrl.includes(\"openrouter.ai\") && model.compat?.openRouterRouting) {\n\t\t(params as any).provider = model.compat.openRouterRouting;\n\t}\n\n\t// Vercel AI Gateway provider routing preferences\n\tif (model.baseUrl.includes(\"ai-gateway.vercel.sh\") && model.compat?.vercelGatewayRouting) {\n\t\tconst routing = model.compat.vercelGatewayRouting;\n\t\tif (routing.only || routing.order) {\n\t\t\tconst gatewayOptions: Record<string, string[]> = {};\n\t\t\tif (routing.only) gatewayOptions.only = routing.only;\n\t\t\tif (routing.order) gatewayOptions.order = routing.order;\n\t\t\t(params as any).providerOptions = { gateway: gatewayOptions };\n\t\t}\n\t}\n\n\treturn params;\n}\n\nfunction getCompatCacheControl(\n\tcompat: ResolvedOpenAICompletionsCompat,\n\tcacheRetention: CacheRetention,\n): OpenAICompatCacheControl | undefined {\n\tif (compat.cacheControlFormat !== \"anthropic\" || cacheRetention === \"none\") {\n\t\treturn undefined;\n\t}\n\n\tconst ttl = cacheRetention === \"long\" && compat.supportsLongCacheRetention ? \"1h\" : undefined;\n\treturn { type: \"ephemeral\", ...(ttl ? { ttl } : {}) };\n}\n\nfunction applyAnthropicCacheControl(\n\tmessages: ChatCompletionMessageParam[],\n\ttools: OpenAI.Chat.Completions.ChatCompletionTool[] | undefined,\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\taddCacheControlToSystemPrompt(messages, cacheControl);\n\taddCacheControlToLastTool(tools, cacheControl);\n\taddCacheControlToLastConversationMessage(messages, cacheControl);\n}\n\nfunction addCacheControlToSystemPrompt(\n\tmessages: ChatCompletionMessageParam[],\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\tfor (const message of messages) {\n\t\tif (message.role === \"system\" || message.role === \"developer\") {\n\t\t\taddCacheControlToInstructionMessage(message, cacheControl);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nfunction addCacheControlToLastConversationMessage(\n\tmessages: ChatCompletionMessageParam[],\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst message = messages[i];\n\t\tif (message.role === \"user\" || message.role === \"assistant\" || message.role === \"tool\") {\n\t\t\tif (addCacheControlToMessage(message, cacheControl)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction addCacheControlToLastTool(\n\ttools: OpenAI.Chat.Completions.ChatCompletionTool[] | undefined,\n\tcacheControl: OpenAICompatCacheControl,\n): void {\n\tif (!tools || tools.length === 0) {\n\t\treturn;\n\t}\n\n\tconst lastTool = tools[tools.length - 1] as ChatCompletionToolWithCacheControl;\n\tlastTool.cache_control = cacheControl;\n}\n\nfunction addCacheControlToInstructionMessage(\n\tmessage: ChatCompletionInstructionMessageParam,\n\tcacheControl: OpenAICompatCacheControl,\n): boolean {\n\treturn addCacheControlToTextContent(message, cacheControl);\n}\n\nfunction addCacheControlToMessage(\n\tmessage: ChatCompletionMessageParam,\n\tcacheControl: OpenAICompatCacheControl,\n): boolean {\n\tif (message.role === \"user\" || message.role === \"assistant\" || message.role === \"tool\") {\n\t\treturn addCacheControlToTextContent(message, cacheControl);\n\t}\n\treturn false;\n}\n\nfunction addCacheControlToTextContent(\n\tmessage:\n\t\t| ChatCompletionInstructionMessageParam\n\t\t| ChatCompletionAssistantMessageParam\n\t\t| ChatCompletionToolMessageParam\n\t\t| Extract<ChatCompletionMessageParam, { role: \"user\" }>,\n\tcacheControl: OpenAICompatCacheControl,\n): boolean {\n\tconst content = message.content;\n\tif (typeof content === \"string\") {\n\t\tif (content.length === 0) {\n\t\t\treturn false;\n\t\t}\n\t\tmessage.content = [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: content,\n\t\t\t\tcache_control: cacheControl,\n\t\t\t},\n\t\t] as ChatCompletionTextPartWithCacheControl[];\n\t\treturn true;\n\t}\n\n\tif (!Array.isArray(content)) {\n\t\treturn false;\n\t}\n\n\tfor (let i = content.length - 1; i >= 0; i--) {\n\t\tconst part = content[i];\n\t\tif (part?.type === \"text\") {\n\t\t\tconst textPart = part as ChatCompletionTextPartWithCacheControl;\n\t\t\ttextPart.cache_control = cacheControl;\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nexport function convertMessages(\n\tmodel: Model<\"openai-completions\">,\n\tcontext: Context,\n\tcompat: ResolvedOpenAICompletionsCompat,\n): ChatCompletionMessageParam[] {\n\tconst params: ChatCompletionMessageParam[] = [];\n\n\tconst normalizeToolCallId = createProviderToolCallIdNormalizer(model);\n\n\tconst transformedMessages = transformMessages(context.messages, model, (id) => normalizeToolCallId(id));\n\n\tif (context.systemPrompt) {\n\t\tconst useDeveloperRole = model.reasoning && compat.supportsDeveloperRole;\n\t\tconst role = useDeveloperRole ? \"developer\" : \"system\";\n\t\tparams.push({ role: role, content: sanitizeSurrogates(context.systemPrompt) });\n\t}\n\n\tlet lastRole: string | null = null;\n\n\tfor (let i = 0; i < transformedMessages.length; i++) {\n\t\tconst msg = transformedMessages[i];\n\t\t// Some providers don't allow user messages directly after tool results\n\t\t// Insert a synthetic assistant message to bridge the gap\n\t\tif (compat.requiresAssistantAfterToolResult && lastRole === \"toolResult\" && msg.role === \"user\") {\n\t\t\tparams.push({\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: \"I have processed the tool results.\",\n\t\t\t});\n\t\t}\n\n\t\tif (msg.role === \"user\") {\n\t\t\tif (typeof msg.content === \"string\") {\n\t\t\t\tparams.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: sanitizeSurrogates(msg.content),\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst content: ChatCompletionContentPart[] = msg.content\n\t\t\t\t\t.filter((item) => item.type !== \"text\" || item.text.length > 0)\n\t\t\t\t\t.map((item): ChatCompletionContentPart => {\n\t\t\t\t\t\tif (item.type === \"text\") {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\ttext: sanitizeSurrogates(item.text),\n\t\t\t\t\t\t\t} satisfies ChatCompletionContentPartText;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\ttype: \"image_url\",\n\t\t\t\t\t\t\t\timage_url: {\n\t\t\t\t\t\t\t\t\turl: `data:${item.mimeType};base64,${item.data}`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t} satisfies ChatCompletionContentPartImage;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tif (content.length === 0) continue;\n\t\t\t\tparams.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (msg.role === \"assistant\") {\n\t\t\t// Some providers don't accept null content, use empty string instead\n\t\t\tconst assistantMsg: ChatCompletionAssistantMessageParam = {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: compat.requiresAssistantAfterToolResult ? \"\" : null,\n\t\t\t};\n\n\t\t\tconst assistantTextParts = msg.content\n\t\t\t\t.filter(isTextContentBlock)\n\t\t\t\t.filter((block) => block.text.trim().length > 0)\n\t\t\t\t.map(\n\t\t\t\t\t(block) =>\n\t\t\t\t\t\t({\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: sanitizeSurrogates(block.text),\n\t\t\t\t\t\t}) satisfies ChatCompletionContentPartText,\n\t\t\t\t);\n\t\t\tconst assistantText = assistantTextParts.map((part) => part.text).join(\"\");\n\n\t\t\tconst nonEmptyThinkingBlocks = msg.content\n\t\t\t\t.filter(isThinkingContentBlock)\n\t\t\t\t.filter((block) => block.thinking.trim().length > 0);\n\t\t\tif (nonEmptyThinkingBlocks.length > 0) {\n\t\t\t\tif (compat.requiresThinkingAsText) {\n\t\t\t\t\t// Convert thinking blocks to plain text (no tags to avoid model mimicking them)\n\t\t\t\t\tconst thinkingText = nonEmptyThinkingBlocks\n\t\t\t\t\t\t.map((block) => sanitizeSurrogates(block.thinking))\n\t\t\t\t\t\t.join(\"\\n\\n\");\n\t\t\t\t\tassistantMsg.content = [{ type: \"text\", text: thinkingText }, ...assistantTextParts];\n\t\t\t\t} else {\n\t\t\t\t\t// Always send assistant content as a plain string (OpenAI Chat Completions\n\t\t\t\t\t// API standard format). Sending as an array of {type:\"text\", text:\"...\"}\n\t\t\t\t\t// objects is non-standard and causes some models (e.g. DeepSeek V3.2 via\n\t\t\t\t\t// NVIDIA NIM) to mirror the content-block structure literally in their\n\t\t\t\t\t// output, producing recursive nesting like [{'type':'text','text':'[{...}]'}].\n\t\t\t\t\tif (assistantText.length > 0) {\n\t\t\t\t\t\tassistantMsg.content = assistantText;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Use the signature from the first thinking block if available (for llama.cpp server + gpt-oss)\n\t\t\t\t\tlet signature = nonEmptyThinkingBlocks[0].thinkingSignature;\n\t\t\t\t\tif (model.provider === \"opencode-go\" && signature === \"reasoning\") {\n\t\t\t\t\t\tsignature = \"reasoning_content\";\n\t\t\t\t\t}\n\t\t\t\t\tif (signature && signature.length > 0) {\n\t\t\t\t\t\t(assistantMsg as any)[signature] = nonEmptyThinkingBlocks.map((block) => block.thinking).join(\"\\n\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (assistantText.length > 0) {\n\t\t\t\t// Always send assistant content as a plain string (OpenAI Chat Completions\n\t\t\t\t// API standard format). Sending as an array of {type:\"text\", text:\"...\"}\n\t\t\t\t// objects is non-standard and causes some models (e.g. DeepSeek V3.2 via\n\t\t\t\t// NVIDIA NIM) to mirror the content-block structure literally in their\n\t\t\t\t// output, producing recursive nesting like [{'type':'text','text':'[{...}]'}].\n\t\t\t\tassistantMsg.content = assistantText;\n\t\t\t}\n\n\t\t\tconst toolCalls = msg.content.filter(isToolCallBlock);\n\t\t\tif (toolCalls.length > 0) {\n\t\t\t\tassistantMsg.tool_calls = toolCalls.map((tc) => ({\n\t\t\t\t\tid: tc.id,\n\t\t\t\t\ttype: \"function\" as const,\n\t\t\t\t\tfunction: {\n\t\t\t\t\t\tname: tc.name,\n\t\t\t\t\t\targuments: JSON.stringify(tc.arguments),\n\t\t\t\t\t},\n\t\t\t\t}));\n\t\t\t\tconst reasoningDetails = toolCalls\n\t\t\t\t\t.filter((tc) => tc.thoughtSignature)\n\t\t\t\t\t.map((tc) => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\treturn JSON.parse(tc.thoughtSignature!);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.filter(Boolean);\n\t\t\t\tif (reasoningDetails.length > 0) {\n\t\t\t\t\t(assistantMsg as any).reasoning_details = reasoningDetails;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (\n\t\t\t\tcompat.requiresReasoningContentOnAssistantMessages &&\n\t\t\t\tmodel.reasoning &&\n\t\t\t\t(assistantMsg as { reasoning_content?: string }).reasoning_content === undefined\n\t\t\t) {\n\t\t\t\t(assistantMsg as { reasoning_content?: string }).reasoning_content = \"\";\n\t\t\t}\n\t\t\t// Skip assistant messages that have no content and no tool calls.\n\t\t\t// Some providers require \"either content or tool_calls, but not none\".\n\t\t\t// Other providers also don't accept empty assistant messages.\n\t\t\t// This handles aborted assistant responses that got no content.\n\t\t\tconst content = assistantMsg.content;\n\t\t\tconst hasContent =\n\t\t\t\tcontent !== null &&\n\t\t\t\tcontent !== undefined &&\n\t\t\t\t(typeof content === \"string\" ? content.length > 0 : content.length > 0);\n\t\t\tif (!hasContent && !assistantMsg.tool_calls) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tparams.push(assistantMsg);\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\tconst imageBlocks: Array<{ type: \"image_url\"; image_url: { url: string } }> = [];\n\t\t\tlet j = i;\n\n\t\t\tfor (; j < transformedMessages.length && transformedMessages[j].role === \"toolResult\"; j++) {\n\t\t\t\tconst toolMsg = transformedMessages[j] as ToolResultMessage;\n\n\t\t\t\t// Extract text and image content\n\t\t\t\tconst textResult = toolMsg.content\n\t\t\t\t\t.filter(isTextContentBlock)\n\t\t\t\t\t.map((block) => block.text)\n\t\t\t\t\t.join(\"\\n\");\n\t\t\t\tconst hasImages = toolMsg.content.some((c) => c.type === \"image\");\n\n\t\t\t\t// Always send tool result with text (or placeholder if only images)\n\t\t\t\tconst hasText = textResult.length > 0;\n\t\t\t\tconst toolResultText = hasText ? textResult : hasImages ? \"(see attached image)\" : \"(no tool output)\";\n\t\t\t\t// Some providers require the 'name' field in tool results\n\t\t\t\tconst toolResultMsg: ChatCompletionToolMessageParam = {\n\t\t\t\t\trole: \"tool\",\n\t\t\t\t\tcontent: sanitizeSurrogates(toolResultText),\n\t\t\t\t\ttool_call_id: toolMsg.toolCallId,\n\t\t\t\t};\n\t\t\t\tif (compat.requiresToolResultName && toolMsg.toolName) {\n\t\t\t\t\t(toolResultMsg as any).name = toolMsg.toolName;\n\t\t\t\t}\n\t\t\t\tparams.push(toolResultMsg);\n\n\t\t\t\tif (hasImages && model.input.includes(\"image\")) {\n\t\t\t\t\tfor (const block of toolMsg.content) {\n\t\t\t\t\t\tif (isImageContentBlock(block)) {\n\t\t\t\t\t\t\timageBlocks.push({\n\t\t\t\t\t\t\t\ttype: \"image_url\",\n\t\t\t\t\t\t\t\timage_url: {\n\t\t\t\t\t\t\t\t\turl: `data:${block.mimeType};base64,${block.data}`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ti = j - 1;\n\n\t\t\tif (imageBlocks.length > 0) {\n\t\t\t\tif (compat.requiresAssistantAfterToolResult) {\n\t\t\t\t\tparams.push({\n\t\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\t\tcontent: \"I have processed the tool results.\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tparams.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: \"Attached image(s) from tool result:\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...imageBlocks,\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\tlastRole = \"user\";\n\t\t\t} else {\n\t\t\t\tlastRole = \"toolResult\";\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tlastRole = msg.role;\n\t}\n\n\treturn params;\n}\n\nfunction convertTools(\n\ttools: Tool[],\n\tcompat: ResolvedOpenAICompletionsCompat,\n): OpenAI.Chat.Completions.ChatCompletionTool[] {\n\treturn tools.map((tool) => ({\n\t\ttype: \"function\",\n\t\tfunction: {\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: tool.parameters as any, // TypeBox already generates JSON Schema\n\t\t\t// Only include strict if provider supports it. Some reject unknown fields.\n\t\t\t...(compat.supportsStrictMode !== false && { strict: false }),\n\t\t},\n\t}));\n}\n\nfunction parseChunkUsage(\n\trawUsage: {\n\t\tprompt_tokens?: number;\n\t\tcompletion_tokens?: number;\n\t\tcached_tokens?: number;\n\t\tprompt_cache_hit_tokens?: number;\n\t\tprompt_tokens_details?: { cached_tokens?: number; cache_write_tokens?: number };\n\t},\n\tmodel: Model<\"openai-completions\">,\n): AssistantMessage[\"usage\"] {\n\tconst promptTokens = rawUsage.prompt_tokens || 0;\n\tconst cacheReadTokens =\n\t\trawUsage.prompt_tokens_details?.cached_tokens ?? rawUsage.prompt_cache_hit_tokens ?? rawUsage.cached_tokens ?? 0;\n\tconst cacheWriteTokens = rawUsage.prompt_tokens_details?.cache_write_tokens || 0;\n\n\t// Follow documented OpenAI/OpenRouter semantics: cached_tokens is cache-read\n\t// tokens (hits). Providers disagree on placement: OpenAI/OpenRouter use\n\t// prompt_tokens_details.cached_tokens, DeepSeek uses prompt_cache_hit_tokens,\n\t// and Kimi documents top-level usage.cached_tokens on the final usage chunk.\n\t// OpenAI does not document or emit cache_write_tokens, but\n\t// OpenRouter-compatible providers can include it as a separate write count.\n\t// OpenRouter's own provider/tests affirm the separate mapping:\n\t// https://github.com/OpenRouterTeam/ai-sdk-provider/pull/409\n\t// Do not subtract writes from cached_tokens, otherwise spec-compliant\n\t// providers are under-reported. DS4 mirrors this contract too:\n\t// https://github.com/antirez/ds4/pull/29\n\tconst input = Math.max(0, promptTokens - cacheReadTokens - cacheWriteTokens);\n\t// OpenAI completion_tokens already includes reasoning_tokens.\n\tconst outputTokens = rawUsage.completion_tokens || 0;\n\tconst usage: AssistantMessage[\"usage\"] = {\n\t\tinput,\n\t\toutput: outputTokens,\n\t\tcacheRead: cacheReadTokens,\n\t\tcacheWrite: cacheWriteTokens,\n\t\ttotalTokens: input + outputTokens + cacheReadTokens + cacheWriteTokens,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n\tcalculateCost(model, usage);\n\treturn usage;\n}\n\nfunction mapStopReason(reason: ChatCompletionChunk.Choice[\"finish_reason\"] | string): {\n\tstopReason: StopReason;\n\terrorMessage?: string;\n} {\n\tif (reason === null) return { stopReason: \"stop\" };\n\tswitch (reason) {\n\t\tcase \"stop\":\n\t\tcase \"end\":\n\t\t\treturn { stopReason: \"stop\" };\n\t\tcase \"length\":\n\t\t\treturn { stopReason: \"length\" };\n\t\tcase \"function_call\":\n\t\tcase \"tool_calls\":\n\t\t\treturn { stopReason: \"toolUse\" };\n\t\tcase \"content_filter\":\n\t\t\treturn { stopReason: \"error\", errorMessage: \"Provider finish_reason: content_filter\" };\n\t\tcase \"network_error\":\n\t\t\treturn { stopReason: \"error\", errorMessage: \"Provider finish_reason: network_error\" };\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tstopReason: \"error\",\n\t\t\t\terrorMessage: `Provider finish_reason: ${reason}`,\n\t\t\t};\n\t}\n}\n\n/**\n * Detect compatibility settings from provider and baseUrl for known providers.\n * Provider takes precedence over URL-based detection since it's explicitly configured.\n * Returns a fully resolved OpenAICompletionsCompat object with all fields set.\n */\nfunction detectCompat(model: Model<\"openai-completions\">): ResolvedOpenAICompletionsCompat {\n\tconst provider = model.provider;\n\tconst baseUrl = model.baseUrl;\n\n\tconst isZai = provider === \"zai\" || baseUrl.includes(\"api.z.ai\");\n\tconst isMoonshot = provider === \"moonshotai\" || provider === \"moonshotai-cn\" || baseUrl.includes(\"api.moonshot.\");\n\tconst isCloudflareWorkersAI = provider === \"cloudflare-workers-ai\" || baseUrl.includes(\"api.cloudflare.com\");\n\tconst isCloudflareAiGateway = provider === \"cloudflare-ai-gateway\" || baseUrl.includes(\"gateway.ai.cloudflare.com\");\n\tconst isAntLing = provider === \"ant-ling\" || baseUrl.includes(\"api.ant-ling.com\");\n\tconst isMiniMax = isMiniMaxModel(model);\n\tconst isDeepSeek = provider === \"deepseek\" || baseUrl.toLowerCase().includes(\"deepseek.com\");\n\n\tconst isNonStandard =\n\t\tprovider === \"cerebras\" ||\n\t\tbaseUrl.includes(\"cerebras.ai\") ||\n\t\tprovider === \"xai\" ||\n\t\tbaseUrl.includes(\"api.x.ai\") ||\n\t\tbaseUrl.includes(\"chutes.ai\") ||\n\t\tisDeepSeek ||\n\t\tisZai ||\n\t\tisMoonshot ||\n\t\tprovider === \"opencode\" ||\n\t\tbaseUrl.includes(\"opencode.ai\") ||\n\t\tisCloudflareWorkersAI ||\n\t\tisCloudflareAiGateway ||\n\t\tisAntLing;\n\n\t// Z.AI ignores max_completion_tokens, so its output cap only applies through max_tokens.\n\tconst isZaiMaxTokensEndpoint = isZai || provider === \"zai-coding-cn\" || baseUrl.includes(\"open.bigmodel.cn\");\n\tconst useMaxTokens =\n\t\tbaseUrl.includes(\"chutes.ai\") ||\n\t\tisDeepSeek ||\n\t\tisMoonshot ||\n\t\tisCloudflareAiGateway ||\n\t\tisAntLing ||\n\t\tisZaiMaxTokensEndpoint;\n\n\tconst isGrok = provider === \"xai\" || baseUrl.includes(\"api.x.ai\");\n\tconst cacheControlFormat = provider === \"openrouter\" && /^~?anthropic\\//.test(model.id) ? \"anthropic\" : undefined;\n\tconst isOpenRouter = provider === \"openrouter\" || baseUrl.includes(\"openrouter.ai\");\n\n\treturn {\n\t\tsupportsStore: !isNonStandard,\n\t\tsupportsDeveloperRole: !isNonStandard,\n\t\tsupportsReasoningEffort: !isGrok && !isZai && !isMoonshot && !isCloudflareAiGateway && !isAntLing,\n\t\tsupportsUsageInStreaming: true,\n\t\tsupportsFinishReason: true,\n\t\tmaxTokensField: useMaxTokens ? \"max_tokens\" : \"max_completion_tokens\",\n\t\trequiresToolResultName: false,\n\t\trequiresAssistantAfterToolResult: false,\n\t\trequiresThinkingAsText: false,\n\t\trequiresReasoningContentOnAssistantMessages: isDeepSeek,\n\t\tthinkingFormat: isMiniMax\n\t\t\t? \"minimax\"\n\t\t\t: isDeepSeek\n\t\t\t\t? \"deepseek\"\n\t\t\t\t: isZai\n\t\t\t\t\t? \"zai\"\n\t\t\t\t\t: isAntLing\n\t\t\t\t\t\t? \"ant-ling\"\n\t\t\t\t\t\t: provider === \"openrouter\" || baseUrl.includes(\"openrouter.ai\")\n\t\t\t\t\t\t\t? \"openrouter\"\n\t\t\t\t\t\t\t: \"openai\",\n\t\topenRouterRouting: {},\n\t\topenRouterImageGeneration: false,\n\t\tvercelGatewayRouting: {},\n\t\tzaiToolStream: false,\n\t\tsupportsStrictMode: !isMoonshot && !isCloudflareAiGateway,\n\t\tcacheControlFormat,\n\t\tsendSessionAffinityHeaders: isOpenRouter,\n\t\tsessionAffinityFormat: isOpenRouter ? \"openrouter\" : \"openai\",\n\t\tsupportsLongCacheRetention: !(isCloudflareWorkersAI || isCloudflareAiGateway || isAntLing),\n\t};\n}\n\n/**\n * Get resolved compatibility settings for a model.\n * Uses explicit model.compat if provided, otherwise auto-detects from provider/URL.\n */\nfunction getCompat(model: Model<\"openai-completions\">): ResolvedOpenAICompletionsCompat {\n\tconst detected = detectCompat(model);\n\tif (!model.compat) return detected;\n\n\treturn {\n\t\tsupportsStore: model.compat.supportsStore ?? detected.supportsStore,\n\t\tsupportsDeveloperRole: model.compat.supportsDeveloperRole ?? detected.supportsDeveloperRole,\n\t\tsupportsReasoningEffort: model.compat.supportsReasoningEffort ?? detected.supportsReasoningEffort,\n\t\tsupportsUsageInStreaming: model.compat.supportsUsageInStreaming ?? detected.supportsUsageInStreaming,\n\t\tsupportsFinishReason: model.compat.supportsFinishReason ?? detected.supportsFinishReason,\n\t\tmaxTokensField: model.compat.maxTokensField ?? detected.maxTokensField,\n\t\trequiresToolResultName: model.compat.requiresToolResultName ?? detected.requiresToolResultName,\n\t\trequiresAssistantAfterToolResult:\n\t\t\tmodel.compat.requiresAssistantAfterToolResult ?? detected.requiresAssistantAfterToolResult,\n\t\trequiresThinkingAsText: model.compat.requiresThinkingAsText ?? detected.requiresThinkingAsText,\n\t\trequiresReasoningContentOnAssistantMessages:\n\t\t\tmodel.compat.requiresReasoningContentOnAssistantMessages ??\n\t\t\tdetected.requiresReasoningContentOnAssistantMessages,\n\t\tthinkingFormat: model.compat.thinkingFormat ?? detected.thinkingFormat,\n\t\topenRouterRouting: model.compat.openRouterRouting ?? {},\n\t\topenRouterImageGeneration: model.compat.openRouterImageGeneration ?? detected.openRouterImageGeneration,\n\t\tvercelGatewayRouting: model.compat.vercelGatewayRouting ?? detected.vercelGatewayRouting,\n\t\tzaiToolStream: model.compat.zaiToolStream ?? detected.zaiToolStream,\n\t\tsupportsStrictMode: model.compat.supportsStrictMode ?? detected.supportsStrictMode,\n\t\tcacheControlFormat: model.compat.cacheControlFormat ?? detected.cacheControlFormat,\n\t\tsendSessionAffinityHeaders: model.compat.sendSessionAffinityHeaders ?? detected.sendSessionAffinityHeaders,\n\t\tsessionAffinityFormat: model.compat.sessionAffinityFormat ?? detected.sessionAffinityFormat,\n\t\tsupportsLongCacheRetention: model.compat.supportsLongCacheRetention ?? detected.supportsLongCacheRetention,\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"simple-options.d.ts","sourceRoot":"","sources":["../../src/providers/simple-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,GAAG,EACH,OAAO,EACP,KAAK,EACL,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,aAAa,EACb,MAAM,aAAa,CAAC;AAKrB,oEAAoE;AACpE,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAGrC,kFAAkF;AAClF,qBAAa,sBAAuB,SAAQ,KAAK;IAChD,6EAA6E;IAC7E,YAAY,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAK7C;CACD;AAED,sFAAsF;AACtF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAOtG;AAED,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,EAC7B,MAAM,CAAC,EAAE,MAAM,GACb,aAAa,CA6Bf;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC,aAAa,EAAE,OAAO,GAAG,KAAK,CAAC,GAAG,SAAS,CAErH;AAED,wBAAgB,0BAA0B,CAEzC,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,aAAa,EAC7B,aAAa,CAAC,EAAE,eAAe,GAC7B;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAoB/C","sourcesContent":["import type {\n\tApi,\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStreamOptions,\n\tThinkingBudgets,\n\tThinkingLevel,\n} from \"../types.js\";\nimport { estimateContextTokens } from \"../utils/estimate.js\";\n\nconst DEFAULT_MAX_OUTPUT_TOKENS = 32000;\nconst CONTEXT_WINDOW_OUTPUT_TOLERANCE = 1024;\n/** Headroom shared by request clamping and proactive compaction. */\nexport const CONTEXT_SAFETY_TOKENS = 4096;\n/** Minimum useful output allowance; deliberately smaller caller caps remain valid. */\nexport const MIN_OUTPUT_TOKENS = 256;\nconst MIN_MAX_TOKENS = 1;\n\n/** Refuses a request whose remaining context cannot support a useful response. */\nexport class OutputTokenBudgetError extends Error {\n\t/** Describe the available output and the minimum required before sending. */\n\tconstructor(available: number, minimum: number) {\n\t\tsuper(\n\t\t\t`Cannot send request: output budget ${available} tokens is below the required minimum ${minimum}. Compact the session or reduce the system prompt, tools, or input.`,\n\t\t);\n\t\tthis.name = \"OutputTokenBudgetError\";\n\t}\n}\n\n/** Purely calculate a context-safe output budget, or refuse an unusable allowance. */\nexport function clampMaxTokensToContext(model: Model<Api>, context: Context, maxTokens: number): number {\n\tif (model.contextWindow <= 0) return Math.max(MIN_MAX_TOKENS, maxTokens);\n\tconst available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;\n\tconst clamped = Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));\n\tconst minimum = Math.min(MIN_OUTPUT_TOKENS, maxTokens);\n\tif (clamped < minimum) throw new OutputTokenBudgetError(clamped, minimum);\n\treturn clamped;\n}\n\n/** Build common simple-provider options with a validated context-safe output allowance. */\nexport function buildBaseOptions(\n\tmodel: Model<Api>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n\tapiKey?: string,\n): StreamOptions {\n\tconst defaultMaxTokens =\n\t\tmodel.maxTokens > 0\n\t\t\t? model.maxTokens >= model.contextWindow - CONTEXT_WINDOW_OUTPUT_TOLERANCE\n\t\t\t\t? Math.min(model.maxTokens, DEFAULT_MAX_OUTPUT_TOKENS)\n\t\t\t\t: model.maxTokens\n\t\t\t: undefined;\n\n\tconst requestedMaxTokens = options?.maxTokens ?? defaultMaxTokens;\n\n\treturn {\n\t\ttemperature: options?.temperature,\n\t\tmaxTokens:\n\t\t\trequestedMaxTokens === undefined ? undefined : clampMaxTokensToContext(model, context, requestedMaxTokens),\n\t\tsignal: options?.signal,\n\t\tapiKey: apiKey || options?.apiKey,\n\t\ttransport: options?.transport,\n\t\tcacheRetention: options?.cacheRetention,\n\t\tsessionId: options?.sessionId,\n\t\theaders: options?.headers,\n\t\tonPayload: options?.onPayload,\n\t\tonResponse: options?.onResponse,\n\t\ttimeoutMs: options?.timeoutMs,\n\t\twebsocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,\n\t\tmaxRetries: options?.maxRetries,\n\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\tmetadata: options?.metadata,\n\t\tenv: options?.env,\n\t};\n}\n\nexport function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, \"xhigh\" | \"max\"> | undefined {\n\treturn effort === \"xhigh\" || effort === \"max\" ? \"high\" : effort;\n}\n\nexport function adjustMaxTokensForThinking(\n\t// Undefined means no explicit caller cap. Use the model cap and fit thinking inside it.\n\tbaseMaxTokens: number | undefined,\n\tmodelMaxTokens: number,\n\treasoningLevel: ThinkingLevel,\n\tcustomBudgets?: ThinkingBudgets,\n): { maxTokens: number; thinkingBudget: number } {\n\tconst defaultBudgets: ThinkingBudgets = {\n\t\tminimal: 1024,\n\t\tlow: 2048,\n\t\tmedium: 8192,\n\t\thigh: 16384,\n\t};\n\tconst budgets = { ...defaultBudgets, ...customBudgets };\n\n\tconst minOutputTokens = 1024;\n\tconst level = clampReasoning(reasoningLevel)!;\n\tlet thinkingBudget = budgets[level]!;\n\tconst maxTokens =\n\t\tbaseMaxTokens === undefined ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n\n\tif (maxTokens <= thinkingBudget) {\n\t\tthinkingBudget = Math.max(0, maxTokens - minOutputTokens);\n\t}\n\n\treturn { maxTokens, thinkingBudget };\n}\n"]}
1
+ {"version":3,"file":"simple-options.d.ts","sourceRoot":"","sources":["../../src/providers/simple-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,GAAG,EACH,OAAO,EACP,KAAK,EACL,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,aAAa,EACb,MAAM,aAAa,CAAC;AAKrB,oEAAoE;AACpE,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAGrC,kFAAkF;AAClF,qBAAa,sBAAuB,SAAQ,KAAK;IAChD,6EAA6E;IAC7E,YAAY,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAK7C;CACD;AAED,sFAAsF;AACtF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQtG;AAED,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,EAC7B,MAAM,CAAC,EAAE,MAAM,GACb,aAAa,CA6Bf;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC,aAAa,EAAE,OAAO,GAAG,KAAK,CAAC,GAAG,SAAS,CAErH;AAED,wBAAgB,0BAA0B,CAEzC,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,aAAa,EAC7B,aAAa,CAAC,EAAE,eAAe,GAC7B;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAoB/C","sourcesContent":["import type {\n\tApi,\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStreamOptions,\n\tThinkingBudgets,\n\tThinkingLevel,\n} from \"../types.js\";\nimport { estimateContextTokens } from \"../utils/estimate.js\";\n\nconst DEFAULT_MAX_OUTPUT_TOKENS = 32000;\nconst CONTEXT_WINDOW_OUTPUT_TOLERANCE = 1024;\n/** Headroom shared by request clamping and proactive compaction. */\nexport const CONTEXT_SAFETY_TOKENS = 4096;\n/** Minimum useful output allowance; deliberately smaller caller caps remain valid. */\nexport const MIN_OUTPUT_TOKENS = 256;\nconst MIN_MAX_TOKENS = 1;\n\n/** Refuses a request whose remaining context cannot support a useful response. */\nexport class OutputTokenBudgetError extends Error {\n\t/** Describe the available output and the minimum required before sending. */\n\tconstructor(available: number, minimum: number) {\n\t\tsuper(\n\t\t\t`Cannot send request: output budget ${available} tokens is below the required minimum ${minimum}. Compact the session or reduce the system prompt, tools, or input.`,\n\t\t);\n\t\tthis.name = \"OutputTokenBudgetError\";\n\t}\n}\n\n/** Purely calculate a context-safe output budget, or refuse an unusable allowance. */\nexport function clampMaxTokensToContext(model: Model<Api>, context: Context, maxTokens: number): number {\n\tif (model.maxTokens > 0) maxTokens = Math.min(maxTokens, model.maxTokens);\n\tif (model.contextWindow <= 0) return Math.max(MIN_MAX_TOKENS, maxTokens);\n\tconst available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;\n\tconst clamped = Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));\n\tconst minimum = Math.min(MIN_OUTPUT_TOKENS, maxTokens);\n\tif (clamped < minimum) throw new OutputTokenBudgetError(clamped, minimum);\n\treturn clamped;\n}\n\n/** Build common simple-provider options with a validated context-safe output allowance. */\nexport function buildBaseOptions(\n\tmodel: Model<Api>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n\tapiKey?: string,\n): StreamOptions {\n\tconst defaultMaxTokens =\n\t\tmodel.maxTokens > 0\n\t\t\t? model.maxTokens >= model.contextWindow - CONTEXT_WINDOW_OUTPUT_TOLERANCE\n\t\t\t\t? Math.min(model.maxTokens, DEFAULT_MAX_OUTPUT_TOKENS)\n\t\t\t\t: model.maxTokens\n\t\t\t: undefined;\n\n\tconst requestedMaxTokens = options?.maxTokens ?? defaultMaxTokens;\n\n\treturn {\n\t\ttemperature: options?.temperature,\n\t\tmaxTokens:\n\t\t\trequestedMaxTokens === undefined ? undefined : clampMaxTokensToContext(model, context, requestedMaxTokens),\n\t\tsignal: options?.signal,\n\t\tapiKey: apiKey || options?.apiKey,\n\t\ttransport: options?.transport,\n\t\tcacheRetention: options?.cacheRetention,\n\t\tsessionId: options?.sessionId,\n\t\theaders: options?.headers,\n\t\tonPayload: options?.onPayload,\n\t\tonResponse: options?.onResponse,\n\t\ttimeoutMs: options?.timeoutMs,\n\t\twebsocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,\n\t\tmaxRetries: options?.maxRetries,\n\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\tmetadata: options?.metadata,\n\t\tenv: options?.env,\n\t};\n}\n\nexport function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, \"xhigh\" | \"max\"> | undefined {\n\treturn effort === \"xhigh\" || effort === \"max\" ? \"high\" : effort;\n}\n\nexport function adjustMaxTokensForThinking(\n\t// Undefined means no explicit caller cap. Use the model cap and fit thinking inside it.\n\tbaseMaxTokens: number | undefined,\n\tmodelMaxTokens: number,\n\treasoningLevel: ThinkingLevel,\n\tcustomBudgets?: ThinkingBudgets,\n): { maxTokens: number; thinkingBudget: number } {\n\tconst defaultBudgets: ThinkingBudgets = {\n\t\tminimal: 1024,\n\t\tlow: 2048,\n\t\tmedium: 8192,\n\t\thigh: 16384,\n\t};\n\tconst budgets = { ...defaultBudgets, ...customBudgets };\n\n\tconst minOutputTokens = 1024;\n\tconst level = clampReasoning(reasoningLevel)!;\n\tlet thinkingBudget = budgets[level]!;\n\tconst maxTokens =\n\t\tbaseMaxTokens === undefined ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n\n\tif (maxTokens <= thinkingBudget) {\n\t\tthinkingBudget = Math.max(0, maxTokens - minOutputTokens);\n\t}\n\n\treturn { maxTokens, thinkingBudget };\n}\n"]}
@@ -16,6 +16,8 @@ export class OutputTokenBudgetError extends Error {
16
16
  }
17
17
  /** Purely calculate a context-safe output budget, or refuse an unusable allowance. */
18
18
  export function clampMaxTokensToContext(model, context, maxTokens) {
19
+ if (model.maxTokens > 0)
20
+ maxTokens = Math.min(maxTokens, model.maxTokens);
19
21
  if (model.contextWindow <= 0)
20
22
  return Math.max(MIN_MAX_TOKENS, maxTokens);
21
23
  const available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;
@@ -1 +1 @@
1
- {"version":3,"file":"simple-options.js","sourceRoot":"","sources":["../../src/providers/simple-options.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tApi,\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStreamOptions,\n\tThinkingBudgets,\n\tThinkingLevel,\n} from \"../types.js\";\nimport { estimateContextTokens } from \"../utils/estimate.js\";\n\nconst DEFAULT_MAX_OUTPUT_TOKENS = 32000;\nconst CONTEXT_WINDOW_OUTPUT_TOLERANCE = 1024;\n/** Headroom shared by request clamping and proactive compaction. */\nexport const CONTEXT_SAFETY_TOKENS = 4096;\n/** Minimum useful output allowance; deliberately smaller caller caps remain valid. */\nexport const MIN_OUTPUT_TOKENS = 256;\nconst MIN_MAX_TOKENS = 1;\n\n/** Refuses a request whose remaining context cannot support a useful response. */\nexport class OutputTokenBudgetError extends Error {\n\t/** Describe the available output and the minimum required before sending. */\n\tconstructor(available: number, minimum: number) {\n\t\tsuper(\n\t\t\t`Cannot send request: output budget ${available} tokens is below the required minimum ${minimum}. Compact the session or reduce the system prompt, tools, or input.`,\n\t\t);\n\t\tthis.name = \"OutputTokenBudgetError\";\n\t}\n}\n\n/** Purely calculate a context-safe output budget, or refuse an unusable allowance. */\nexport function clampMaxTokensToContext(model: Model<Api>, context: Context, maxTokens: number): number {\n\tif (model.contextWindow <= 0) return Math.max(MIN_MAX_TOKENS, maxTokens);\n\tconst available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;\n\tconst clamped = Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));\n\tconst minimum = Math.min(MIN_OUTPUT_TOKENS, maxTokens);\n\tif (clamped < minimum) throw new OutputTokenBudgetError(clamped, minimum);\n\treturn clamped;\n}\n\n/** Build common simple-provider options with a validated context-safe output allowance. */\nexport function buildBaseOptions(\n\tmodel: Model<Api>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n\tapiKey?: string,\n): StreamOptions {\n\tconst defaultMaxTokens =\n\t\tmodel.maxTokens > 0\n\t\t\t? model.maxTokens >= model.contextWindow - CONTEXT_WINDOW_OUTPUT_TOLERANCE\n\t\t\t\t? Math.min(model.maxTokens, DEFAULT_MAX_OUTPUT_TOKENS)\n\t\t\t\t: model.maxTokens\n\t\t\t: undefined;\n\n\tconst requestedMaxTokens = options?.maxTokens ?? defaultMaxTokens;\n\n\treturn {\n\t\ttemperature: options?.temperature,\n\t\tmaxTokens:\n\t\t\trequestedMaxTokens === undefined ? undefined : clampMaxTokensToContext(model, context, requestedMaxTokens),\n\t\tsignal: options?.signal,\n\t\tapiKey: apiKey || options?.apiKey,\n\t\ttransport: options?.transport,\n\t\tcacheRetention: options?.cacheRetention,\n\t\tsessionId: options?.sessionId,\n\t\theaders: options?.headers,\n\t\tonPayload: options?.onPayload,\n\t\tonResponse: options?.onResponse,\n\t\ttimeoutMs: options?.timeoutMs,\n\t\twebsocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,\n\t\tmaxRetries: options?.maxRetries,\n\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\tmetadata: options?.metadata,\n\t\tenv: options?.env,\n\t};\n}\n\nexport function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, \"xhigh\" | \"max\"> | undefined {\n\treturn effort === \"xhigh\" || effort === \"max\" ? \"high\" : effort;\n}\n\nexport function adjustMaxTokensForThinking(\n\t// Undefined means no explicit caller cap. Use the model cap and fit thinking inside it.\n\tbaseMaxTokens: number | undefined,\n\tmodelMaxTokens: number,\n\treasoningLevel: ThinkingLevel,\n\tcustomBudgets?: ThinkingBudgets,\n): { maxTokens: number; thinkingBudget: number } {\n\tconst defaultBudgets: ThinkingBudgets = {\n\t\tminimal: 1024,\n\t\tlow: 2048,\n\t\tmedium: 8192,\n\t\thigh: 16384,\n\t};\n\tconst budgets = { ...defaultBudgets, ...customBudgets };\n\n\tconst minOutputTokens = 1024;\n\tconst level = clampReasoning(reasoningLevel)!;\n\tlet thinkingBudget = budgets[level]!;\n\tconst maxTokens =\n\t\tbaseMaxTokens === undefined ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n\n\tif (maxTokens <= thinkingBudget) {\n\t\tthinkingBudget = Math.max(0, maxTokens - minOutputTokens);\n\t}\n\n\treturn { maxTokens, thinkingBudget };\n}\n"]}
1
+ {"version":3,"file":"simple-options.js","sourceRoot":"","sources":["../../src/providers/simple-options.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tApi,\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStreamOptions,\n\tThinkingBudgets,\n\tThinkingLevel,\n} from \"../types.js\";\nimport { estimateContextTokens } from \"../utils/estimate.js\";\n\nconst DEFAULT_MAX_OUTPUT_TOKENS = 32000;\nconst CONTEXT_WINDOW_OUTPUT_TOLERANCE = 1024;\n/** Headroom shared by request clamping and proactive compaction. */\nexport const CONTEXT_SAFETY_TOKENS = 4096;\n/** Minimum useful output allowance; deliberately smaller caller caps remain valid. */\nexport const MIN_OUTPUT_TOKENS = 256;\nconst MIN_MAX_TOKENS = 1;\n\n/** Refuses a request whose remaining context cannot support a useful response. */\nexport class OutputTokenBudgetError extends Error {\n\t/** Describe the available output and the minimum required before sending. */\n\tconstructor(available: number, minimum: number) {\n\t\tsuper(\n\t\t\t`Cannot send request: output budget ${available} tokens is below the required minimum ${minimum}. Compact the session or reduce the system prompt, tools, or input.`,\n\t\t);\n\t\tthis.name = \"OutputTokenBudgetError\";\n\t}\n}\n\n/** Purely calculate a context-safe output budget, or refuse an unusable allowance. */\nexport function clampMaxTokensToContext(model: Model<Api>, context: Context, maxTokens: number): number {\n\tif (model.maxTokens > 0) maxTokens = Math.min(maxTokens, model.maxTokens);\n\tif (model.contextWindow <= 0) return Math.max(MIN_MAX_TOKENS, maxTokens);\n\tconst available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;\n\tconst clamped = Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));\n\tconst minimum = Math.min(MIN_OUTPUT_TOKENS, maxTokens);\n\tif (clamped < minimum) throw new OutputTokenBudgetError(clamped, minimum);\n\treturn clamped;\n}\n\n/** Build common simple-provider options with a validated context-safe output allowance. */\nexport function buildBaseOptions(\n\tmodel: Model<Api>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n\tapiKey?: string,\n): StreamOptions {\n\tconst defaultMaxTokens =\n\t\tmodel.maxTokens > 0\n\t\t\t? model.maxTokens >= model.contextWindow - CONTEXT_WINDOW_OUTPUT_TOLERANCE\n\t\t\t\t? Math.min(model.maxTokens, DEFAULT_MAX_OUTPUT_TOKENS)\n\t\t\t\t: model.maxTokens\n\t\t\t: undefined;\n\n\tconst requestedMaxTokens = options?.maxTokens ?? defaultMaxTokens;\n\n\treturn {\n\t\ttemperature: options?.temperature,\n\t\tmaxTokens:\n\t\t\trequestedMaxTokens === undefined ? undefined : clampMaxTokensToContext(model, context, requestedMaxTokens),\n\t\tsignal: options?.signal,\n\t\tapiKey: apiKey || options?.apiKey,\n\t\ttransport: options?.transport,\n\t\tcacheRetention: options?.cacheRetention,\n\t\tsessionId: options?.sessionId,\n\t\theaders: options?.headers,\n\t\tonPayload: options?.onPayload,\n\t\tonResponse: options?.onResponse,\n\t\ttimeoutMs: options?.timeoutMs,\n\t\twebsocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,\n\t\tmaxRetries: options?.maxRetries,\n\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\tmetadata: options?.metadata,\n\t\tenv: options?.env,\n\t};\n}\n\nexport function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, \"xhigh\" | \"max\"> | undefined {\n\treturn effort === \"xhigh\" || effort === \"max\" ? \"high\" : effort;\n}\n\nexport function adjustMaxTokensForThinking(\n\t// Undefined means no explicit caller cap. Use the model cap and fit thinking inside it.\n\tbaseMaxTokens: number | undefined,\n\tmodelMaxTokens: number,\n\treasoningLevel: ThinkingLevel,\n\tcustomBudgets?: ThinkingBudgets,\n): { maxTokens: number; thinkingBudget: number } {\n\tconst defaultBudgets: ThinkingBudgets = {\n\t\tminimal: 1024,\n\t\tlow: 2048,\n\t\tmedium: 8192,\n\t\thigh: 16384,\n\t};\n\tconst budgets = { ...defaultBudgets, ...customBudgets };\n\n\tconst minOutputTokens = 1024;\n\tconst level = clampReasoning(reasoningLevel)!;\n\tlet thinkingBudget = budgets[level]!;\n\tconst maxTokens =\n\t\tbaseMaxTokens === undefined ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n\n\tif (maxTokens <= thinkingBudget) {\n\t\tthinkingBudget = Math.max(0, maxTokens - minOutputTokens);\n\t}\n\n\treturn { maxTokens, thinkingBudget };\n}\n"]}
@@ -16,6 +16,7 @@ import type { AssistantMessage } from "../types.js";
16
16
  * - Google Gemini: "input token count exceeds the maximum"
17
17
  * - xAI (Grok): "maximum prompt length is X but request contains Y"
18
18
  * - Groq: "reduce the length of the messages"
19
+ * - GitHub Copilot: HTTP 413 "failed to parse request" (request byte-size overflow)
19
20
  * - Cerebras: 400/413 status code (no body)
20
21
  * - Mistral: "Prompt contains X tokens ... too large for model with Y maximum context length"
21
22
  * - OpenRouter (all backends): "maximum context length is X tokens"
@@ -1 +1 @@
1
- {"version":3,"file":"overflow.d.ts","sourceRoot":"","sources":["../../src/utils/overflow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA4EpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAkC5F;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAEhG;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C","sourcesContent":["import type { AssistantMessage } from \"../types.js\";\n\n/**\n * Regex patterns to detect context overflow errors from different providers.\n *\n * These patterns match error messages returned when the input exceeds\n * the model's context window.\n *\n * Provider-specific patterns (with example error messages):\n *\n * - Anthropic: \"prompt is too long: 213462 tokens > 200000 maximum\"\n * - Anthropic: \"413 {\\\"error\\\":{\\\"type\\\":\\\"request_too_large\\\",\\\"message\\\":\\\"Request exceeds the maximum size\\\"}}\"\n * - OpenAI: \"Your input exceeds the context window of this model\"\n * - OpenAI/LiteLLM: \"Requested token count exceeds the model's maximum context length of 131072 tokens\"\n * - OpenAI-compatible: \"Input length (265330) exceeds model's maximum context length (262144).\"\n * - Google: \"The input token count (1196265) exceeds the maximum number of tokens allowed (1048575)\"\n * - xAI: \"This model's maximum prompt length is 131072 but the request contains 537812 tokens\"\n * - Groq: \"Please reduce the length of the messages or completion\"\n * - OpenRouter: \"This endpoint's maximum context length is X tokens. However, you requested about Y tokens\"\n * - llama.cpp: \"the request exceeds the available context size, try increasing it\"\n * - LM Studio: \"tokens to keep from the initial prompt is greater than the context length\"\n * - GitHub Copilot: \"prompt token count of X exceeds the limit of Y\"\n * - MiniMax: \"invalid params, context window exceeds limit\"\n * - Kimi For Coding: \"Your request exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n * - Cerebras: \"400/413 status code (no body)\"\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - z.ai: `{\"code\":\"1261\",\"message\":\"Prompt too long\"}`, `{\"code\":\"1261\",\"message\":\"Prompt exceeds max length\"}` (CN endpoint), or silent overflow via usage.input > contextWindow\n * - Xiaomi MiMo: Truncates input to fill contextWindow exactly, then returns finish_reason \"length\"\n * with output=0 (no room left to generate). Detected via stopReason \"length\" + zero output +\n * input filling the context window.\n * - Ollama: Some deployments truncate silently, others return errors like \"prompt too long; exceeded max context length by X tokens\"\n */\nconst OVERFLOW_PATTERNS = [\n\t/prompt (?:is )?too long/i, // Anthropic and z.ai token overflow\n\t/prompt exceeds max length/i, // z.ai CN endpoint token overflow\n\t/request_too_large/i, // Anthropic request byte-size overflow (HTTP 413)\n\t/input is too long for requested model/i, // Amazon Bedrock\n\t/exceeds the context window/i, // OpenAI (Completions & Responses API)\n\t/exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\\d,]+ tokens?|\\s*\\([\\d,]+\\))/i, // OpenAI-compatible proxies (LiteLLM)\n\t/input token count.*exceeds the maximum/i, // Google (Gemini)\n\t/maximum prompt length is \\d+/i, // xAI (Grok)\n\t/reduce the length of the messages/i, // Groq\n\t/maximum context length is \\d+ tokens/i, // OpenRouter (all backends)\n\t/exceeds (?:the )?maximum allowed input length of [\\d,]+ tokens?/i, // OpenRouter/Poolside\n\t/exceeds the limit of \\d+/i, // GitHub Copilot\n\t/exceeds the available context size/i, // llama.cpp server\n\t/greater than the context length/i, // LM Studio\n\t/context window exceeds limit/i, // MiniMax\n\t/exceeded model token limit/i, // Kimi For Coding\n\t/too large for model with \\d+ maximum context length/i, // Mistral\n\t/prompt has [\\d,]+ tokens?, but the configured context size is [\\d,]+ tokens?/i, // DS4 server\n\t/model_context_window_exceeded/i, // z.ai non-standard finish_reason surfaced as error text\n\t/prompt too long; exceeded (?:max )?context length/i, // Ollama explicit overflow error\n\t/context[_ ]length[_ ]exceeded/i, // Generic fallback\n\t/too many tokens/i, // Generic fallback\n\t/token limit exceeded/i, // Generic fallback\n];\n\nconst CEREBRAS_BODYLESS_OVERFLOW_PATTERN = /^4(?:00|13)\\s*(?:status code)?\\s*\\(no body\\)/i;\n\n/**\n * Patterns that indicate non-overflow errors (e.g. rate limiting, server errors).\n * Error messages matching any of these are excluded from overflow detection\n * even if they also match an OVERFLOW_PATTERN.\n *\n * Example: Bedrock formats throttling errors as \"ThrottlingException: Too many tokens,\n * please wait before trying again.\" which would match the /too many tokens/i overflow\n * pattern without this exclusion.\n */\nconst NON_OVERFLOW_PATTERNS = [\n\t/^(Throttling error|Service unavailable):/i, // AWS Bedrock non-overflow errors (human-readable prefixes from formatBedrockError)\n\t/rate limit/i, // Generic rate limiting\n\t/too many requests/i, // Generic HTTP 429 style\n];\n\n/**\n * Check if an assistant message represents a context overflow error.\n *\n * This handles two cases:\n * 1. Error-based overflow: Most providers return stopReason \"error\" with a\n * specific error message pattern.\n * 2. Silent overflow: Some providers accept overflow requests and return\n * successfully. For these, we check if usage.input exceeds the context window.\n *\n * ## Reliability by Provider\n *\n * **Reliable detection (returns error with detectable message):**\n * - Anthropic: \"prompt is too long: X tokens > Y maximum\" or \"request_too_large\"\n * - OpenAI (Completions & Responses): \"exceeds the context window\", \"exceeds the model's maximum context length of X tokens\", or \"exceeds model's maximum context length (X)\"\n * - Google Gemini: \"input token count exceeds the maximum\"\n * - xAI (Grok): \"maximum prompt length is X but request contains Y\"\n * - Groq: \"reduce the length of the messages\"\n * - Cerebras: 400/413 status code (no body)\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - OpenRouter (all backends): \"maximum context length is X tokens\"\n * - llama.cpp: \"exceeds the available context size\"\n * - LM Studio: \"greater than the context length\"\n * - Kimi For Coding: \"exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n * - z.ai: \"Prompt too long\"\n *\n * **Unreliable detection:**\n * - z.ai: Sometimes accepts overflow silently (detectable via usage.input > contextWindow),\n * sometimes returns rate limit errors. Pass contextWindow param to detect silent overflow.\n * - Xiaomi MiMo: Truncates input to fit contextWindow then returns stopReason \"length\" with\n * output=0. Pass contextWindow param to detect via the \"filled context + zero output\" signal.\n * - Ollama: May truncate input silently for some setups, but may also return explicit\n * overflow errors that match the patterns above. Silent truncation still cannot be\n * detected here because we do not know the expected token count.\n *\n * ## Custom Providers\n *\n * If you've added custom models via settings.json, this function may not detect\n * overflow errors from those providers. To add support:\n *\n * 1. Send a request that exceeds the model's context window\n * 2. Check the errorMessage in the response\n * 3. Create a regex pattern that matches the error\n * 4. The pattern should be added to OVERFLOW_PATTERNS in this file, or\n * check the errorMessage yourself before calling this function\n *\n * @param message - The assistant message to check\n * @param contextWindow - Optional context window size for detecting silent overflow (z.ai)\n * @returns true if the message indicates a context overflow\n */\nexport function isContextOverflow(message: AssistantMessage, contextWindow?: number): boolean {\n\t// Case 1: Check error message patterns\n\tif (message.stopReason === \"error\" && message.errorMessage) {\n\t\t// Skip messages matching known non-overflow patterns (e.g. throttling / rate-limit)\n\t\tconst isNonOverflow = NON_OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!));\n\t\tif (!isNonOverflow) {\n\t\t\tif (OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!))) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (message.provider === \"cerebras\" && CEREBRAS_BODYLESS_OVERFLOW_PATTERN.test(message.errorMessage)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Case 2: Silent overflow (z.ai style) - successful but usage exceeds context\n\tif (contextWindow && message.stopReason === \"stop\") {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens > contextWindow) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Case 3: Length-stop overflow (Xiaomi MiMo style) - server truncates oversized input\n\t// to fit the context window, leaving no room for output. Returns stopReason \"length\"\n\t// with output=0 and input+cacheRead filling the context window.\n\tif (contextWindow && message.stopReason === \"length\" && message.usage.output === 0) {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens >= contextWindow * 0.99) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Check whether a length stop ended below the caller or model's intended output limit.\n * Such responses may be caused by context pressure or provider-side truncation, so callers\n * can make one bounded compact-and-retry attempt. `desiredMaxOutput` must be the original\n * limit before any context-based clamping.\n */\nexport function isRecoverableLength(message: AssistantMessage, desiredMaxOutput: number): boolean {\n\treturn message.stopReason === \"length\" && desiredMaxOutput > 0 && message.usage.output < desiredMaxOutput;\n}\n\n/**\n * Get the overflow patterns for testing purposes.\n */\nexport function getOverflowPatterns(): RegExp[] {\n\treturn [...OVERFLOW_PATTERNS];\n}\n"]}
1
+ {"version":3,"file":"overflow.d.ts","sourceRoot":"","sources":["../../src/utils/overflow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAgGpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAqC5F;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAEhG;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C","sourcesContent":["import type { AssistantMessage } from \"../types.js\";\n\n/**\n * Regex patterns to detect context overflow errors from different providers.\n *\n * These patterns match error messages returned when the input exceeds\n * the model's context window or the provider's request byte-size limit.\n *\n * Provider-specific patterns (with example error messages):\n *\n * - Anthropic: \"prompt is too long: 213462 tokens > 200000 maximum\"\n * - Anthropic: \"413 {\\\"error\\\":{\\\"type\\\":\\\"request_too_large\\\",\\\"message\\\":\\\"Request exceeds the maximum size\\\"}}\"\n * - OpenAI: \"Your input exceeds the context window of this model\"\n * - OpenAI/LiteLLM: \"Requested token count exceeds the model's maximum context length of 131072 tokens\"\n * - OpenAI-compatible: \"Input length (265330) exceeds model's maximum context length (262144).\"\n * - Google: \"The input token count (1196265) exceeds the maximum number of tokens allowed (1048575)\"\n * - xAI: \"This model's maximum prompt length is 131072 but the request contains 537812 tokens\"\n * - Groq: \"Please reduce the length of the messages or completion\"\n * - OpenRouter: \"This endpoint's maximum context length is X tokens. However, you requested about Y tokens\"\n * - llama.cpp: \"the request exceeds the available context size, try increasing it\"\n * - LM Studio: \"tokens to keep from the initial prompt is greater than the context length\"\n * - GitHub Copilot: \"prompt token count of X exceeds the limit of Y\"\n * - GitHub Copilot: 'github-copilot API error (413): {\"message\":\"failed to parse request\",\"code\":\"\"}'\n * - MiniMax: \"invalid params, context window exceeds limit\"\n * - Kimi For Coding: \"Your request exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n * - Cerebras: \"400/413 status code (no body)\"\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - z.ai: `{\"code\":\"1261\",\"message\":\"Prompt too long\"}`, `{\"code\":\"1261\",\"message\":\"Prompt exceeds max length\"}` (CN endpoint), or silent overflow via usage.input > contextWindow\n * - Xiaomi MiMo: Truncates input to fill contextWindow exactly, then returns finish_reason \"length\"\n * with output=0 (no room left to generate). Detected via stopReason \"length\" + zero output +\n * input filling the context window.\n * - Ollama: Some deployments truncate silently, others return errors like \"prompt too long; exceeded max context length by X tokens\"\n */\nconst OVERFLOW_PATTERNS = [\n\t/prompt (?:is )?too long/i, // Anthropic and z.ai token overflow\n\t/prompt exceeds max length/i, // z.ai CN endpoint token overflow\n\t/request_too_large/i, // Anthropic request byte-size overflow (HTTP 413)\n\t/input is too long for requested model/i, // Amazon Bedrock\n\t/exceeds the context window/i, // OpenAI (Completions & Responses API)\n\t/exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\\d,]+ tokens?|\\s*\\([\\d,]+\\))/i, // OpenAI-compatible proxies (LiteLLM)\n\t/input token count.*exceeds the maximum/i, // Google (Gemini)\n\t/maximum prompt length is \\d+/i, // xAI (Grok)\n\t/reduce the length of the messages/i, // Groq\n\t/maximum context length is \\d+ tokens/i, // OpenRouter (all backends)\n\t/exceeds (?:the )?maximum allowed input length of [\\d,]+ tokens?/i, // OpenRouter/Poolside\n\t/exceeds the limit of \\d+/i, // GitHub Copilot\n\t/exceeds the available context size/i, // llama.cpp server\n\t/greater than the context length/i, // LM Studio\n\t/context window exceeds limit/i, // MiniMax\n\t/exceeded model token limit/i, // Kimi For Coding\n\t/too large for model with \\d+ maximum context length/i, // Mistral\n\t/prompt has [\\d,]+ tokens?, but the configured context size is [\\d,]+ tokens?/i, // DS4 server\n\t/model_context_window_exceeded/i, // z.ai non-standard finish_reason surfaced as error text\n\t/prompt too long; exceeded (?:max )?context length/i, // Ollama explicit overflow error\n\t/context[_ ]length[_ ]exceeded/i, // Generic fallback\n\t/too many tokens/i, // Generic fallback\n\t/token limit exceeded/i, // Generic fallback\n\t// HTTP 413 means request-size overflow regardless of provider or body text.\n\t// Bare SDK status; formatted provider headers are parsed separately below.\n\t/^413(?:\\s|:|$)/i,\n];\n\n/** Match the first single-line API-error header with linear work and unrestricted provider names. */\nfunction hasRequestSizeOverflowHeader(message: string): boolean {\n\tconst header = \" api error (\";\n\tfor (let index = 0; index < message.length; index++) {\n\t\tconst code = message.charCodeAt(index);\n\t\tif (code === 10 || code === 13) return false;\n\t\tif (code !== 32 || index === 0) continue;\n\t\t// The fixed-size comparison cannot backtrack over the provider prefix.\n\t\tif (message.slice(index, index + header.length).toLowerCase() === header) {\n\t\t\t// Stop at the first header so a different status's body cannot supply a 413 header.\n\t\t\treturn message.startsWith(\"413):\", index + header.length);\n\t\t}\n\t}\n\treturn false;\n}\n\nconst CEREBRAS_BODYLESS_OVERFLOW_PATTERN = /^4(?:00|13)\\s*(?:status code)?\\s*\\(no body\\)/i;\n\n/**\n * Patterns that indicate non-overflow errors (e.g. rate limiting, server errors).\n * Error messages matching any of these are excluded from overflow detection\n * even if they also match an OVERFLOW_PATTERN.\n *\n * Example: Bedrock formats throttling errors as \"ThrottlingException: Too many tokens,\n * please wait before trying again.\" which would match the /too many tokens/i overflow\n * pattern without this exclusion.\n */\nconst NON_OVERFLOW_PATTERNS = [\n\t/^(Throttling error|Service unavailable):/i, // AWS Bedrock non-overflow errors (human-readable prefixes from formatBedrockError)\n\t/rate limit/i, // Generic rate limiting\n\t/too many requests/i, // Generic HTTP 429 style\n];\n\n/**\n * Check if an assistant message represents a context overflow error.\n *\n * This handles two cases:\n * 1. Error-based overflow: Most providers return stopReason \"error\" with a\n * specific error message pattern.\n * 2. Silent overflow: Some providers accept overflow requests and return\n * successfully. For these, we check if usage.input exceeds the context window.\n *\n * ## Reliability by Provider\n *\n * **Reliable detection (returns error with detectable message):**\n * - Anthropic: \"prompt is too long: X tokens > Y maximum\" or \"request_too_large\"\n * - OpenAI (Completions & Responses): \"exceeds the context window\", \"exceeds the model's maximum context length of X tokens\", or \"exceeds model's maximum context length (X)\"\n * - Google Gemini: \"input token count exceeds the maximum\"\n * - xAI (Grok): \"maximum prompt length is X but request contains Y\"\n * - Groq: \"reduce the length of the messages\"\n * - GitHub Copilot: HTTP 413 \"failed to parse request\" (request byte-size overflow)\n * - Cerebras: 400/413 status code (no body)\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - OpenRouter (all backends): \"maximum context length is X tokens\"\n * - llama.cpp: \"exceeds the available context size\"\n * - LM Studio: \"greater than the context length\"\n * - Kimi For Coding: \"exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n * - z.ai: \"Prompt too long\"\n *\n * **Unreliable detection:**\n * - z.ai: Sometimes accepts overflow silently (detectable via usage.input > contextWindow),\n * sometimes returns rate limit errors. Pass contextWindow param to detect silent overflow.\n * - Xiaomi MiMo: Truncates input to fit contextWindow then returns stopReason \"length\" with\n * output=0. Pass contextWindow param to detect via the \"filled context + zero output\" signal.\n * - Ollama: May truncate input silently for some setups, but may also return explicit\n * overflow errors that match the patterns above. Silent truncation still cannot be\n * detected here because we do not know the expected token count.\n *\n * ## Custom Providers\n *\n * If you've added custom models via settings.json, this function may not detect\n * overflow errors from those providers. To add support:\n *\n * 1. Send a request that exceeds the model's context window\n * 2. Check the errorMessage in the response\n * 3. Create a regex pattern that matches the error\n * 4. The pattern should be added to OVERFLOW_PATTERNS in this file, or\n * check the errorMessage yourself before calling this function\n *\n * @param message - The assistant message to check\n * @param contextWindow - Optional context window size for detecting silent overflow (z.ai)\n * @returns true if the message indicates a context overflow\n */\nexport function isContextOverflow(message: AssistantMessage, contextWindow?: number): boolean {\n\t// Case 1: Check error message patterns\n\tif (message.stopReason === \"error\" && message.errorMessage) {\n\t\t// Skip messages matching known non-overflow patterns (e.g. throttling / rate-limit)\n\t\tconst isNonOverflow = NON_OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!));\n\t\tif (!isNonOverflow) {\n\t\t\tif (\n\t\t\t\thasRequestSizeOverflowHeader(message.errorMessage) ||\n\t\t\t\tOVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!))\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (message.provider === \"cerebras\" && CEREBRAS_BODYLESS_OVERFLOW_PATTERN.test(message.errorMessage)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Case 2: Silent overflow (z.ai style) - successful but usage exceeds context\n\tif (contextWindow && message.stopReason === \"stop\") {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens > contextWindow) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Case 3: Length-stop overflow (Xiaomi MiMo style) - server truncates oversized input\n\t// to fit the context window, leaving no room for output. Returns stopReason \"length\"\n\t// with output=0 and input+cacheRead filling the context window.\n\tif (contextWindow && message.stopReason === \"length\" && message.usage.output === 0) {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens >= contextWindow * 0.99) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Check whether a length stop ended below the caller or model's intended output limit.\n * Such responses may be caused by context pressure or provider-side truncation, so callers\n * can make one bounded compact-and-retry attempt. `desiredMaxOutput` must be the original\n * limit before any context-based clamping.\n */\nexport function isRecoverableLength(message: AssistantMessage, desiredMaxOutput: number): boolean {\n\treturn message.stopReason === \"length\" && desiredMaxOutput > 0 && message.usage.output < desiredMaxOutput;\n}\n\n/**\n * Get the overflow patterns for testing purposes.\n */\nexport function getOverflowPatterns(): RegExp[] {\n\treturn [...OVERFLOW_PATTERNS];\n}\n"]}
@@ -2,7 +2,7 @@
2
2
  * Regex patterns to detect context overflow errors from different providers.
3
3
  *
4
4
  * These patterns match error messages returned when the input exceeds
5
- * the model's context window.
5
+ * the model's context window or the provider's request byte-size limit.
6
6
  *
7
7
  * Provider-specific patterns (with example error messages):
8
8
  *
@@ -18,6 +18,7 @@
18
18
  * - llama.cpp: "the request exceeds the available context size, try increasing it"
19
19
  * - LM Studio: "tokens to keep from the initial prompt is greater than the context length"
20
20
  * - GitHub Copilot: "prompt token count of X exceeds the limit of Y"
21
+ * - GitHub Copilot: 'github-copilot API error (413): {"message":"failed to parse request","code":""}'
21
22
  * - MiniMax: "invalid params, context window exceeds limit"
22
23
  * - Kimi For Coding: "Your request exceeded model token limit: X (requested: Y)"
23
24
  * - DS4: "Prompt has X tokens, but the configured context size is Y tokens"
@@ -53,7 +54,27 @@ const OVERFLOW_PATTERNS = [
53
54
  /context[_ ]length[_ ]exceeded/i, // Generic fallback
54
55
  /too many tokens/i, // Generic fallback
55
56
  /token limit exceeded/i, // Generic fallback
57
+ // HTTP 413 means request-size overflow regardless of provider or body text.
58
+ // Bare SDK status; formatted provider headers are parsed separately below.
59
+ /^413(?:\s|:|$)/i,
56
60
  ];
61
+ /** Match the first single-line API-error header with linear work and unrestricted provider names. */
62
+ function hasRequestSizeOverflowHeader(message) {
63
+ const header = " api error (";
64
+ for (let index = 0; index < message.length; index++) {
65
+ const code = message.charCodeAt(index);
66
+ if (code === 10 || code === 13)
67
+ return false;
68
+ if (code !== 32 || index === 0)
69
+ continue;
70
+ // The fixed-size comparison cannot backtrack over the provider prefix.
71
+ if (message.slice(index, index + header.length).toLowerCase() === header) {
72
+ // Stop at the first header so a different status's body cannot supply a 413 header.
73
+ return message.startsWith("413):", index + header.length);
74
+ }
75
+ }
76
+ return false;
77
+ }
57
78
  const CEREBRAS_BODYLESS_OVERFLOW_PATTERN = /^4(?:00|13)\s*(?:status code)?\s*\(no body\)/i;
58
79
  /**
59
80
  * Patterns that indicate non-overflow errors (e.g. rate limiting, server errors).
@@ -86,6 +107,7 @@ const NON_OVERFLOW_PATTERNS = [
86
107
  * - Google Gemini: "input token count exceeds the maximum"
87
108
  * - xAI (Grok): "maximum prompt length is X but request contains Y"
88
109
  * - Groq: "reduce the length of the messages"
110
+ * - GitHub Copilot: HTTP 413 "failed to parse request" (request byte-size overflow)
89
111
  * - Cerebras: 400/413 status code (no body)
90
112
  * - Mistral: "Prompt contains X tokens ... too large for model with Y maximum context length"
91
113
  * - OpenRouter (all backends): "maximum context length is X tokens"
@@ -125,7 +147,8 @@ export function isContextOverflow(message, contextWindow) {
125
147
  // Skip messages matching known non-overflow patterns (e.g. throttling / rate-limit)
126
148
  const isNonOverflow = NON_OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage));
127
149
  if (!isNonOverflow) {
128
- if (OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage))) {
150
+ if (hasRequestSizeOverflowHeader(message.errorMessage) ||
151
+ OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage))) {
129
152
  return true;
130
153
  }
131
154
  if (message.provider === "cerebras" && CEREBRAS_BODYLESS_OVERFLOW_PATTERN.test(message.errorMessage)) {
@@ -1 +1 @@
1
- {"version":3,"file":"overflow.js","sourceRoot":"","sources":["../../src/utils/overflow.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"../types.js\";\n\n/**\n * Regex patterns to detect context overflow errors from different providers.\n *\n * These patterns match error messages returned when the input exceeds\n * the model's context window.\n *\n * Provider-specific patterns (with example error messages):\n *\n * - Anthropic: \"prompt is too long: 213462 tokens > 200000 maximum\"\n * - Anthropic: \"413 {\\\"error\\\":{\\\"type\\\":\\\"request_too_large\\\",\\\"message\\\":\\\"Request exceeds the maximum size\\\"}}\"\n * - OpenAI: \"Your input exceeds the context window of this model\"\n * - OpenAI/LiteLLM: \"Requested token count exceeds the model's maximum context length of 131072 tokens\"\n * - OpenAI-compatible: \"Input length (265330) exceeds model's maximum context length (262144).\"\n * - Google: \"The input token count (1196265) exceeds the maximum number of tokens allowed (1048575)\"\n * - xAI: \"This model's maximum prompt length is 131072 but the request contains 537812 tokens\"\n * - Groq: \"Please reduce the length of the messages or completion\"\n * - OpenRouter: \"This endpoint's maximum context length is X tokens. However, you requested about Y tokens\"\n * - llama.cpp: \"the request exceeds the available context size, try increasing it\"\n * - LM Studio: \"tokens to keep from the initial prompt is greater than the context length\"\n * - GitHub Copilot: \"prompt token count of X exceeds the limit of Y\"\n * - MiniMax: \"invalid params, context window exceeds limit\"\n * - Kimi For Coding: \"Your request exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n * - Cerebras: \"400/413 status code (no body)\"\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - z.ai: `{\"code\":\"1261\",\"message\":\"Prompt too long\"}`, `{\"code\":\"1261\",\"message\":\"Prompt exceeds max length\"}` (CN endpoint), or silent overflow via usage.input > contextWindow\n * - Xiaomi MiMo: Truncates input to fill contextWindow exactly, then returns finish_reason \"length\"\n * with output=0 (no room left to generate). Detected via stopReason \"length\" + zero output +\n * input filling the context window.\n * - Ollama: Some deployments truncate silently, others return errors like \"prompt too long; exceeded max context length by X tokens\"\n */\nconst OVERFLOW_PATTERNS = [\n\t/prompt (?:is )?too long/i, // Anthropic and z.ai token overflow\n\t/prompt exceeds max length/i, // z.ai CN endpoint token overflow\n\t/request_too_large/i, // Anthropic request byte-size overflow (HTTP 413)\n\t/input is too long for requested model/i, // Amazon Bedrock\n\t/exceeds the context window/i, // OpenAI (Completions & Responses API)\n\t/exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\\d,]+ tokens?|\\s*\\([\\d,]+\\))/i, // OpenAI-compatible proxies (LiteLLM)\n\t/input token count.*exceeds the maximum/i, // Google (Gemini)\n\t/maximum prompt length is \\d+/i, // xAI (Grok)\n\t/reduce the length of the messages/i, // Groq\n\t/maximum context length is \\d+ tokens/i, // OpenRouter (all backends)\n\t/exceeds (?:the )?maximum allowed input length of [\\d,]+ tokens?/i, // OpenRouter/Poolside\n\t/exceeds the limit of \\d+/i, // GitHub Copilot\n\t/exceeds the available context size/i, // llama.cpp server\n\t/greater than the context length/i, // LM Studio\n\t/context window exceeds limit/i, // MiniMax\n\t/exceeded model token limit/i, // Kimi For Coding\n\t/too large for model with \\d+ maximum context length/i, // Mistral\n\t/prompt has [\\d,]+ tokens?, but the configured context size is [\\d,]+ tokens?/i, // DS4 server\n\t/model_context_window_exceeded/i, // z.ai non-standard finish_reason surfaced as error text\n\t/prompt too long; exceeded (?:max )?context length/i, // Ollama explicit overflow error\n\t/context[_ ]length[_ ]exceeded/i, // Generic fallback\n\t/too many tokens/i, // Generic fallback\n\t/token limit exceeded/i, // Generic fallback\n];\n\nconst CEREBRAS_BODYLESS_OVERFLOW_PATTERN = /^4(?:00|13)\\s*(?:status code)?\\s*\\(no body\\)/i;\n\n/**\n * Patterns that indicate non-overflow errors (e.g. rate limiting, server errors).\n * Error messages matching any of these are excluded from overflow detection\n * even if they also match an OVERFLOW_PATTERN.\n *\n * Example: Bedrock formats throttling errors as \"ThrottlingException: Too many tokens,\n * please wait before trying again.\" which would match the /too many tokens/i overflow\n * pattern without this exclusion.\n */\nconst NON_OVERFLOW_PATTERNS = [\n\t/^(Throttling error|Service unavailable):/i, // AWS Bedrock non-overflow errors (human-readable prefixes from formatBedrockError)\n\t/rate limit/i, // Generic rate limiting\n\t/too many requests/i, // Generic HTTP 429 style\n];\n\n/**\n * Check if an assistant message represents a context overflow error.\n *\n * This handles two cases:\n * 1. Error-based overflow: Most providers return stopReason \"error\" with a\n * specific error message pattern.\n * 2. Silent overflow: Some providers accept overflow requests and return\n * successfully. For these, we check if usage.input exceeds the context window.\n *\n * ## Reliability by Provider\n *\n * **Reliable detection (returns error with detectable message):**\n * - Anthropic: \"prompt is too long: X tokens > Y maximum\" or \"request_too_large\"\n * - OpenAI (Completions & Responses): \"exceeds the context window\", \"exceeds the model's maximum context length of X tokens\", or \"exceeds model's maximum context length (X)\"\n * - Google Gemini: \"input token count exceeds the maximum\"\n * - xAI (Grok): \"maximum prompt length is X but request contains Y\"\n * - Groq: \"reduce the length of the messages\"\n * - Cerebras: 400/413 status code (no body)\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - OpenRouter (all backends): \"maximum context length is X tokens\"\n * - llama.cpp: \"exceeds the available context size\"\n * - LM Studio: \"greater than the context length\"\n * - Kimi For Coding: \"exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n * - z.ai: \"Prompt too long\"\n *\n * **Unreliable detection:**\n * - z.ai: Sometimes accepts overflow silently (detectable via usage.input > contextWindow),\n * sometimes returns rate limit errors. Pass contextWindow param to detect silent overflow.\n * - Xiaomi MiMo: Truncates input to fit contextWindow then returns stopReason \"length\" with\n * output=0. Pass contextWindow param to detect via the \"filled context + zero output\" signal.\n * - Ollama: May truncate input silently for some setups, but may also return explicit\n * overflow errors that match the patterns above. Silent truncation still cannot be\n * detected here because we do not know the expected token count.\n *\n * ## Custom Providers\n *\n * If you've added custom models via settings.json, this function may not detect\n * overflow errors from those providers. To add support:\n *\n * 1. Send a request that exceeds the model's context window\n * 2. Check the errorMessage in the response\n * 3. Create a regex pattern that matches the error\n * 4. The pattern should be added to OVERFLOW_PATTERNS in this file, or\n * check the errorMessage yourself before calling this function\n *\n * @param message - The assistant message to check\n * @param contextWindow - Optional context window size for detecting silent overflow (z.ai)\n * @returns true if the message indicates a context overflow\n */\nexport function isContextOverflow(message: AssistantMessage, contextWindow?: number): boolean {\n\t// Case 1: Check error message patterns\n\tif (message.stopReason === \"error\" && message.errorMessage) {\n\t\t// Skip messages matching known non-overflow patterns (e.g. throttling / rate-limit)\n\t\tconst isNonOverflow = NON_OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!));\n\t\tif (!isNonOverflow) {\n\t\t\tif (OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!))) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (message.provider === \"cerebras\" && CEREBRAS_BODYLESS_OVERFLOW_PATTERN.test(message.errorMessage)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Case 2: Silent overflow (z.ai style) - successful but usage exceeds context\n\tif (contextWindow && message.stopReason === \"stop\") {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens > contextWindow) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Case 3: Length-stop overflow (Xiaomi MiMo style) - server truncates oversized input\n\t// to fit the context window, leaving no room for output. Returns stopReason \"length\"\n\t// with output=0 and input+cacheRead filling the context window.\n\tif (contextWindow && message.stopReason === \"length\" && message.usage.output === 0) {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens >= contextWindow * 0.99) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Check whether a length stop ended below the caller or model's intended output limit.\n * Such responses may be caused by context pressure or provider-side truncation, so callers\n * can make one bounded compact-and-retry attempt. `desiredMaxOutput` must be the original\n * limit before any context-based clamping.\n */\nexport function isRecoverableLength(message: AssistantMessage, desiredMaxOutput: number): boolean {\n\treturn message.stopReason === \"length\" && desiredMaxOutput > 0 && message.usage.output < desiredMaxOutput;\n}\n\n/**\n * Get the overflow patterns for testing purposes.\n */\nexport function getOverflowPatterns(): RegExp[] {\n\treturn [...OVERFLOW_PATTERNS];\n}\n"]}
1
+ {"version":3,"file":"overflow.js","sourceRoot":"","sources":["../../src/utils/overflow.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"../types.js\";\n\n/**\n * Regex patterns to detect context overflow errors from different providers.\n *\n * These patterns match error messages returned when the input exceeds\n * the model's context window or the provider's request byte-size limit.\n *\n * Provider-specific patterns (with example error messages):\n *\n * - Anthropic: \"prompt is too long: 213462 tokens > 200000 maximum\"\n * - Anthropic: \"413 {\\\"error\\\":{\\\"type\\\":\\\"request_too_large\\\",\\\"message\\\":\\\"Request exceeds the maximum size\\\"}}\"\n * - OpenAI: \"Your input exceeds the context window of this model\"\n * - OpenAI/LiteLLM: \"Requested token count exceeds the model's maximum context length of 131072 tokens\"\n * - OpenAI-compatible: \"Input length (265330) exceeds model's maximum context length (262144).\"\n * - Google: \"The input token count (1196265) exceeds the maximum number of tokens allowed (1048575)\"\n * - xAI: \"This model's maximum prompt length is 131072 but the request contains 537812 tokens\"\n * - Groq: \"Please reduce the length of the messages or completion\"\n * - OpenRouter: \"This endpoint's maximum context length is X tokens. However, you requested about Y tokens\"\n * - llama.cpp: \"the request exceeds the available context size, try increasing it\"\n * - LM Studio: \"tokens to keep from the initial prompt is greater than the context length\"\n * - GitHub Copilot: \"prompt token count of X exceeds the limit of Y\"\n * - GitHub Copilot: 'github-copilot API error (413): {\"message\":\"failed to parse request\",\"code\":\"\"}'\n * - MiniMax: \"invalid params, context window exceeds limit\"\n * - Kimi For Coding: \"Your request exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n * - Cerebras: \"400/413 status code (no body)\"\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - z.ai: `{\"code\":\"1261\",\"message\":\"Prompt too long\"}`, `{\"code\":\"1261\",\"message\":\"Prompt exceeds max length\"}` (CN endpoint), or silent overflow via usage.input > contextWindow\n * - Xiaomi MiMo: Truncates input to fill contextWindow exactly, then returns finish_reason \"length\"\n * with output=0 (no room left to generate). Detected via stopReason \"length\" + zero output +\n * input filling the context window.\n * - Ollama: Some deployments truncate silently, others return errors like \"prompt too long; exceeded max context length by X tokens\"\n */\nconst OVERFLOW_PATTERNS = [\n\t/prompt (?:is )?too long/i, // Anthropic and z.ai token overflow\n\t/prompt exceeds max length/i, // z.ai CN endpoint token overflow\n\t/request_too_large/i, // Anthropic request byte-size overflow (HTTP 413)\n\t/input is too long for requested model/i, // Amazon Bedrock\n\t/exceeds the context window/i, // OpenAI (Completions & Responses API)\n\t/exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\\d,]+ tokens?|\\s*\\([\\d,]+\\))/i, // OpenAI-compatible proxies (LiteLLM)\n\t/input token count.*exceeds the maximum/i, // Google (Gemini)\n\t/maximum prompt length is \\d+/i, // xAI (Grok)\n\t/reduce the length of the messages/i, // Groq\n\t/maximum context length is \\d+ tokens/i, // OpenRouter (all backends)\n\t/exceeds (?:the )?maximum allowed input length of [\\d,]+ tokens?/i, // OpenRouter/Poolside\n\t/exceeds the limit of \\d+/i, // GitHub Copilot\n\t/exceeds the available context size/i, // llama.cpp server\n\t/greater than the context length/i, // LM Studio\n\t/context window exceeds limit/i, // MiniMax\n\t/exceeded model token limit/i, // Kimi For Coding\n\t/too large for model with \\d+ maximum context length/i, // Mistral\n\t/prompt has [\\d,]+ tokens?, but the configured context size is [\\d,]+ tokens?/i, // DS4 server\n\t/model_context_window_exceeded/i, // z.ai non-standard finish_reason surfaced as error text\n\t/prompt too long; exceeded (?:max )?context length/i, // Ollama explicit overflow error\n\t/context[_ ]length[_ ]exceeded/i, // Generic fallback\n\t/too many tokens/i, // Generic fallback\n\t/token limit exceeded/i, // Generic fallback\n\t// HTTP 413 means request-size overflow regardless of provider or body text.\n\t// Bare SDK status; formatted provider headers are parsed separately below.\n\t/^413(?:\\s|:|$)/i,\n];\n\n/** Match the first single-line API-error header with linear work and unrestricted provider names. */\nfunction hasRequestSizeOverflowHeader(message: string): boolean {\n\tconst header = \" api error (\";\n\tfor (let index = 0; index < message.length; index++) {\n\t\tconst code = message.charCodeAt(index);\n\t\tif (code === 10 || code === 13) return false;\n\t\tif (code !== 32 || index === 0) continue;\n\t\t// The fixed-size comparison cannot backtrack over the provider prefix.\n\t\tif (message.slice(index, index + header.length).toLowerCase() === header) {\n\t\t\t// Stop at the first header so a different status's body cannot supply a 413 header.\n\t\t\treturn message.startsWith(\"413):\", index + header.length);\n\t\t}\n\t}\n\treturn false;\n}\n\nconst CEREBRAS_BODYLESS_OVERFLOW_PATTERN = /^4(?:00|13)\\s*(?:status code)?\\s*\\(no body\\)/i;\n\n/**\n * Patterns that indicate non-overflow errors (e.g. rate limiting, server errors).\n * Error messages matching any of these are excluded from overflow detection\n * even if they also match an OVERFLOW_PATTERN.\n *\n * Example: Bedrock formats throttling errors as \"ThrottlingException: Too many tokens,\n * please wait before trying again.\" which would match the /too many tokens/i overflow\n * pattern without this exclusion.\n */\nconst NON_OVERFLOW_PATTERNS = [\n\t/^(Throttling error|Service unavailable):/i, // AWS Bedrock non-overflow errors (human-readable prefixes from formatBedrockError)\n\t/rate limit/i, // Generic rate limiting\n\t/too many requests/i, // Generic HTTP 429 style\n];\n\n/**\n * Check if an assistant message represents a context overflow error.\n *\n * This handles two cases:\n * 1. Error-based overflow: Most providers return stopReason \"error\" with a\n * specific error message pattern.\n * 2. Silent overflow: Some providers accept overflow requests and return\n * successfully. For these, we check if usage.input exceeds the context window.\n *\n * ## Reliability by Provider\n *\n * **Reliable detection (returns error with detectable message):**\n * - Anthropic: \"prompt is too long: X tokens > Y maximum\" or \"request_too_large\"\n * - OpenAI (Completions & Responses): \"exceeds the context window\", \"exceeds the model's maximum context length of X tokens\", or \"exceeds model's maximum context length (X)\"\n * - Google Gemini: \"input token count exceeds the maximum\"\n * - xAI (Grok): \"maximum prompt length is X but request contains Y\"\n * - Groq: \"reduce the length of the messages\"\n * - GitHub Copilot: HTTP 413 \"failed to parse request\" (request byte-size overflow)\n * - Cerebras: 400/413 status code (no body)\n * - Mistral: \"Prompt contains X tokens ... too large for model with Y maximum context length\"\n * - OpenRouter (all backends): \"maximum context length is X tokens\"\n * - llama.cpp: \"exceeds the available context size\"\n * - LM Studio: \"greater than the context length\"\n * - Kimi For Coding: \"exceeded model token limit: X (requested: Y)\"\n * - DS4: \"Prompt has X tokens, but the configured context size is Y tokens\"\n * - z.ai: \"Prompt too long\"\n *\n * **Unreliable detection:**\n * - z.ai: Sometimes accepts overflow silently (detectable via usage.input > contextWindow),\n * sometimes returns rate limit errors. Pass contextWindow param to detect silent overflow.\n * - Xiaomi MiMo: Truncates input to fit contextWindow then returns stopReason \"length\" with\n * output=0. Pass contextWindow param to detect via the \"filled context + zero output\" signal.\n * - Ollama: May truncate input silently for some setups, but may also return explicit\n * overflow errors that match the patterns above. Silent truncation still cannot be\n * detected here because we do not know the expected token count.\n *\n * ## Custom Providers\n *\n * If you've added custom models via settings.json, this function may not detect\n * overflow errors from those providers. To add support:\n *\n * 1. Send a request that exceeds the model's context window\n * 2. Check the errorMessage in the response\n * 3. Create a regex pattern that matches the error\n * 4. The pattern should be added to OVERFLOW_PATTERNS in this file, or\n * check the errorMessage yourself before calling this function\n *\n * @param message - The assistant message to check\n * @param contextWindow - Optional context window size for detecting silent overflow (z.ai)\n * @returns true if the message indicates a context overflow\n */\nexport function isContextOverflow(message: AssistantMessage, contextWindow?: number): boolean {\n\t// Case 1: Check error message patterns\n\tif (message.stopReason === \"error\" && message.errorMessage) {\n\t\t// Skip messages matching known non-overflow patterns (e.g. throttling / rate-limit)\n\t\tconst isNonOverflow = NON_OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!));\n\t\tif (!isNonOverflow) {\n\t\t\tif (\n\t\t\t\thasRequestSizeOverflowHeader(message.errorMessage) ||\n\t\t\t\tOVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!))\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (message.provider === \"cerebras\" && CEREBRAS_BODYLESS_OVERFLOW_PATTERN.test(message.errorMessage)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Case 2: Silent overflow (z.ai style) - successful but usage exceeds context\n\tif (contextWindow && message.stopReason === \"stop\") {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens > contextWindow) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Case 3: Length-stop overflow (Xiaomi MiMo style) - server truncates oversized input\n\t// to fit the context window, leaving no room for output. Returns stopReason \"length\"\n\t// with output=0 and input+cacheRead filling the context window.\n\tif (contextWindow && message.stopReason === \"length\" && message.usage.output === 0) {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens >= contextWindow * 0.99) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Check whether a length stop ended below the caller or model's intended output limit.\n * Such responses may be caused by context pressure or provider-side truncation, so callers\n * can make one bounded compact-and-retry attempt. `desiredMaxOutput` must be the original\n * limit before any context-based clamping.\n */\nexport function isRecoverableLength(message: AssistantMessage, desiredMaxOutput: number): boolean {\n\treturn message.stopReason === \"length\" && desiredMaxOutput > 0 && message.usage.output < desiredMaxOutput;\n}\n\n/**\n * Get the overflow patterns for testing purposes.\n */\nexport function getOverflowPatterns(): RegExp[] {\n\treturn [...OVERFLOW_PATTERNS];\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jecruz/merc-ai",
3
- "version": "0.1.6",
3
+ "version": "0.2.0",
4
4
  "description": "Unified LLM API with automatic model discovery and provider configuration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -84,7 +84,7 @@
84
84
  "partial-json": "^0.1.7",
85
85
  "proxy-agent": "^6.5.0",
86
86
  "proxy-from-env": "^1.1.0",
87
- "undici": "^7.19.1",
87
+ "undici": "^7.30.1",
88
88
  "uuid": "^14.0.0",
89
89
  "zod-to-json-schema": "^3.24.6"
90
90
  },
@@ -111,6 +111,6 @@
111
111
  "devDependencies": {
112
112
  "@types/node": "^24.3.0",
113
113
  "canvas": "^3.2.0",
114
- "vitest": "^4.1.11"
114
+ "vitest": "^4.1.12"
115
115
  }
116
116
  }