@caupulican/pi-ai 0.81.22 → 0.81.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/providers/openai-responses-shared.d.ts.map +1 -1
- package/dist/providers/openai-responses-shared.js +22 -13
- package/dist/providers/openai-responses-shared.js.map +1 -1
- package/dist/utils/validation.d.ts +1 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-responses-shared.d.ts","sourceRoot":"","sources":["../../src/providers/openai-responses-shared.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,IAAI,IAAI,UAAU,EAClB,6BAA6B,EAG7B,aAAa,EAQb,mBAAmB,EACnB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,KAAK,EACX,GAAG,EACH,gBAAgB,EAChB,OAAO,EAEP,KAAK,EAKL,IAAI,EAEJ,KAAK,EACL,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAoC5E,MAAM,WAAW,4BAA4B;IAC5C,WAAW,CAAC,EAAE,6BAA6B,CAAC,cAAc,CAAC,CAAC;IAC5D,kBAAkB,CAAC,EAAE,CACpB,mBAAmB,EAAE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,EAC9E,kBAAkB,EAAE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,KACzE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAC/D,uBAAuB,CAAC,EAAE,CACzB,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,KAClE,IAAI,CAAC;CACV;AAED,MAAM,WAAW,4BAA4B;IAC5C,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CACxB;AAgCD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE/E;AAED,wBAAgB,wBAAwB,CAAC,IAAI,SAAS,GAAG,EACxD,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,wBAAwB,EAAE,WAAW,CAAC,MAAM,CAAC,GAC3C,aAAa,CAkKf;AAMD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,EAAE,4BAA4B,GAAG,UAAU,EAAE,CASzG;AAMD,wBAAsB,sBAAsB,CAAC,IAAI,SAAS,GAAG,EAC5D,YAAY,EAAE,aAAa,CAAC,mBAAmB,CAAC,EAChD,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,2BAA2B,EACnC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,CAAC,EAAE,4BAA4B,GACpC,OAAO,CAAC,IAAI,CAAC,CA0Rf","sourcesContent":["import type OpenAI from \"openai\";\nimport type {\n\tTool as OpenAITool,\n\tResponseCreateParamsStreaming,\n\tResponseFunctionCallOutputItemList,\n\tResponseFunctionToolCall,\n\tResponseInput,\n\tResponseInputContent,\n\tResponseInputImage,\n\tResponseInputText,\n\tResponseOutputMessage,\n\tResponseOutputRefusal,\n\tResponseOutputText,\n\tResponseReasoningItem,\n\tResponseStreamEvent,\n} from \"openai/resources/responses/responses.js\";\nimport { calculateCost } from \"../models.ts\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tContext,\n\tImageContent,\n\tModel,\n\tStopReason,\n\tTextContent,\n\tTextSignatureV1,\n\tThinkingContent,\n\tTool,\n\tToolCall,\n\tUsage,\n} from \"../types.ts\";\nimport type { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { shortHash } from \"../utils/hash.ts\";\nimport { parseStreamingJson } from \"../utils/json-parse.ts\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.ts\";\nimport { transformMessages } from \"./transform-messages.ts\";\n\n// =============================================================================\n// Utilities\n// =============================================================================\n\nfunction encodeTextSignatureV1(id: string, phase?: TextSignatureV1[\"phase\"]): string {\n\tconst payload: TextSignatureV1 = { v: 1, id };\n\tif (phase) payload.phase = phase;\n\treturn JSON.stringify(payload);\n}\n\nfunction parseTextSignature(\n\tsignature: string | undefined,\n): { id: string; phase?: TextSignatureV1[\"phase\"] } | undefined {\n\tif (!signature) return undefined;\n\tif (signature.startsWith(\"{\")) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(signature) as Partial<TextSignatureV1>;\n\t\t\tif (parsed.v === 1 && typeof parsed.id === \"string\") {\n\t\t\t\tif (parsed.phase === \"commentary\" || parsed.phase === \"final_answer\") {\n\t\t\t\t\treturn { id: parsed.id, phase: parsed.phase };\n\t\t\t\t}\n\t\t\t\treturn { id: parsed.id };\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to legacy plain-string handling.\n\t\t}\n\t}\n\treturn { id: signature };\n}\n\nexport interface OpenAIResponsesStreamOptions {\n\tserviceTier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\tresolveServiceTier?: (\n\t\tresponseServiceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\t\trequestServiceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\t) => ResponseCreateParamsStreaming[\"service_tier\"] | undefined;\n\tapplyServiceTierPricing?: (\n\t\tusage: Usage,\n\t\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\t) => void;\n}\n\nexport interface ConvertResponsesToolsOptions {\n\tstrict?: boolean | null;\n}\n\ninterface InputTokenDetailsWithOrchestration {\n\tcached_tokens?: number;\n\torchestration_input_tokens?: number;\n\torchestration_input_cached_tokens?: number;\n}\n\ninterface OutputTokenDetailsWithOrchestration {\n\torchestration_output_tokens?: number;\n}\n\nfunction applyFuguUltraPricing<TApi extends Api>(model: Model<TApi>, usage: Usage): void {\n\tif (model.provider !== \"fugu\" || model.id !== \"fugu-ultra\") return;\n\n\t// Sakana pricing has a higher Fugu Ultra tier once context exceeds 272K tokens.\n\t// Source: https://console.sakana.ai/pricing\n\tconst highContext = usage.input + usage.cacheRead > 272_000;\n\tconst inputRate = highContext ? 10 : 5;\n\tconst outputRate = highContext ? 45 : 30;\n\tconst cacheReadRate = highContext ? 1 : 0.5;\n\tusage.cost.input = (inputRate / 1_000_000) * usage.input;\n\tusage.cost.output = (outputRate / 1_000_000) * usage.output;\n\tusage.cost.cacheRead = (cacheReadRate / 1_000_000) * usage.cacheRead;\n\tusage.cost.cacheWrite = 0;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead;\n}\n\n// =============================================================================\n// Message conversion\n// =============================================================================\n\nexport function buildResponsesInstructions(context: Context): string | undefined {\n\treturn context.systemPrompt ? sanitizeSurrogates(context.systemPrompt) : undefined;\n}\n\nexport function convertResponsesMessages<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\tallowedToolCallProviders: ReadonlySet<string>,\n): ResponseInput {\n\tconst messages: ResponseInput = [];\n\n\tconst normalizeIdPart = (part: string): string => {\n\t\tconst sanitized = part.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n\t\tconst normalized = sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;\n\t\treturn normalized.replace(/_+$/, \"\");\n\t};\n\n\tconst buildForeignResponsesItemId = (itemId: string): string => {\n\t\tconst normalized = `fc_${shortHash(itemId)}`;\n\t\treturn normalized.length > 64 ? normalized.slice(0, 64) : normalized;\n\t};\n\n\tconst normalizeToolCallId = (id: string, _targetModel: Model<TApi>, source: AssistantMessage): string => {\n\t\tif (!allowedToolCallProviders.has(model.provider)) return normalizeIdPart(id);\n\t\tif (!id.includes(\"|\")) return normalizeIdPart(id);\n\t\tconst [callId, itemId] = id.split(\"|\");\n\t\tconst normalizedCallId = normalizeIdPart(callId);\n\t\tconst isForeignToolCall = source.provider !== model.provider || source.api !== model.api;\n\t\tlet normalizedItemId = isForeignToolCall ? buildForeignResponsesItemId(itemId) : normalizeIdPart(itemId);\n\t\t// OpenAI Responses API requires item id to start with \"fc\"\n\t\tif (!normalizedItemId.startsWith(\"fc_\")) {\n\t\t\tnormalizedItemId = normalizeIdPart(`fc_${normalizedItemId}`);\n\t\t}\n\t\treturn `${normalizedCallId}|${normalizedItemId}`;\n\t};\n\n\tconst transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);\n\n\tlet msgIndex = 0;\n\tfor (const msg of transformedMessages) {\n\t\tif (msg.role === \"user\") {\n\t\t\tif (typeof msg.content === \"string\") {\n\t\t\t\tmessages.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: [{ type: \"input_text\", text: sanitizeSurrogates(msg.content) }],\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst content: ResponseInputContent[] = msg.content.map((item): ResponseInputContent => {\n\t\t\t\t\tif (item.type === \"text\") {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttype: \"input_text\",\n\t\t\t\t\t\t\ttext: sanitizeSurrogates(item.text),\n\t\t\t\t\t\t} satisfies ResponseInputText;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: \"input_image\",\n\t\t\t\t\t\tdetail: \"auto\",\n\t\t\t\t\t\timage_url: `data:${item.mimeType};base64,${item.data}`,\n\t\t\t\t\t} satisfies ResponseInputImage;\n\t\t\t\t});\n\t\t\t\tif (content.length === 0) continue;\n\t\t\t\tmessages.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\tconst output: ResponseInput = [];\n\t\t\tconst assistantMsg = msg as AssistantMessage;\n\t\t\tconst isDifferentModel =\n\t\t\t\tassistantMsg.model !== model.id &&\n\t\t\t\tassistantMsg.provider === model.provider &&\n\t\t\t\tassistantMsg.api === model.api;\n\t\t\tlet textBlockIndex = 0;\n\n\t\t\tfor (const block of msg.content) {\n\t\t\t\tif (block.type === \"thinking\") {\n\t\t\t\t\tif (block.thinkingSignature) {\n\t\t\t\t\t\tconst reasoningItem = JSON.parse(block.thinkingSignature) as ResponseReasoningItem;\n\t\t\t\t\t\toutput.push(reasoningItem);\n\t\t\t\t\t}\n\t\t\t\t} else if (block.type === \"text\") {\n\t\t\t\t\tconst textBlock = block as TextContent;\n\t\t\t\t\tconst parsedSignature = parseTextSignature(textBlock.textSignature);\n\t\t\t\t\tconst fallbackMessageId =\n\t\t\t\t\t\ttextBlockIndex === 0 ? `msg_pi_${msgIndex}` : `msg_pi_${msgIndex}_${textBlockIndex}`;\n\t\t\t\t\ttextBlockIndex++;\n\t\t\t\t\t// OpenAI requires id to be max 64 characters\n\t\t\t\t\tlet msgId = parsedSignature?.id;\n\t\t\t\t\tif (!msgId) {\n\t\t\t\t\t\tmsgId = fallbackMessageId;\n\t\t\t\t\t} else if (msgId.length > 64) {\n\t\t\t\t\t\tmsgId = `msg_${shortHash(msgId)}`;\n\t\t\t\t\t}\n\t\t\t\t\toutput.push({\n\t\t\t\t\t\ttype: \"message\",\n\t\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\t\tcontent: [{ type: \"output_text\", text: sanitizeSurrogates(textBlock.text), annotations: [] }],\n\t\t\t\t\t\tstatus: \"completed\",\n\t\t\t\t\t\tid: msgId,\n\t\t\t\t\t\tphase: parsedSignature?.phase,\n\t\t\t\t\t} satisfies ResponseOutputMessage);\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\tconst toolCall = block as ToolCall;\n\t\t\t\t\tconst [callId, itemIdRaw] = toolCall.id.split(\"|\");\n\t\t\t\t\tlet itemId: string | undefined = itemIdRaw;\n\n\t\t\t\t\t// For different-model messages, set id to undefined to avoid pairing validation.\n\t\t\t\t\t// OpenAI tracks which fc_xxx IDs were paired with rs_xxx reasoning items.\n\t\t\t\t\t// By omitting the id, we avoid triggering that validation (like cross-provider does).\n\t\t\t\t\tif (isDifferentModel && itemId?.startsWith(\"fc_\")) {\n\t\t\t\t\t\titemId = undefined;\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.push({\n\t\t\t\t\t\ttype: \"function_call\",\n\t\t\t\t\t\tid: itemId,\n\t\t\t\t\t\tcall_id: callId,\n\t\t\t\t\t\tname: toolCall.name,\n\t\t\t\t\t\targuments: JSON.stringify(toolCall.arguments),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (output.length === 0) continue;\n\t\t\tmessages.push(...output);\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\tconst textResult = msg.content\n\t\t\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\\n\");\n\t\t\tconst hasImages = msg.content.some((c): c is ImageContent => c.type === \"image\");\n\t\t\tconst hasText = textResult.length > 0;\n\t\t\tconst [callId] = msg.toolCallId.split(\"|\");\n\n\t\t\tlet output: string | ResponseFunctionCallOutputItemList;\n\t\t\tif (hasImages && model.input.includes(\"image\")) {\n\t\t\t\tconst contentParts: ResponseFunctionCallOutputItemList = [];\n\n\t\t\t\tif (hasText) {\n\t\t\t\t\tcontentParts.push({\n\t\t\t\t\t\ttype: \"input_text\",\n\t\t\t\t\t\ttext: sanitizeSurrogates(textResult),\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tfor (const block of msg.content) {\n\t\t\t\t\tif (block.type === \"image\") {\n\t\t\t\t\t\tcontentParts.push({\n\t\t\t\t\t\t\ttype: \"input_image\",\n\t\t\t\t\t\t\tdetail: \"auto\",\n\t\t\t\t\t\t\timage_url: `data:${block.mimeType};base64,${block.data}`,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\toutput = contentParts;\n\t\t\t} else {\n\t\t\t\toutput = sanitizeSurrogates(hasText ? textResult : \"(see attached image)\");\n\t\t\t}\n\n\t\t\tmessages.push({\n\t\t\t\ttype: \"function_call_output\",\n\t\t\t\tcall_id: callId,\n\t\t\t\toutput,\n\t\t\t});\n\t\t}\n\t\tmsgIndex++;\n\t}\n\n\treturn messages;\n}\n\n// =============================================================================\n// Tool conversion\n// =============================================================================\n\nexport function convertResponsesTools(tools: Tool[], options?: ConvertResponsesToolsOptions): OpenAITool[] {\n\tconst strict = options?.strict === undefined ? false : options.strict;\n\treturn tools.map((tool) => ({\n\t\ttype: \"function\",\n\t\tname: tool.name,\n\t\tdescription: tool.description,\n\t\tparameters: tool.parameters as any, // TypeBox already generates JSON Schema\n\t\tstrict,\n\t}));\n}\n\n// =============================================================================\n// Stream processing\n// =============================================================================\n\nexport async function processResponsesStream<TApi extends Api>(\n\topenaiStream: AsyncIterable<ResponseStreamEvent>,\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n\tmodel: Model<TApi>,\n\toptions?: OpenAIResponsesStreamOptions,\n): Promise<void> {\n\tlet currentItem: ResponseReasoningItem | ResponseOutputMessage | ResponseFunctionToolCall | null = null;\n\tlet currentBlock: ThinkingContent | TextContent | (ToolCall & { partialJson: string }) | null = null;\n\tlet sawTerminalResponseEvent = false;\n\tconst blocks = output.content;\n\tconst blockIndex = () => blocks.length - 1;\n\tconst ensureMessageOutputTextPart = (): ResponseOutputText | undefined => {\n\t\tif (currentItem?.type !== \"message\") return undefined;\n\t\tconst lastPart = currentItem.content[currentItem.content.length - 1];\n\t\tif (lastPart?.type === \"output_text\") return lastPart;\n\t\tconst part: ResponseOutputText = { type: \"output_text\", text: \"\", annotations: [] };\n\t\tcurrentItem.content.push(part);\n\t\treturn part;\n\t};\n\tconst ensureMessageRefusalPart = (): ResponseOutputRefusal | undefined => {\n\t\tif (currentItem?.type !== \"message\") return undefined;\n\t\tconst lastPart = currentItem.content[currentItem.content.length - 1];\n\t\tif (lastPart?.type === \"refusal\") return lastPart;\n\t\tconst part: ResponseOutputRefusal = { type: \"refusal\", refusal: \"\" };\n\t\tcurrentItem.content.push(part);\n\t\treturn part;\n\t};\n\tconst finalizeResponse = (\n\t\tresponse: Extract<ResponseStreamEvent, { type: \"response.completed\" | \"response.incomplete\" }>[\"response\"],\n\t): void => {\n\t\tsawTerminalResponseEvent = true;\n\t\tif (response?.id) {\n\t\t\toutput.responseId = response.id;\n\t\t}\n\t\tif (response?.usage) {\n\t\t\tconst inputDetails = response.usage.input_tokens_details as InputTokenDetailsWithOrchestration | undefined;\n\t\t\tconst outputDetails = response.usage.output_tokens_details as OutputTokenDetailsWithOrchestration | undefined;\n\t\t\tconst cachedTokens = inputDetails?.cached_tokens || 0;\n\t\t\tlet inputTokens = (response.usage.input_tokens || 0) - cachedTokens;\n\t\t\tlet outputTokens = response.usage.output_tokens || 0;\n\t\t\tlet cacheReadTokens = cachedTokens;\n\t\t\tlet totalTokens = response.usage.total_tokens || 0;\n\t\t\tif (model.provider === \"fugu\") {\n\t\t\t\tconst orchestrationInputTokens = inputDetails?.orchestration_input_tokens || 0;\n\t\t\t\tconst orchestrationInputCachedTokens = inputDetails?.orchestration_input_cached_tokens || 0;\n\t\t\t\tconst orchestrationOutputTokens = outputDetails?.orchestration_output_tokens || 0;\n\t\t\t\tinputTokens += orchestrationInputTokens;\n\t\t\t\tcacheReadTokens += orchestrationInputCachedTokens;\n\t\t\t\toutputTokens += orchestrationOutputTokens;\n\t\t\t\ttotalTokens += orchestrationInputTokens + orchestrationInputCachedTokens + orchestrationOutputTokens;\n\t\t\t}\n\t\t\toutput.usage = {\n\t\t\t\t// OpenAI includes cached tokens in input_tokens, so subtract to get non-cached input.\n\t\t\t\t// Sakana Fugu Ultra also reports billable orchestration tokens in token details fields.\n\t\t\t\t// Source: https://console.sakana.ai/pricing#usage-field-details\n\t\t\t\tinput: inputTokens,\n\t\t\t\toutput: outputTokens,\n\t\t\t\tcacheRead: cacheReadTokens,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: (response.usage as any).cost || 0 },\n\t\t\t};\n\t\t}\n\t\tcalculateCost(model, output.usage, {\n\t\t\t// response.usage is absent on some streams; this call sits outside the guard above.\n\t\t\tproviderSuppliedTotal: Boolean((response.usage as { cost?: number } | undefined)?.cost),\n\t\t});\n\t\tapplyFuguUltraPricing(model, output.usage);\n\t\tif (options?.applyServiceTierPricing) {\n\t\t\tconst serviceTier = options.resolveServiceTier\n\t\t\t\t? options.resolveServiceTier(response?.service_tier, options.serviceTier)\n\t\t\t\t: (response?.service_tier ?? options.serviceTier);\n\t\t\toptions.applyServiceTierPricing(output.usage, serviceTier);\n\t\t}\n\t\t// Map status to stop reason\n\t\toutput.stopReason = mapStopReason(response?.status);\n\t\tif (output.content.some((b) => b.type === \"toolCall\") && output.stopReason === \"stop\") {\n\t\t\toutput.stopReason = \"toolUse\";\n\t\t}\n\t};\n\n\tfor await (const event of openaiStream) {\n\t\tif (event.type === \"response.created\") {\n\t\t\toutput.responseId = event.response.id;\n\t\t} else if (event.type === \"response.output_item.added\") {\n\t\t\tconst item = event.item;\n\t\t\tif (item.type === \"reasoning\") {\n\t\t\t\tcurrentItem = item;\n\t\t\t\tcurrentBlock = { type: \"thinking\", thinking: \"\" };\n\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\tstream.push({ type: \"thinking_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t} else if (item.type === \"message\") {\n\t\t\t\tcurrentItem = item;\n\t\t\t\tcurrentBlock = { type: \"text\", text: \"\" };\n\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\tstream.push({ type: \"text_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t} else if (item.type === \"function_call\") {\n\t\t\t\tcurrentItem = item;\n\t\t\t\tcurrentBlock = {\n\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\tid: `${item.call_id}|${item.id}`,\n\t\t\t\t\tname: item.name,\n\t\t\t\t\targuments: {},\n\t\t\t\t\tpartialJson: item.arguments || \"\",\n\t\t\t\t};\n\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\tstream.push({ type: \"toolcall_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t}\n\t\t} else if (event.type === \"response.reasoning_summary_part.added\") {\n\t\t\tif (currentItem && currentItem.type === \"reasoning\") {\n\t\t\t\tcurrentItem.summary = currentItem.summary || [];\n\t\t\t\tcurrentItem.summary.push(event.part);\n\t\t\t}\n\t\t} else if (event.type === \"response.reasoning_summary_text.delta\") {\n\t\t\tif (currentItem?.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tcurrentItem.summary = currentItem.summary || [];\n\t\t\t\tconst lastPart = currentItem.summary[currentItem.summary.length - 1];\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tcurrentBlock.thinking += event.delta;\n\t\t\t\t\tlastPart.text += event.delta;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta: event.delta,\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} else if (event.type === \"response.reasoning_summary_part.done\") {\n\t\t\tif (currentItem?.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tcurrentItem.summary = currentItem.summary || [];\n\t\t\t\tconst lastPart = currentItem.summary[currentItem.summary.length - 1];\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tcurrentBlock.thinking += \"\\n\\n\";\n\t\t\t\t\tlastPart.text += \"\\n\\n\";\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta: \"\\n\\n\",\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} else if (event.type === \"response.reasoning_text.delta\") {\n\t\t\tif (currentItem?.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tcurrentBlock.thinking += event.delta;\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tdelta: event.delta,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (event.type === \"response.content_part.added\") {\n\t\t\tif (currentItem?.type === \"message\") {\n\t\t\t\tcurrentItem.content = currentItem.content || [];\n\t\t\t\t// Filter out ReasoningText, only accept output_text and refusal\n\t\t\t\tif (event.part.type === \"output_text\" || event.part.type === \"refusal\") {\n\t\t\t\t\tcurrentItem.content.push(event.part);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (event.type === \"response.output_text.delta\") {\n\t\t\tif (currentItem?.type === \"message\" && currentBlock?.type === \"text\") {\n\t\t\t\tconst lastPart = ensureMessageOutputTextPart();\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tcurrentBlock.text += event.delta;\n\t\t\t\t\tlastPart.text += event.delta;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta: event.delta,\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} else if (event.type === \"response.refusal.delta\") {\n\t\t\tif (currentItem?.type === \"message\" && currentBlock?.type === \"text\") {\n\t\t\t\tconst lastPart = ensureMessageRefusalPart();\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tcurrentBlock.text += event.delta;\n\t\t\t\t\tlastPart.refusal += event.delta;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta: event.delta,\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} else if (event.type === \"response.function_call_arguments.delta\") {\n\t\t\tif (currentItem?.type === \"function_call\" && currentBlock?.type === \"toolCall\") {\n\t\t\t\tcurrentBlock.partialJson += event.delta;\n\t\t\t\tcurrentBlock.arguments = parseStreamingJson(currentBlock.partialJson);\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tdelta: event.delta,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (event.type === \"response.function_call_arguments.done\") {\n\t\t\tif (currentItem?.type === \"function_call\" && currentBlock?.type === \"toolCall\") {\n\t\t\t\tconst previousPartialJson = currentBlock.partialJson;\n\t\t\t\tcurrentBlock.partialJson = event.arguments;\n\t\t\t\tcurrentBlock.arguments = parseStreamingJson(currentBlock.partialJson);\n\n\t\t\t\tif (event.arguments.startsWith(previousPartialJson)) {\n\t\t\t\t\tconst delta = event.arguments.slice(previousPartialJson.length);\n\t\t\t\t\tif (delta.length > 0) {\n\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\tdelta,\n\t\t\t\t\t\t\tpartial: output,\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} else if (event.type === \"response.output_item.done\") {\n\t\t\tconst item = event.item;\n\n\t\t\tif (item.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tconst summaryText = item.summary?.map((s) => s.text).join(\"\\n\\n\") || \"\";\n\t\t\t\tconst contentText = item.content?.map((c) => c.text).join(\"\\n\\n\") || \"\";\n\t\t\t\tcurrentBlock.thinking = summaryText || contentText || currentBlock.thinking;\n\t\t\t\tcurrentBlock.thinkingSignature = JSON.stringify(item);\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tcontent: currentBlock.thinking,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t\tcurrentBlock = null;\n\t\t\t} else if (item.type === \"message\" && currentBlock?.type === \"text\") {\n\t\t\t\tcurrentBlock.text = item.content.map((c) => (c.type === \"output_text\" ? c.text : c.refusal)).join(\"\");\n\t\t\t\tcurrentBlock.textSignature = encodeTextSignatureV1(item.id, item.phase ?? undefined);\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tcontent: currentBlock.text,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t\tcurrentBlock = null;\n\t\t\t} else if (item.type === \"function_call\") {\n\t\t\t\tconst args =\n\t\t\t\t\tcurrentBlock?.type === \"toolCall\" && currentBlock.partialJson\n\t\t\t\t\t\t? parseStreamingJson(currentBlock.partialJson)\n\t\t\t\t\t\t: parseStreamingJson(item.arguments || \"{}\");\n\n\t\t\t\tlet toolCall: ToolCall;\n\t\t\t\tif (currentBlock?.type === \"toolCall\") {\n\t\t\t\t\t// Finalize in-place and strip the scratch buffer so replay only\n\t\t\t\t\t// carries parsed arguments.\n\t\t\t\t\tcurrentBlock.arguments = args;\n\t\t\t\t\tdelete (currentBlock as { partialJson?: string }).partialJson;\n\t\t\t\t\ttoolCall = currentBlock;\n\t\t\t\t} else {\n\t\t\t\t\ttoolCall = {\n\t\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\t\tid: `${item.call_id}|${item.id}`,\n\t\t\t\t\t\tname: item.name,\n\t\t\t\t\t\targuments: args,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tcurrentBlock = null;\n\t\t\t\tstream.push({ type: \"toolcall_end\", contentIndex: blockIndex(), toolCall, partial: output });\n\t\t\t}\n\t\t} else if (event.type === \"response.completed\" || event.type === \"response.incomplete\") {\n\t\t\tfinalizeResponse(event.response);\n\t\t} else if (event.type === \"error\") {\n\t\t\tthrow new Error(`Error Code ${event.code}: ${event.message}` || \"Unknown error\");\n\t\t} else if (event.type === \"response.failed\") {\n\t\t\tsawTerminalResponseEvent = true;\n\t\t\tconst error = event.response?.error;\n\t\t\tconst details = event.response?.incomplete_details;\n\t\t\tconst msg = error\n\t\t\t\t? `${error.code || \"unknown\"}: ${error.message || \"no message\"}`\n\t\t\t\t: details?.reason\n\t\t\t\t\t? `incomplete: ${details.reason}`\n\t\t\t\t\t: \"Unknown error (no error details in response)\";\n\t\t\tthrow new Error(msg);\n\t\t}\n\t}\n\tif (!sawTerminalResponseEvent) {\n\t\tthrow new Error(\"OpenAI Responses stream ended before a terminal response event\");\n\t}\n}\n\nfunction mapStopReason(status: OpenAI.Responses.ResponseStatus | undefined): StopReason {\n\tif (!status) return \"stop\";\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn \"stop\";\n\t\tcase \"incomplete\":\n\t\t\treturn \"length\";\n\t\tcase \"failed\":\n\t\tcase \"cancelled\":\n\t\t\treturn \"error\";\n\t\t// These two are wonky ...\n\t\tcase \"in_progress\":\n\t\tcase \"queued\":\n\t\t\treturn \"stop\";\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = status;\n\t\t\tthrow new Error(`Unhandled stop reason: ${_exhaustive}`);\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"openai-responses-shared.d.ts","sourceRoot":"","sources":["../../src/providers/openai-responses-shared.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,IAAI,IAAI,UAAU,EAClB,6BAA6B,EAG7B,aAAa,EAQb,mBAAmB,EACnB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,KAAK,EACX,GAAG,EACH,gBAAgB,EAChB,OAAO,EAEP,KAAK,EAKL,IAAI,EAEJ,KAAK,EACL,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAoC5E,MAAM,WAAW,4BAA4B;IAC5C,WAAW,CAAC,EAAE,6BAA6B,CAAC,cAAc,CAAC,CAAC;IAC5D,kBAAkB,CAAC,EAAE,CACpB,mBAAmB,EAAE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,EAC9E,kBAAkB,EAAE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,KACzE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAC/D,uBAAuB,CAAC,EAAE,CACzB,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,6BAA6B,CAAC,cAAc,CAAC,GAAG,SAAS,KAClE,IAAI,CAAC;CACV;AAED,MAAM,WAAW,4BAA4B;IAC5C,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CACxB;AAgCD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE/E;AAED,wBAAgB,wBAAwB,CAAC,IAAI,SAAS,GAAG,EACxD,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,wBAAwB,EAAE,WAAW,CAAC,MAAM,CAAC,GAC3C,aAAa,CAkKf;AAMD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,EAAE,4BAA4B,GAAG,UAAU,EAAE,CASzG;AAmBD,wBAAsB,sBAAsB,CAAC,IAAI,SAAS,GAAG,EAC5D,YAAY,EAAE,aAAa,CAAC,mBAAmB,CAAC,EAChD,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,2BAA2B,EACnC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,CAAC,EAAE,4BAA4B,GACpC,OAAO,CAAC,IAAI,CAAC,CAyRf","sourcesContent":["import type OpenAI from \"openai\";\nimport type {\n\tTool as OpenAITool,\n\tResponseCreateParamsStreaming,\n\tResponseFunctionCallOutputItemList,\n\tResponseFunctionToolCall,\n\tResponseInput,\n\tResponseInputContent,\n\tResponseInputImage,\n\tResponseInputText,\n\tResponseOutputMessage,\n\tResponseOutputRefusal,\n\tResponseOutputText,\n\tResponseReasoningItem,\n\tResponseStreamEvent,\n} from \"openai/resources/responses/responses.js\";\nimport { calculateCost } from \"../models.ts\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tContext,\n\tImageContent,\n\tModel,\n\tStopReason,\n\tTextContent,\n\tTextSignatureV1,\n\tThinkingContent,\n\tTool,\n\tToolCall,\n\tUsage,\n} from \"../types.ts\";\nimport type { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { shortHash } from \"../utils/hash.ts\";\nimport { parseStreamingJson } from \"../utils/json-parse.ts\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.ts\";\nimport { transformMessages } from \"./transform-messages.ts\";\n\n// =============================================================================\n// Utilities\n// =============================================================================\n\nfunction encodeTextSignatureV1(id: string, phase?: TextSignatureV1[\"phase\"]): string {\n\tconst payload: TextSignatureV1 = { v: 1, id };\n\tif (phase) payload.phase = phase;\n\treturn JSON.stringify(payload);\n}\n\nfunction parseTextSignature(\n\tsignature: string | undefined,\n): { id: string; phase?: TextSignatureV1[\"phase\"] } | undefined {\n\tif (!signature) return undefined;\n\tif (signature.startsWith(\"{\")) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(signature) as Partial<TextSignatureV1>;\n\t\t\tif (parsed.v === 1 && typeof parsed.id === \"string\") {\n\t\t\t\tif (parsed.phase === \"commentary\" || parsed.phase === \"final_answer\") {\n\t\t\t\t\treturn { id: parsed.id, phase: parsed.phase };\n\t\t\t\t}\n\t\t\t\treturn { id: parsed.id };\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to legacy plain-string handling.\n\t\t}\n\t}\n\treturn { id: signature };\n}\n\nexport interface OpenAIResponsesStreamOptions {\n\tserviceTier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\tresolveServiceTier?: (\n\t\tresponseServiceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\t\trequestServiceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\t) => ResponseCreateParamsStreaming[\"service_tier\"] | undefined;\n\tapplyServiceTierPricing?: (\n\t\tusage: Usage,\n\t\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\t) => void;\n}\n\nexport interface ConvertResponsesToolsOptions {\n\tstrict?: boolean | null;\n}\n\ninterface InputTokenDetailsWithOrchestration {\n\tcached_tokens?: number;\n\torchestration_input_tokens?: number;\n\torchestration_input_cached_tokens?: number;\n}\n\ninterface OutputTokenDetailsWithOrchestration {\n\torchestration_output_tokens?: number;\n}\n\nfunction applyFuguUltraPricing<TApi extends Api>(model: Model<TApi>, usage: Usage): void {\n\tif (model.provider !== \"fugu\" || model.id !== \"fugu-ultra\") return;\n\n\t// Sakana pricing has a higher Fugu Ultra tier once context exceeds 272K tokens.\n\t// Source: https://console.sakana.ai/pricing\n\tconst highContext = usage.input + usage.cacheRead > 272_000;\n\tconst inputRate = highContext ? 10 : 5;\n\tconst outputRate = highContext ? 45 : 30;\n\tconst cacheReadRate = highContext ? 1 : 0.5;\n\tusage.cost.input = (inputRate / 1_000_000) * usage.input;\n\tusage.cost.output = (outputRate / 1_000_000) * usage.output;\n\tusage.cost.cacheRead = (cacheReadRate / 1_000_000) * usage.cacheRead;\n\tusage.cost.cacheWrite = 0;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead;\n}\n\n// =============================================================================\n// Message conversion\n// =============================================================================\n\nexport function buildResponsesInstructions(context: Context): string | undefined {\n\treturn context.systemPrompt ? sanitizeSurrogates(context.systemPrompt) : undefined;\n}\n\nexport function convertResponsesMessages<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\tallowedToolCallProviders: ReadonlySet<string>,\n): ResponseInput {\n\tconst messages: ResponseInput = [];\n\n\tconst normalizeIdPart = (part: string): string => {\n\t\tconst sanitized = part.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n\t\tconst normalized = sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;\n\t\treturn normalized.replace(/_+$/, \"\");\n\t};\n\n\tconst buildForeignResponsesItemId = (itemId: string): string => {\n\t\tconst normalized = `fc_${shortHash(itemId)}`;\n\t\treturn normalized.length > 64 ? normalized.slice(0, 64) : normalized;\n\t};\n\n\tconst normalizeToolCallId = (id: string, _targetModel: Model<TApi>, source: AssistantMessage): string => {\n\t\tif (!allowedToolCallProviders.has(model.provider)) return normalizeIdPart(id);\n\t\tif (!id.includes(\"|\")) return normalizeIdPart(id);\n\t\tconst [callId, itemId] = id.split(\"|\");\n\t\tconst normalizedCallId = normalizeIdPart(callId);\n\t\tconst isForeignToolCall = source.provider !== model.provider || source.api !== model.api;\n\t\tlet normalizedItemId = isForeignToolCall ? buildForeignResponsesItemId(itemId) : normalizeIdPart(itemId);\n\t\t// OpenAI Responses API requires item id to start with \"fc\"\n\t\tif (!normalizedItemId.startsWith(\"fc_\")) {\n\t\t\tnormalizedItemId = normalizeIdPart(`fc_${normalizedItemId}`);\n\t\t}\n\t\treturn `${normalizedCallId}|${normalizedItemId}`;\n\t};\n\n\tconst transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);\n\n\tlet msgIndex = 0;\n\tfor (const msg of transformedMessages) {\n\t\tif (msg.role === \"user\") {\n\t\t\tif (typeof msg.content === \"string\") {\n\t\t\t\tmessages.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: [{ type: \"input_text\", text: sanitizeSurrogates(msg.content) }],\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst content: ResponseInputContent[] = msg.content.map((item): ResponseInputContent => {\n\t\t\t\t\tif (item.type === \"text\") {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttype: \"input_text\",\n\t\t\t\t\t\t\ttext: sanitizeSurrogates(item.text),\n\t\t\t\t\t\t} satisfies ResponseInputText;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: \"input_image\",\n\t\t\t\t\t\tdetail: \"auto\",\n\t\t\t\t\t\timage_url: `data:${item.mimeType};base64,${item.data}`,\n\t\t\t\t\t} satisfies ResponseInputImage;\n\t\t\t\t});\n\t\t\t\tif (content.length === 0) continue;\n\t\t\t\tmessages.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\tconst output: ResponseInput = [];\n\t\t\tconst assistantMsg = msg as AssistantMessage;\n\t\t\tconst isDifferentModel =\n\t\t\t\tassistantMsg.model !== model.id &&\n\t\t\t\tassistantMsg.provider === model.provider &&\n\t\t\t\tassistantMsg.api === model.api;\n\t\t\tlet textBlockIndex = 0;\n\n\t\t\tfor (const block of msg.content) {\n\t\t\t\tif (block.type === \"thinking\") {\n\t\t\t\t\tif (block.thinkingSignature) {\n\t\t\t\t\t\tconst reasoningItem = JSON.parse(block.thinkingSignature) as ResponseReasoningItem;\n\t\t\t\t\t\toutput.push(reasoningItem);\n\t\t\t\t\t}\n\t\t\t\t} else if (block.type === \"text\") {\n\t\t\t\t\tconst textBlock = block as TextContent;\n\t\t\t\t\tconst parsedSignature = parseTextSignature(textBlock.textSignature);\n\t\t\t\t\tconst fallbackMessageId =\n\t\t\t\t\t\ttextBlockIndex === 0 ? `msg_pi_${msgIndex}` : `msg_pi_${msgIndex}_${textBlockIndex}`;\n\t\t\t\t\ttextBlockIndex++;\n\t\t\t\t\t// OpenAI requires id to be max 64 characters\n\t\t\t\t\tlet msgId = parsedSignature?.id;\n\t\t\t\t\tif (!msgId) {\n\t\t\t\t\t\tmsgId = fallbackMessageId;\n\t\t\t\t\t} else if (msgId.length > 64) {\n\t\t\t\t\t\tmsgId = `msg_${shortHash(msgId)}`;\n\t\t\t\t\t}\n\t\t\t\t\toutput.push({\n\t\t\t\t\t\ttype: \"message\",\n\t\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\t\tcontent: [{ type: \"output_text\", text: sanitizeSurrogates(textBlock.text), annotations: [] }],\n\t\t\t\t\t\tstatus: \"completed\",\n\t\t\t\t\t\tid: msgId,\n\t\t\t\t\t\tphase: parsedSignature?.phase,\n\t\t\t\t\t} satisfies ResponseOutputMessage);\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\tconst toolCall = block as ToolCall;\n\t\t\t\t\tconst [callId, itemIdRaw] = toolCall.id.split(\"|\");\n\t\t\t\t\tlet itemId: string | undefined = itemIdRaw;\n\n\t\t\t\t\t// For different-model messages, set id to undefined to avoid pairing validation.\n\t\t\t\t\t// OpenAI tracks which fc_xxx IDs were paired with rs_xxx reasoning items.\n\t\t\t\t\t// By omitting the id, we avoid triggering that validation (like cross-provider does).\n\t\t\t\t\tif (isDifferentModel && itemId?.startsWith(\"fc_\")) {\n\t\t\t\t\t\titemId = undefined;\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.push({\n\t\t\t\t\t\ttype: \"function_call\",\n\t\t\t\t\t\tid: itemId,\n\t\t\t\t\t\tcall_id: callId,\n\t\t\t\t\t\tname: toolCall.name,\n\t\t\t\t\t\targuments: JSON.stringify(toolCall.arguments),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (output.length === 0) continue;\n\t\t\tmessages.push(...output);\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\tconst textResult = msg.content\n\t\t\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\\n\");\n\t\t\tconst hasImages = msg.content.some((c): c is ImageContent => c.type === \"image\");\n\t\t\tconst hasText = textResult.length > 0;\n\t\t\tconst [callId] = msg.toolCallId.split(\"|\");\n\n\t\t\tlet output: string | ResponseFunctionCallOutputItemList;\n\t\t\tif (hasImages && model.input.includes(\"image\")) {\n\t\t\t\tconst contentParts: ResponseFunctionCallOutputItemList = [];\n\n\t\t\t\tif (hasText) {\n\t\t\t\t\tcontentParts.push({\n\t\t\t\t\t\ttype: \"input_text\",\n\t\t\t\t\t\ttext: sanitizeSurrogates(textResult),\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tfor (const block of msg.content) {\n\t\t\t\t\tif (block.type === \"image\") {\n\t\t\t\t\t\tcontentParts.push({\n\t\t\t\t\t\t\ttype: \"input_image\",\n\t\t\t\t\t\t\tdetail: \"auto\",\n\t\t\t\t\t\t\timage_url: `data:${block.mimeType};base64,${block.data}`,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\toutput = contentParts;\n\t\t\t} else {\n\t\t\t\toutput = sanitizeSurrogates(hasText ? textResult : \"(see attached image)\");\n\t\t\t}\n\n\t\t\tmessages.push({\n\t\t\t\ttype: \"function_call_output\",\n\t\t\t\tcall_id: callId,\n\t\t\t\toutput,\n\t\t\t});\n\t\t}\n\t\tmsgIndex++;\n\t}\n\n\treturn messages;\n}\n\n// =============================================================================\n// Tool conversion\n// =============================================================================\n\nexport function convertResponsesTools(tools: Tool[], options?: ConvertResponsesToolsOptions): OpenAITool[] {\n\tconst strict = options?.strict === undefined ? false : options.strict;\n\treturn tools.map((tool) => ({\n\t\ttype: \"function\",\n\t\tname: tool.name,\n\t\tdescription: tool.description,\n\t\tparameters: tool.parameters as any, // TypeBox already generates JSON Schema\n\t\tstrict,\n\t}));\n}\n\n// =============================================================================\n// Stream processing\n// =============================================================================\n\nconst REASONING_SUMMARY_DELIMITER_ONLY = /^<!--\\s*-->$/;\n\nfunction isReasoningSummaryDelimiterOnly(text: string): boolean {\n\treturn REASONING_SUMMARY_DELIMITER_ONLY.test(text.trim());\n}\n\nfunction normalizeReasoningSummaryText(parts: readonly { text?: string }[] | undefined): string {\n\treturn (parts ?? [])\n\t\t.map((part) => part.text ?? \"\")\n\t\t.filter((text) => text.trim().length > 0 && !isReasoningSummaryDelimiterOnly(text))\n\t\t.join(\"\\n\\n\");\n}\n\nexport async function processResponsesStream<TApi extends Api>(\n\topenaiStream: AsyncIterable<ResponseStreamEvent>,\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n\tmodel: Model<TApi>,\n\toptions?: OpenAIResponsesStreamOptions,\n): Promise<void> {\n\tlet currentItem: ResponseReasoningItem | ResponseOutputMessage | ResponseFunctionToolCall | null = null;\n\tlet currentBlock: ThinkingContent | TextContent | (ToolCall & { partialJson: string }) | null = null;\n\tlet currentReasoningSummaryPartText = \"\";\n\tlet sawTerminalResponseEvent = false;\n\tconst blocks = output.content;\n\tconst blockIndex = () => blocks.length - 1;\n\tconst ensureMessageOutputTextPart = (): ResponseOutputText | undefined => {\n\t\tif (currentItem?.type !== \"message\") return undefined;\n\t\tconst lastPart = currentItem.content[currentItem.content.length - 1];\n\t\tif (lastPart?.type === \"output_text\") return lastPart;\n\t\tconst part: ResponseOutputText = { type: \"output_text\", text: \"\", annotations: [] };\n\t\tcurrentItem.content.push(part);\n\t\treturn part;\n\t};\n\tconst ensureMessageRefusalPart = (): ResponseOutputRefusal | undefined => {\n\t\tif (currentItem?.type !== \"message\") return undefined;\n\t\tconst lastPart = currentItem.content[currentItem.content.length - 1];\n\t\tif (lastPart?.type === \"refusal\") return lastPart;\n\t\tconst part: ResponseOutputRefusal = { type: \"refusal\", refusal: \"\" };\n\t\tcurrentItem.content.push(part);\n\t\treturn part;\n\t};\n\tconst finalizeResponse = (\n\t\tresponse: Extract<ResponseStreamEvent, { type: \"response.completed\" | \"response.incomplete\" }>[\"response\"],\n\t): void => {\n\t\tsawTerminalResponseEvent = true;\n\t\tif (response?.id) {\n\t\t\toutput.responseId = response.id;\n\t\t}\n\t\tif (response?.usage) {\n\t\t\tconst inputDetails = response.usage.input_tokens_details as InputTokenDetailsWithOrchestration | undefined;\n\t\t\tconst outputDetails = response.usage.output_tokens_details as OutputTokenDetailsWithOrchestration | undefined;\n\t\t\tconst cachedTokens = inputDetails?.cached_tokens || 0;\n\t\t\tlet inputTokens = (response.usage.input_tokens || 0) - cachedTokens;\n\t\t\tlet outputTokens = response.usage.output_tokens || 0;\n\t\t\tlet cacheReadTokens = cachedTokens;\n\t\t\tlet totalTokens = response.usage.total_tokens || 0;\n\t\t\tif (model.provider === \"fugu\") {\n\t\t\t\tconst orchestrationInputTokens = inputDetails?.orchestration_input_tokens || 0;\n\t\t\t\tconst orchestrationInputCachedTokens = inputDetails?.orchestration_input_cached_tokens || 0;\n\t\t\t\tconst orchestrationOutputTokens = outputDetails?.orchestration_output_tokens || 0;\n\t\t\t\tinputTokens += orchestrationInputTokens;\n\t\t\t\tcacheReadTokens += orchestrationInputCachedTokens;\n\t\t\t\toutputTokens += orchestrationOutputTokens;\n\t\t\t\ttotalTokens += orchestrationInputTokens + orchestrationInputCachedTokens + orchestrationOutputTokens;\n\t\t\t}\n\t\t\toutput.usage = {\n\t\t\t\t// OpenAI includes cached tokens in input_tokens, so subtract to get non-cached input.\n\t\t\t\t// Sakana Fugu Ultra also reports billable orchestration tokens in token details fields.\n\t\t\t\t// Source: https://console.sakana.ai/pricing#usage-field-details\n\t\t\t\tinput: inputTokens,\n\t\t\t\toutput: outputTokens,\n\t\t\t\tcacheRead: cacheReadTokens,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: (response.usage as any).cost || 0 },\n\t\t\t};\n\t\t}\n\t\tcalculateCost(model, output.usage, {\n\t\t\t// response.usage is absent on some streams; this call sits outside the guard above.\n\t\t\tproviderSuppliedTotal: Boolean((response.usage as { cost?: number } | undefined)?.cost),\n\t\t});\n\t\tapplyFuguUltraPricing(model, output.usage);\n\t\tif (options?.applyServiceTierPricing) {\n\t\t\tconst serviceTier = options.resolveServiceTier\n\t\t\t\t? options.resolveServiceTier(response?.service_tier, options.serviceTier)\n\t\t\t\t: (response?.service_tier ?? options.serviceTier);\n\t\t\toptions.applyServiceTierPricing(output.usage, serviceTier);\n\t\t}\n\t\t// Map status to stop reason\n\t\toutput.stopReason = mapStopReason(response?.status);\n\t\tif (output.content.some((b) => b.type === \"toolCall\") && output.stopReason === \"stop\") {\n\t\t\toutput.stopReason = \"toolUse\";\n\t\t}\n\t};\n\n\tfor await (const event of openaiStream) {\n\t\tif (event.type === \"response.created\") {\n\t\t\toutput.responseId = event.response.id;\n\t\t} else if (event.type === \"response.output_item.added\") {\n\t\t\tconst item = event.item;\n\t\t\tif (item.type === \"reasoning\") {\n\t\t\t\tcurrentItem = item;\n\t\t\t\tcurrentBlock = { type: \"thinking\", thinking: \"\" };\n\t\t\t\tcurrentReasoningSummaryPartText = \"\";\n\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\tstream.push({ type: \"thinking_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t} else if (item.type === \"message\") {\n\t\t\t\tcurrentItem = item;\n\t\t\t\tcurrentBlock = { type: \"text\", text: \"\" };\n\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\tstream.push({ type: \"text_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t} else if (item.type === \"function_call\") {\n\t\t\t\tcurrentItem = item;\n\t\t\t\tcurrentBlock = {\n\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\tid: `${item.call_id}|${item.id}`,\n\t\t\t\t\tname: item.name,\n\t\t\t\t\targuments: {},\n\t\t\t\t\tpartialJson: item.arguments || \"\",\n\t\t\t\t};\n\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\tstream.push({ type: \"toolcall_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t}\n\t\t} else if (event.type === \"response.reasoning_summary_part.added\") {\n\t\t\tif (currentItem && currentItem.type === \"reasoning\") {\n\t\t\t\tcurrentItem.summary = currentItem.summary || [];\n\t\t\t\tcurrentItem.summary.push(event.part);\n\t\t\t\tcurrentReasoningSummaryPartText = event.part.text ?? \"\";\n\t\t\t}\n\t\t} else if (event.type === \"response.reasoning_summary_text.delta\") {\n\t\t\tif (currentItem?.type === \"reasoning\") {\n\t\t\t\tcurrentItem.summary = currentItem.summary || [];\n\t\t\t\tconst lastPart = currentItem.summary[currentItem.summary.length - 1];\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tlastPart.text += event.delta;\n\t\t\t\t\tcurrentReasoningSummaryPartText += event.delta;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (event.type === \"response.reasoning_summary_part.done\") {\n\t\t\tif (currentItem?.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tcurrentItem.summary = currentItem.summary || [];\n\t\t\t\tconst lastPart = currentItem.summary[currentItem.summary.length - 1];\n\t\t\t\tconst partText = lastPart?.text ?? currentReasoningSummaryPartText;\n\t\t\t\tif (partText.trim().length > 0 && !isReasoningSummaryDelimiterOnly(partText)) {\n\t\t\t\t\tconst delta = `${partText}\\n\\n`;\n\t\t\t\t\tcurrentBlock.thinking += delta;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tcurrentReasoningSummaryPartText = \"\";\n\t\t\t}\n\t\t} else if (event.type === \"response.reasoning_text.delta\") {\n\t\t\tif (currentItem?.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tcurrentBlock.thinking += event.delta;\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tdelta: event.delta,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (event.type === \"response.content_part.added\") {\n\t\t\tif (currentItem?.type === \"message\") {\n\t\t\t\tcurrentItem.content = currentItem.content || [];\n\t\t\t\t// Filter out ReasoningText, only accept output_text and refusal\n\t\t\t\tif (event.part.type === \"output_text\" || event.part.type === \"refusal\") {\n\t\t\t\t\tcurrentItem.content.push(event.part);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (event.type === \"response.output_text.delta\") {\n\t\t\tif (currentItem?.type === \"message\" && currentBlock?.type === \"text\") {\n\t\t\t\tconst lastPart = ensureMessageOutputTextPart();\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tcurrentBlock.text += event.delta;\n\t\t\t\t\tlastPart.text += event.delta;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta: event.delta,\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} else if (event.type === \"response.refusal.delta\") {\n\t\t\tif (currentItem?.type === \"message\" && currentBlock?.type === \"text\") {\n\t\t\t\tconst lastPart = ensureMessageRefusalPart();\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tcurrentBlock.text += event.delta;\n\t\t\t\t\tlastPart.refusal += event.delta;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta: event.delta,\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} else if (event.type === \"response.function_call_arguments.delta\") {\n\t\t\tif (currentItem?.type === \"function_call\" && currentBlock?.type === \"toolCall\") {\n\t\t\t\tcurrentBlock.partialJson += event.delta;\n\t\t\t\tcurrentBlock.arguments = parseStreamingJson(currentBlock.partialJson);\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tdelta: event.delta,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (event.type === \"response.function_call_arguments.done\") {\n\t\t\tif (currentItem?.type === \"function_call\" && currentBlock?.type === \"toolCall\") {\n\t\t\t\tconst previousPartialJson = currentBlock.partialJson;\n\t\t\t\tcurrentBlock.partialJson = event.arguments;\n\t\t\t\tcurrentBlock.arguments = parseStreamingJson(currentBlock.partialJson);\n\n\t\t\t\tif (event.arguments.startsWith(previousPartialJson)) {\n\t\t\t\t\tconst delta = event.arguments.slice(previousPartialJson.length);\n\t\t\t\t\tif (delta.length > 0) {\n\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\tdelta,\n\t\t\t\t\t\t\tpartial: output,\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} else if (event.type === \"response.output_item.done\") {\n\t\t\tconst item = event.item;\n\n\t\t\tif (item.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tconst summaryText = normalizeReasoningSummaryText(item.summary);\n\t\t\t\tconst contentText = item.content?.map((c) => c.text).join(\"\\n\\n\") || \"\";\n\t\t\t\tcurrentBlock.thinking = summaryText || contentText || currentBlock.thinking;\n\t\t\t\tcurrentBlock.thinkingSignature = JSON.stringify(item);\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tcontent: currentBlock.thinking,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t\tcurrentBlock = null;\n\t\t\t} else if (item.type === \"message\" && currentBlock?.type === \"text\") {\n\t\t\t\tcurrentBlock.text = item.content.map((c) => (c.type === \"output_text\" ? c.text : c.refusal)).join(\"\");\n\t\t\t\tcurrentBlock.textSignature = encodeTextSignatureV1(item.id, item.phase ?? undefined);\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tcontent: currentBlock.text,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t\tcurrentBlock = null;\n\t\t\t} else if (item.type === \"function_call\") {\n\t\t\t\tconst args =\n\t\t\t\t\tcurrentBlock?.type === \"toolCall\" && currentBlock.partialJson\n\t\t\t\t\t\t? parseStreamingJson(currentBlock.partialJson)\n\t\t\t\t\t\t: parseStreamingJson(item.arguments || \"{}\");\n\n\t\t\t\tlet toolCall: ToolCall;\n\t\t\t\tif (currentBlock?.type === \"toolCall\") {\n\t\t\t\t\t// Finalize in-place and strip the scratch buffer so replay only\n\t\t\t\t\t// carries parsed arguments.\n\t\t\t\t\tcurrentBlock.arguments = args;\n\t\t\t\t\tdelete (currentBlock as { partialJson?: string }).partialJson;\n\t\t\t\t\ttoolCall = currentBlock;\n\t\t\t\t} else {\n\t\t\t\t\ttoolCall = {\n\t\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\t\tid: `${item.call_id}|${item.id}`,\n\t\t\t\t\t\tname: item.name,\n\t\t\t\t\t\targuments: args,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tcurrentBlock = null;\n\t\t\t\tstream.push({ type: \"toolcall_end\", contentIndex: blockIndex(), toolCall, partial: output });\n\t\t\t}\n\t\t} else if (event.type === \"response.completed\" || event.type === \"response.incomplete\") {\n\t\t\tfinalizeResponse(event.response);\n\t\t} else if (event.type === \"error\") {\n\t\t\tthrow new Error(`Error Code ${event.code}: ${event.message}` || \"Unknown error\");\n\t\t} else if (event.type === \"response.failed\") {\n\t\t\tsawTerminalResponseEvent = true;\n\t\t\tconst error = event.response?.error;\n\t\t\tconst details = event.response?.incomplete_details;\n\t\t\tconst msg = error\n\t\t\t\t? `${error.code || \"unknown\"}: ${error.message || \"no message\"}`\n\t\t\t\t: details?.reason\n\t\t\t\t\t? `incomplete: ${details.reason}`\n\t\t\t\t\t: \"Unknown error (no error details in response)\";\n\t\t\tthrow new Error(msg);\n\t\t}\n\t}\n\tif (!sawTerminalResponseEvent) {\n\t\tthrow new Error(\"OpenAI Responses stream ended before a terminal response event\");\n\t}\n}\n\nfunction mapStopReason(status: OpenAI.Responses.ResponseStatus | undefined): StopReason {\n\tif (!status) return \"stop\";\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn \"stop\";\n\t\tcase \"incomplete\":\n\t\t\treturn \"length\";\n\t\tcase \"failed\":\n\t\tcase \"cancelled\":\n\t\t\treturn \"error\";\n\t\t// These two are wonky ...\n\t\tcase \"in_progress\":\n\t\tcase \"queued\":\n\t\t\treturn \"stop\";\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = status;\n\t\t\tthrow new Error(`Unhandled stop reason: ${_exhaustive}`);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -226,9 +226,20 @@ export function convertResponsesTools(tools, options) {
|
|
|
226
226
|
// =============================================================================
|
|
227
227
|
// Stream processing
|
|
228
228
|
// =============================================================================
|
|
229
|
+
const REASONING_SUMMARY_DELIMITER_ONLY = /^<!--\s*-->$/;
|
|
230
|
+
function isReasoningSummaryDelimiterOnly(text) {
|
|
231
|
+
return REASONING_SUMMARY_DELIMITER_ONLY.test(text.trim());
|
|
232
|
+
}
|
|
233
|
+
function normalizeReasoningSummaryText(parts) {
|
|
234
|
+
return (parts ?? [])
|
|
235
|
+
.map((part) => part.text ?? "")
|
|
236
|
+
.filter((text) => text.trim().length > 0 && !isReasoningSummaryDelimiterOnly(text))
|
|
237
|
+
.join("\n\n");
|
|
238
|
+
}
|
|
229
239
|
export async function processResponsesStream(openaiStream, output, stream, model, options) {
|
|
230
240
|
let currentItem = null;
|
|
231
241
|
let currentBlock = null;
|
|
242
|
+
let currentReasoningSummaryPartText = "";
|
|
232
243
|
let sawTerminalResponseEvent = false;
|
|
233
244
|
const blocks = output.content;
|
|
234
245
|
const blockIndex = () => blocks.length - 1;
|
|
@@ -312,6 +323,7 @@ export async function processResponsesStream(openaiStream, output, stream, model
|
|
|
312
323
|
if (item.type === "reasoning") {
|
|
313
324
|
currentItem = item;
|
|
314
325
|
currentBlock = { type: "thinking", thinking: "" };
|
|
326
|
+
currentReasoningSummaryPartText = "";
|
|
315
327
|
output.content.push(currentBlock);
|
|
316
328
|
stream.push({ type: "thinking_start", contentIndex: blockIndex(), partial: output });
|
|
317
329
|
}
|
|
@@ -338,21 +350,16 @@ export async function processResponsesStream(openaiStream, output, stream, model
|
|
|
338
350
|
if (currentItem && currentItem.type === "reasoning") {
|
|
339
351
|
currentItem.summary = currentItem.summary || [];
|
|
340
352
|
currentItem.summary.push(event.part);
|
|
353
|
+
currentReasoningSummaryPartText = event.part.text ?? "";
|
|
341
354
|
}
|
|
342
355
|
}
|
|
343
356
|
else if (event.type === "response.reasoning_summary_text.delta") {
|
|
344
|
-
if (currentItem?.type === "reasoning"
|
|
357
|
+
if (currentItem?.type === "reasoning") {
|
|
345
358
|
currentItem.summary = currentItem.summary || [];
|
|
346
359
|
const lastPart = currentItem.summary[currentItem.summary.length - 1];
|
|
347
360
|
if (lastPart) {
|
|
348
|
-
currentBlock.thinking += event.delta;
|
|
349
361
|
lastPart.text += event.delta;
|
|
350
|
-
|
|
351
|
-
type: "thinking_delta",
|
|
352
|
-
contentIndex: blockIndex(),
|
|
353
|
-
delta: event.delta,
|
|
354
|
-
partial: output,
|
|
355
|
-
});
|
|
362
|
+
currentReasoningSummaryPartText += event.delta;
|
|
356
363
|
}
|
|
357
364
|
}
|
|
358
365
|
}
|
|
@@ -360,16 +367,18 @@ export async function processResponsesStream(openaiStream, output, stream, model
|
|
|
360
367
|
if (currentItem?.type === "reasoning" && currentBlock?.type === "thinking") {
|
|
361
368
|
currentItem.summary = currentItem.summary || [];
|
|
362
369
|
const lastPart = currentItem.summary[currentItem.summary.length - 1];
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
370
|
+
const partText = lastPart?.text ?? currentReasoningSummaryPartText;
|
|
371
|
+
if (partText.trim().length > 0 && !isReasoningSummaryDelimiterOnly(partText)) {
|
|
372
|
+
const delta = `${partText}\n\n`;
|
|
373
|
+
currentBlock.thinking += delta;
|
|
366
374
|
stream.push({
|
|
367
375
|
type: "thinking_delta",
|
|
368
376
|
contentIndex: blockIndex(),
|
|
369
|
-
delta
|
|
377
|
+
delta,
|
|
370
378
|
partial: output,
|
|
371
379
|
});
|
|
372
380
|
}
|
|
381
|
+
currentReasoningSummaryPartText = "";
|
|
373
382
|
}
|
|
374
383
|
}
|
|
375
384
|
else if (event.type === "response.reasoning_text.delta") {
|
|
@@ -455,7 +464,7 @@ export async function processResponsesStream(openaiStream, output, stream, model
|
|
|
455
464
|
else if (event.type === "response.output_item.done") {
|
|
456
465
|
const item = event.item;
|
|
457
466
|
if (item.type === "reasoning" && currentBlock?.type === "thinking") {
|
|
458
|
-
const summaryText = item.summary
|
|
467
|
+
const summaryText = normalizeReasoningSummaryText(item.summary);
|
|
459
468
|
const contentText = item.content?.map((c) => c.text).join("\n\n") || "";
|
|
460
469
|
currentBlock.thinking = summaryText || contentText || currentBlock.thinking;
|
|
461
470
|
currentBlock.thinkingSignature = JSON.stringify(item);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-responses-shared.js","sourceRoot":"","sources":["../../src/providers/openai-responses-shared.ts"],"names":[],"mappings":"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","sourcesContent":["import type OpenAI from \"openai\";\nimport type {\n\tTool as OpenAITool,\n\tResponseCreateParamsStreaming,\n\tResponseFunctionCallOutputItemList,\n\tResponseFunctionToolCall,\n\tResponseInput,\n\tResponseInputContent,\n\tResponseInputImage,\n\tResponseInputText,\n\tResponseOutputMessage,\n\tResponseOutputRefusal,\n\tResponseOutputText,\n\tResponseReasoningItem,\n\tResponseStreamEvent,\n} from \"openai/resources/responses/responses.js\";\nimport { calculateCost } from \"../models.ts\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tContext,\n\tImageContent,\n\tModel,\n\tStopReason,\n\tTextContent,\n\tTextSignatureV1,\n\tThinkingContent,\n\tTool,\n\tToolCall,\n\tUsage,\n} from \"../types.ts\";\nimport type { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { shortHash } from \"../utils/hash.ts\";\nimport { parseStreamingJson } from \"../utils/json-parse.ts\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.ts\";\nimport { transformMessages } from \"./transform-messages.ts\";\n\n// =============================================================================\n// Utilities\n// =============================================================================\n\nfunction encodeTextSignatureV1(id: string, phase?: TextSignatureV1[\"phase\"]): string {\n\tconst payload: TextSignatureV1 = { v: 1, id };\n\tif (phase) payload.phase = phase;\n\treturn JSON.stringify(payload);\n}\n\nfunction parseTextSignature(\n\tsignature: string | undefined,\n): { id: string; phase?: TextSignatureV1[\"phase\"] } | undefined {\n\tif (!signature) return undefined;\n\tif (signature.startsWith(\"{\")) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(signature) as Partial<TextSignatureV1>;\n\t\t\tif (parsed.v === 1 && typeof parsed.id === \"string\") {\n\t\t\t\tif (parsed.phase === \"commentary\" || parsed.phase === \"final_answer\") {\n\t\t\t\t\treturn { id: parsed.id, phase: parsed.phase };\n\t\t\t\t}\n\t\t\t\treturn { id: parsed.id };\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to legacy plain-string handling.\n\t\t}\n\t}\n\treturn { id: signature };\n}\n\nexport interface OpenAIResponsesStreamOptions {\n\tserviceTier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\tresolveServiceTier?: (\n\t\tresponseServiceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\t\trequestServiceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\t) => ResponseCreateParamsStreaming[\"service_tier\"] | undefined;\n\tapplyServiceTierPricing?: (\n\t\tusage: Usage,\n\t\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\t) => void;\n}\n\nexport interface ConvertResponsesToolsOptions {\n\tstrict?: boolean | null;\n}\n\ninterface InputTokenDetailsWithOrchestration {\n\tcached_tokens?: number;\n\torchestration_input_tokens?: number;\n\torchestration_input_cached_tokens?: number;\n}\n\ninterface OutputTokenDetailsWithOrchestration {\n\torchestration_output_tokens?: number;\n}\n\nfunction applyFuguUltraPricing<TApi extends Api>(model: Model<TApi>, usage: Usage): void {\n\tif (model.provider !== \"fugu\" || model.id !== \"fugu-ultra\") return;\n\n\t// Sakana pricing has a higher Fugu Ultra tier once context exceeds 272K tokens.\n\t// Source: https://console.sakana.ai/pricing\n\tconst highContext = usage.input + usage.cacheRead > 272_000;\n\tconst inputRate = highContext ? 10 : 5;\n\tconst outputRate = highContext ? 45 : 30;\n\tconst cacheReadRate = highContext ? 1 : 0.5;\n\tusage.cost.input = (inputRate / 1_000_000) * usage.input;\n\tusage.cost.output = (outputRate / 1_000_000) * usage.output;\n\tusage.cost.cacheRead = (cacheReadRate / 1_000_000) * usage.cacheRead;\n\tusage.cost.cacheWrite = 0;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead;\n}\n\n// =============================================================================\n// Message conversion\n// =============================================================================\n\nexport function buildResponsesInstructions(context: Context): string | undefined {\n\treturn context.systemPrompt ? sanitizeSurrogates(context.systemPrompt) : undefined;\n}\n\nexport function convertResponsesMessages<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\tallowedToolCallProviders: ReadonlySet<string>,\n): ResponseInput {\n\tconst messages: ResponseInput = [];\n\n\tconst normalizeIdPart = (part: string): string => {\n\t\tconst sanitized = part.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n\t\tconst normalized = sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;\n\t\treturn normalized.replace(/_+$/, \"\");\n\t};\n\n\tconst buildForeignResponsesItemId = (itemId: string): string => {\n\t\tconst normalized = `fc_${shortHash(itemId)}`;\n\t\treturn normalized.length > 64 ? normalized.slice(0, 64) : normalized;\n\t};\n\n\tconst normalizeToolCallId = (id: string, _targetModel: Model<TApi>, source: AssistantMessage): string => {\n\t\tif (!allowedToolCallProviders.has(model.provider)) return normalizeIdPart(id);\n\t\tif (!id.includes(\"|\")) return normalizeIdPart(id);\n\t\tconst [callId, itemId] = id.split(\"|\");\n\t\tconst normalizedCallId = normalizeIdPart(callId);\n\t\tconst isForeignToolCall = source.provider !== model.provider || source.api !== model.api;\n\t\tlet normalizedItemId = isForeignToolCall ? buildForeignResponsesItemId(itemId) : normalizeIdPart(itemId);\n\t\t// OpenAI Responses API requires item id to start with \"fc\"\n\t\tif (!normalizedItemId.startsWith(\"fc_\")) {\n\t\t\tnormalizedItemId = normalizeIdPart(`fc_${normalizedItemId}`);\n\t\t}\n\t\treturn `${normalizedCallId}|${normalizedItemId}`;\n\t};\n\n\tconst transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);\n\n\tlet msgIndex = 0;\n\tfor (const msg of transformedMessages) {\n\t\tif (msg.role === \"user\") {\n\t\t\tif (typeof msg.content === \"string\") {\n\t\t\t\tmessages.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: [{ type: \"input_text\", text: sanitizeSurrogates(msg.content) }],\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst content: ResponseInputContent[] = msg.content.map((item): ResponseInputContent => {\n\t\t\t\t\tif (item.type === \"text\") {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttype: \"input_text\",\n\t\t\t\t\t\t\ttext: sanitizeSurrogates(item.text),\n\t\t\t\t\t\t} satisfies ResponseInputText;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: \"input_image\",\n\t\t\t\t\t\tdetail: \"auto\",\n\t\t\t\t\t\timage_url: `data:${item.mimeType};base64,${item.data}`,\n\t\t\t\t\t} satisfies ResponseInputImage;\n\t\t\t\t});\n\t\t\t\tif (content.length === 0) continue;\n\t\t\t\tmessages.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\tconst output: ResponseInput = [];\n\t\t\tconst assistantMsg = msg as AssistantMessage;\n\t\t\tconst isDifferentModel =\n\t\t\t\tassistantMsg.model !== model.id &&\n\t\t\t\tassistantMsg.provider === model.provider &&\n\t\t\t\tassistantMsg.api === model.api;\n\t\t\tlet textBlockIndex = 0;\n\n\t\t\tfor (const block of msg.content) {\n\t\t\t\tif (block.type === \"thinking\") {\n\t\t\t\t\tif (block.thinkingSignature) {\n\t\t\t\t\t\tconst reasoningItem = JSON.parse(block.thinkingSignature) as ResponseReasoningItem;\n\t\t\t\t\t\toutput.push(reasoningItem);\n\t\t\t\t\t}\n\t\t\t\t} else if (block.type === \"text\") {\n\t\t\t\t\tconst textBlock = block as TextContent;\n\t\t\t\t\tconst parsedSignature = parseTextSignature(textBlock.textSignature);\n\t\t\t\t\tconst fallbackMessageId =\n\t\t\t\t\t\ttextBlockIndex === 0 ? `msg_pi_${msgIndex}` : `msg_pi_${msgIndex}_${textBlockIndex}`;\n\t\t\t\t\ttextBlockIndex++;\n\t\t\t\t\t// OpenAI requires id to be max 64 characters\n\t\t\t\t\tlet msgId = parsedSignature?.id;\n\t\t\t\t\tif (!msgId) {\n\t\t\t\t\t\tmsgId = fallbackMessageId;\n\t\t\t\t\t} else if (msgId.length > 64) {\n\t\t\t\t\t\tmsgId = `msg_${shortHash(msgId)}`;\n\t\t\t\t\t}\n\t\t\t\t\toutput.push({\n\t\t\t\t\t\ttype: \"message\",\n\t\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\t\tcontent: [{ type: \"output_text\", text: sanitizeSurrogates(textBlock.text), annotations: [] }],\n\t\t\t\t\t\tstatus: \"completed\",\n\t\t\t\t\t\tid: msgId,\n\t\t\t\t\t\tphase: parsedSignature?.phase,\n\t\t\t\t\t} satisfies ResponseOutputMessage);\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\tconst toolCall = block as ToolCall;\n\t\t\t\t\tconst [callId, itemIdRaw] = toolCall.id.split(\"|\");\n\t\t\t\t\tlet itemId: string | undefined = itemIdRaw;\n\n\t\t\t\t\t// For different-model messages, set id to undefined to avoid pairing validation.\n\t\t\t\t\t// OpenAI tracks which fc_xxx IDs were paired with rs_xxx reasoning items.\n\t\t\t\t\t// By omitting the id, we avoid triggering that validation (like cross-provider does).\n\t\t\t\t\tif (isDifferentModel && itemId?.startsWith(\"fc_\")) {\n\t\t\t\t\t\titemId = undefined;\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.push({\n\t\t\t\t\t\ttype: \"function_call\",\n\t\t\t\t\t\tid: itemId,\n\t\t\t\t\t\tcall_id: callId,\n\t\t\t\t\t\tname: toolCall.name,\n\t\t\t\t\t\targuments: JSON.stringify(toolCall.arguments),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (output.length === 0) continue;\n\t\t\tmessages.push(...output);\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\tconst textResult = msg.content\n\t\t\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\\n\");\n\t\t\tconst hasImages = msg.content.some((c): c is ImageContent => c.type === \"image\");\n\t\t\tconst hasText = textResult.length > 0;\n\t\t\tconst [callId] = msg.toolCallId.split(\"|\");\n\n\t\t\tlet output: string | ResponseFunctionCallOutputItemList;\n\t\t\tif (hasImages && model.input.includes(\"image\")) {\n\t\t\t\tconst contentParts: ResponseFunctionCallOutputItemList = [];\n\n\t\t\t\tif (hasText) {\n\t\t\t\t\tcontentParts.push({\n\t\t\t\t\t\ttype: \"input_text\",\n\t\t\t\t\t\ttext: sanitizeSurrogates(textResult),\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tfor (const block of msg.content) {\n\t\t\t\t\tif (block.type === \"image\") {\n\t\t\t\t\t\tcontentParts.push({\n\t\t\t\t\t\t\ttype: \"input_image\",\n\t\t\t\t\t\t\tdetail: \"auto\",\n\t\t\t\t\t\t\timage_url: `data:${block.mimeType};base64,${block.data}`,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\toutput = contentParts;\n\t\t\t} else {\n\t\t\t\toutput = sanitizeSurrogates(hasText ? textResult : \"(see attached image)\");\n\t\t\t}\n\n\t\t\tmessages.push({\n\t\t\t\ttype: \"function_call_output\",\n\t\t\t\tcall_id: callId,\n\t\t\t\toutput,\n\t\t\t});\n\t\t}\n\t\tmsgIndex++;\n\t}\n\n\treturn messages;\n}\n\n// =============================================================================\n// Tool conversion\n// =============================================================================\n\nexport function convertResponsesTools(tools: Tool[], options?: ConvertResponsesToolsOptions): OpenAITool[] {\n\tconst strict = options?.strict === undefined ? false : options.strict;\n\treturn tools.map((tool) => ({\n\t\ttype: \"function\",\n\t\tname: tool.name,\n\t\tdescription: tool.description,\n\t\tparameters: tool.parameters as any, // TypeBox already generates JSON Schema\n\t\tstrict,\n\t}));\n}\n\n// =============================================================================\n// Stream processing\n// =============================================================================\n\nexport async function processResponsesStream<TApi extends Api>(\n\topenaiStream: AsyncIterable<ResponseStreamEvent>,\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n\tmodel: Model<TApi>,\n\toptions?: OpenAIResponsesStreamOptions,\n): Promise<void> {\n\tlet currentItem: ResponseReasoningItem | ResponseOutputMessage | ResponseFunctionToolCall | null = null;\n\tlet currentBlock: ThinkingContent | TextContent | (ToolCall & { partialJson: string }) | null = null;\n\tlet sawTerminalResponseEvent = false;\n\tconst blocks = output.content;\n\tconst blockIndex = () => blocks.length - 1;\n\tconst ensureMessageOutputTextPart = (): ResponseOutputText | undefined => {\n\t\tif (currentItem?.type !== \"message\") return undefined;\n\t\tconst lastPart = currentItem.content[currentItem.content.length - 1];\n\t\tif (lastPart?.type === \"output_text\") return lastPart;\n\t\tconst part: ResponseOutputText = { type: \"output_text\", text: \"\", annotations: [] };\n\t\tcurrentItem.content.push(part);\n\t\treturn part;\n\t};\n\tconst ensureMessageRefusalPart = (): ResponseOutputRefusal | undefined => {\n\t\tif (currentItem?.type !== \"message\") return undefined;\n\t\tconst lastPart = currentItem.content[currentItem.content.length - 1];\n\t\tif (lastPart?.type === \"refusal\") return lastPart;\n\t\tconst part: ResponseOutputRefusal = { type: \"refusal\", refusal: \"\" };\n\t\tcurrentItem.content.push(part);\n\t\treturn part;\n\t};\n\tconst finalizeResponse = (\n\t\tresponse: Extract<ResponseStreamEvent, { type: \"response.completed\" | \"response.incomplete\" }>[\"response\"],\n\t): void => {\n\t\tsawTerminalResponseEvent = true;\n\t\tif (response?.id) {\n\t\t\toutput.responseId = response.id;\n\t\t}\n\t\tif (response?.usage) {\n\t\t\tconst inputDetails = response.usage.input_tokens_details as InputTokenDetailsWithOrchestration | undefined;\n\t\t\tconst outputDetails = response.usage.output_tokens_details as OutputTokenDetailsWithOrchestration | undefined;\n\t\t\tconst cachedTokens = inputDetails?.cached_tokens || 0;\n\t\t\tlet inputTokens = (response.usage.input_tokens || 0) - cachedTokens;\n\t\t\tlet outputTokens = response.usage.output_tokens || 0;\n\t\t\tlet cacheReadTokens = cachedTokens;\n\t\t\tlet totalTokens = response.usage.total_tokens || 0;\n\t\t\tif (model.provider === \"fugu\") {\n\t\t\t\tconst orchestrationInputTokens = inputDetails?.orchestration_input_tokens || 0;\n\t\t\t\tconst orchestrationInputCachedTokens = inputDetails?.orchestration_input_cached_tokens || 0;\n\t\t\t\tconst orchestrationOutputTokens = outputDetails?.orchestration_output_tokens || 0;\n\t\t\t\tinputTokens += orchestrationInputTokens;\n\t\t\t\tcacheReadTokens += orchestrationInputCachedTokens;\n\t\t\t\toutputTokens += orchestrationOutputTokens;\n\t\t\t\ttotalTokens += orchestrationInputTokens + orchestrationInputCachedTokens + orchestrationOutputTokens;\n\t\t\t}\n\t\t\toutput.usage = {\n\t\t\t\t// OpenAI includes cached tokens in input_tokens, so subtract to get non-cached input.\n\t\t\t\t// Sakana Fugu Ultra also reports billable orchestration tokens in token details fields.\n\t\t\t\t// Source: https://console.sakana.ai/pricing#usage-field-details\n\t\t\t\tinput: inputTokens,\n\t\t\t\toutput: outputTokens,\n\t\t\t\tcacheRead: cacheReadTokens,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: (response.usage as any).cost || 0 },\n\t\t\t};\n\t\t}\n\t\tcalculateCost(model, output.usage, {\n\t\t\t// response.usage is absent on some streams; this call sits outside the guard above.\n\t\t\tproviderSuppliedTotal: Boolean((response.usage as { cost?: number } | undefined)?.cost),\n\t\t});\n\t\tapplyFuguUltraPricing(model, output.usage);\n\t\tif (options?.applyServiceTierPricing) {\n\t\t\tconst serviceTier = options.resolveServiceTier\n\t\t\t\t? options.resolveServiceTier(response?.service_tier, options.serviceTier)\n\t\t\t\t: (response?.service_tier ?? options.serviceTier);\n\t\t\toptions.applyServiceTierPricing(output.usage, serviceTier);\n\t\t}\n\t\t// Map status to stop reason\n\t\toutput.stopReason = mapStopReason(response?.status);\n\t\tif (output.content.some((b) => b.type === \"toolCall\") && output.stopReason === \"stop\") {\n\t\t\toutput.stopReason = \"toolUse\";\n\t\t}\n\t};\n\n\tfor await (const event of openaiStream) {\n\t\tif (event.type === \"response.created\") {\n\t\t\toutput.responseId = event.response.id;\n\t\t} else if (event.type === \"response.output_item.added\") {\n\t\t\tconst item = event.item;\n\t\t\tif (item.type === \"reasoning\") {\n\t\t\t\tcurrentItem = item;\n\t\t\t\tcurrentBlock = { type: \"thinking\", thinking: \"\" };\n\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\tstream.push({ type: \"thinking_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t} else if (item.type === \"message\") {\n\t\t\t\tcurrentItem = item;\n\t\t\t\tcurrentBlock = { type: \"text\", text: \"\" };\n\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\tstream.push({ type: \"text_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t} else if (item.type === \"function_call\") {\n\t\t\t\tcurrentItem = item;\n\t\t\t\tcurrentBlock = {\n\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\tid: `${item.call_id}|${item.id}`,\n\t\t\t\t\tname: item.name,\n\t\t\t\t\targuments: {},\n\t\t\t\t\tpartialJson: item.arguments || \"\",\n\t\t\t\t};\n\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\tstream.push({ type: \"toolcall_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t}\n\t\t} else if (event.type === \"response.reasoning_summary_part.added\") {\n\t\t\tif (currentItem && currentItem.type === \"reasoning\") {\n\t\t\t\tcurrentItem.summary = currentItem.summary || [];\n\t\t\t\tcurrentItem.summary.push(event.part);\n\t\t\t}\n\t\t} else if (event.type === \"response.reasoning_summary_text.delta\") {\n\t\t\tif (currentItem?.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tcurrentItem.summary = currentItem.summary || [];\n\t\t\t\tconst lastPart = currentItem.summary[currentItem.summary.length - 1];\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tcurrentBlock.thinking += event.delta;\n\t\t\t\t\tlastPart.text += event.delta;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta: event.delta,\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} else if (event.type === \"response.reasoning_summary_part.done\") {\n\t\t\tif (currentItem?.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tcurrentItem.summary = currentItem.summary || [];\n\t\t\t\tconst lastPart = currentItem.summary[currentItem.summary.length - 1];\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tcurrentBlock.thinking += \"\\n\\n\";\n\t\t\t\t\tlastPart.text += \"\\n\\n\";\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta: \"\\n\\n\",\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} else if (event.type === \"response.reasoning_text.delta\") {\n\t\t\tif (currentItem?.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tcurrentBlock.thinking += event.delta;\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tdelta: event.delta,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (event.type === \"response.content_part.added\") {\n\t\t\tif (currentItem?.type === \"message\") {\n\t\t\t\tcurrentItem.content = currentItem.content || [];\n\t\t\t\t// Filter out ReasoningText, only accept output_text and refusal\n\t\t\t\tif (event.part.type === \"output_text\" || event.part.type === \"refusal\") {\n\t\t\t\t\tcurrentItem.content.push(event.part);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (event.type === \"response.output_text.delta\") {\n\t\t\tif (currentItem?.type === \"message\" && currentBlock?.type === \"text\") {\n\t\t\t\tconst lastPart = ensureMessageOutputTextPart();\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tcurrentBlock.text += event.delta;\n\t\t\t\t\tlastPart.text += event.delta;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta: event.delta,\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} else if (event.type === \"response.refusal.delta\") {\n\t\t\tif (currentItem?.type === \"message\" && currentBlock?.type === \"text\") {\n\t\t\t\tconst lastPart = ensureMessageRefusalPart();\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tcurrentBlock.text += event.delta;\n\t\t\t\t\tlastPart.refusal += event.delta;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta: event.delta,\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} else if (event.type === \"response.function_call_arguments.delta\") {\n\t\t\tif (currentItem?.type === \"function_call\" && currentBlock?.type === \"toolCall\") {\n\t\t\t\tcurrentBlock.partialJson += event.delta;\n\t\t\t\tcurrentBlock.arguments = parseStreamingJson(currentBlock.partialJson);\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tdelta: event.delta,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (event.type === \"response.function_call_arguments.done\") {\n\t\t\tif (currentItem?.type === \"function_call\" && currentBlock?.type === \"toolCall\") {\n\t\t\t\tconst previousPartialJson = currentBlock.partialJson;\n\t\t\t\tcurrentBlock.partialJson = event.arguments;\n\t\t\t\tcurrentBlock.arguments = parseStreamingJson(currentBlock.partialJson);\n\n\t\t\t\tif (event.arguments.startsWith(previousPartialJson)) {\n\t\t\t\t\tconst delta = event.arguments.slice(previousPartialJson.length);\n\t\t\t\t\tif (delta.length > 0) {\n\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\tdelta,\n\t\t\t\t\t\t\tpartial: output,\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} else if (event.type === \"response.output_item.done\") {\n\t\t\tconst item = event.item;\n\n\t\t\tif (item.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tconst summaryText = item.summary?.map((s) => s.text).join(\"\\n\\n\") || \"\";\n\t\t\t\tconst contentText = item.content?.map((c) => c.text).join(\"\\n\\n\") || \"\";\n\t\t\t\tcurrentBlock.thinking = summaryText || contentText || currentBlock.thinking;\n\t\t\t\tcurrentBlock.thinkingSignature = JSON.stringify(item);\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tcontent: currentBlock.thinking,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t\tcurrentBlock = null;\n\t\t\t} else if (item.type === \"message\" && currentBlock?.type === \"text\") {\n\t\t\t\tcurrentBlock.text = item.content.map((c) => (c.type === \"output_text\" ? c.text : c.refusal)).join(\"\");\n\t\t\t\tcurrentBlock.textSignature = encodeTextSignatureV1(item.id, item.phase ?? undefined);\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tcontent: currentBlock.text,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t\tcurrentBlock = null;\n\t\t\t} else if (item.type === \"function_call\") {\n\t\t\t\tconst args =\n\t\t\t\t\tcurrentBlock?.type === \"toolCall\" && currentBlock.partialJson\n\t\t\t\t\t\t? parseStreamingJson(currentBlock.partialJson)\n\t\t\t\t\t\t: parseStreamingJson(item.arguments || \"{}\");\n\n\t\t\t\tlet toolCall: ToolCall;\n\t\t\t\tif (currentBlock?.type === \"toolCall\") {\n\t\t\t\t\t// Finalize in-place and strip the scratch buffer so replay only\n\t\t\t\t\t// carries parsed arguments.\n\t\t\t\t\tcurrentBlock.arguments = args;\n\t\t\t\t\tdelete (currentBlock as { partialJson?: string }).partialJson;\n\t\t\t\t\ttoolCall = currentBlock;\n\t\t\t\t} else {\n\t\t\t\t\ttoolCall = {\n\t\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\t\tid: `${item.call_id}|${item.id}`,\n\t\t\t\t\t\tname: item.name,\n\t\t\t\t\t\targuments: args,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tcurrentBlock = null;\n\t\t\t\tstream.push({ type: \"toolcall_end\", contentIndex: blockIndex(), toolCall, partial: output });\n\t\t\t}\n\t\t} else if (event.type === \"response.completed\" || event.type === \"response.incomplete\") {\n\t\t\tfinalizeResponse(event.response);\n\t\t} else if (event.type === \"error\") {\n\t\t\tthrow new Error(`Error Code ${event.code}: ${event.message}` || \"Unknown error\");\n\t\t} else if (event.type === \"response.failed\") {\n\t\t\tsawTerminalResponseEvent = true;\n\t\t\tconst error = event.response?.error;\n\t\t\tconst details = event.response?.incomplete_details;\n\t\t\tconst msg = error\n\t\t\t\t? `${error.code || \"unknown\"}: ${error.message || \"no message\"}`\n\t\t\t\t: details?.reason\n\t\t\t\t\t? `incomplete: ${details.reason}`\n\t\t\t\t\t: \"Unknown error (no error details in response)\";\n\t\t\tthrow new Error(msg);\n\t\t}\n\t}\n\tif (!sawTerminalResponseEvent) {\n\t\tthrow new Error(\"OpenAI Responses stream ended before a terminal response event\");\n\t}\n}\n\nfunction mapStopReason(status: OpenAI.Responses.ResponseStatus | undefined): StopReason {\n\tif (!status) return \"stop\";\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn \"stop\";\n\t\tcase \"incomplete\":\n\t\t\treturn \"length\";\n\t\tcase \"failed\":\n\t\tcase \"cancelled\":\n\t\t\treturn \"error\";\n\t\t// These two are wonky ...\n\t\tcase \"in_progress\":\n\t\tcase \"queued\":\n\t\t\treturn \"stop\";\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = status;\n\t\t\tthrow new Error(`Unhandled stop reason: ${_exhaustive}`);\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"openai-responses-shared.js","sourceRoot":"","sources":["../../src/providers/openai-responses-shared.ts"],"names":[],"mappings":"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","sourcesContent":["import type OpenAI from \"openai\";\nimport type {\n\tTool as OpenAITool,\n\tResponseCreateParamsStreaming,\n\tResponseFunctionCallOutputItemList,\n\tResponseFunctionToolCall,\n\tResponseInput,\n\tResponseInputContent,\n\tResponseInputImage,\n\tResponseInputText,\n\tResponseOutputMessage,\n\tResponseOutputRefusal,\n\tResponseOutputText,\n\tResponseReasoningItem,\n\tResponseStreamEvent,\n} from \"openai/resources/responses/responses.js\";\nimport { calculateCost } from \"../models.ts\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tContext,\n\tImageContent,\n\tModel,\n\tStopReason,\n\tTextContent,\n\tTextSignatureV1,\n\tThinkingContent,\n\tTool,\n\tToolCall,\n\tUsage,\n} from \"../types.ts\";\nimport type { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { shortHash } from \"../utils/hash.ts\";\nimport { parseStreamingJson } from \"../utils/json-parse.ts\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.ts\";\nimport { transformMessages } from \"./transform-messages.ts\";\n\n// =============================================================================\n// Utilities\n// =============================================================================\n\nfunction encodeTextSignatureV1(id: string, phase?: TextSignatureV1[\"phase\"]): string {\n\tconst payload: TextSignatureV1 = { v: 1, id };\n\tif (phase) payload.phase = phase;\n\treturn JSON.stringify(payload);\n}\n\nfunction parseTextSignature(\n\tsignature: string | undefined,\n): { id: string; phase?: TextSignatureV1[\"phase\"] } | undefined {\n\tif (!signature) return undefined;\n\tif (signature.startsWith(\"{\")) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(signature) as Partial<TextSignatureV1>;\n\t\t\tif (parsed.v === 1 && typeof parsed.id === \"string\") {\n\t\t\t\tif (parsed.phase === \"commentary\" || parsed.phase === \"final_answer\") {\n\t\t\t\t\treturn { id: parsed.id, phase: parsed.phase };\n\t\t\t\t}\n\t\t\t\treturn { id: parsed.id };\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to legacy plain-string handling.\n\t\t}\n\t}\n\treturn { id: signature };\n}\n\nexport interface OpenAIResponsesStreamOptions {\n\tserviceTier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\tresolveServiceTier?: (\n\t\tresponseServiceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\t\trequestServiceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\t) => ResponseCreateParamsStreaming[\"service_tier\"] | undefined;\n\tapplyServiceTierPricing?: (\n\t\tusage: Usage,\n\t\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\t) => void;\n}\n\nexport interface ConvertResponsesToolsOptions {\n\tstrict?: boolean | null;\n}\n\ninterface InputTokenDetailsWithOrchestration {\n\tcached_tokens?: number;\n\torchestration_input_tokens?: number;\n\torchestration_input_cached_tokens?: number;\n}\n\ninterface OutputTokenDetailsWithOrchestration {\n\torchestration_output_tokens?: number;\n}\n\nfunction applyFuguUltraPricing<TApi extends Api>(model: Model<TApi>, usage: Usage): void {\n\tif (model.provider !== \"fugu\" || model.id !== \"fugu-ultra\") return;\n\n\t// Sakana pricing has a higher Fugu Ultra tier once context exceeds 272K tokens.\n\t// Source: https://console.sakana.ai/pricing\n\tconst highContext = usage.input + usage.cacheRead > 272_000;\n\tconst inputRate = highContext ? 10 : 5;\n\tconst outputRate = highContext ? 45 : 30;\n\tconst cacheReadRate = highContext ? 1 : 0.5;\n\tusage.cost.input = (inputRate / 1_000_000) * usage.input;\n\tusage.cost.output = (outputRate / 1_000_000) * usage.output;\n\tusage.cost.cacheRead = (cacheReadRate / 1_000_000) * usage.cacheRead;\n\tusage.cost.cacheWrite = 0;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead;\n}\n\n// =============================================================================\n// Message conversion\n// =============================================================================\n\nexport function buildResponsesInstructions(context: Context): string | undefined {\n\treturn context.systemPrompt ? sanitizeSurrogates(context.systemPrompt) : undefined;\n}\n\nexport function convertResponsesMessages<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\tallowedToolCallProviders: ReadonlySet<string>,\n): ResponseInput {\n\tconst messages: ResponseInput = [];\n\n\tconst normalizeIdPart = (part: string): string => {\n\t\tconst sanitized = part.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n\t\tconst normalized = sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;\n\t\treturn normalized.replace(/_+$/, \"\");\n\t};\n\n\tconst buildForeignResponsesItemId = (itemId: string): string => {\n\t\tconst normalized = `fc_${shortHash(itemId)}`;\n\t\treturn normalized.length > 64 ? normalized.slice(0, 64) : normalized;\n\t};\n\n\tconst normalizeToolCallId = (id: string, _targetModel: Model<TApi>, source: AssistantMessage): string => {\n\t\tif (!allowedToolCallProviders.has(model.provider)) return normalizeIdPart(id);\n\t\tif (!id.includes(\"|\")) return normalizeIdPart(id);\n\t\tconst [callId, itemId] = id.split(\"|\");\n\t\tconst normalizedCallId = normalizeIdPart(callId);\n\t\tconst isForeignToolCall = source.provider !== model.provider || source.api !== model.api;\n\t\tlet normalizedItemId = isForeignToolCall ? buildForeignResponsesItemId(itemId) : normalizeIdPart(itemId);\n\t\t// OpenAI Responses API requires item id to start with \"fc\"\n\t\tif (!normalizedItemId.startsWith(\"fc_\")) {\n\t\t\tnormalizedItemId = normalizeIdPart(`fc_${normalizedItemId}`);\n\t\t}\n\t\treturn `${normalizedCallId}|${normalizedItemId}`;\n\t};\n\n\tconst transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);\n\n\tlet msgIndex = 0;\n\tfor (const msg of transformedMessages) {\n\t\tif (msg.role === \"user\") {\n\t\t\tif (typeof msg.content === \"string\") {\n\t\t\t\tmessages.push({\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: [{ type: \"input_text\", text: sanitizeSurrogates(msg.content) }],\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst content: ResponseInputContent[] = msg.content.map((item): ResponseInputContent => {\n\t\t\t\t\tif (item.type === \"text\") {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttype: \"input_text\",\n\t\t\t\t\t\t\ttext: sanitizeSurrogates(item.text),\n\t\t\t\t\t\t} satisfies ResponseInputText;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: \"input_image\",\n\t\t\t\t\t\tdetail: \"auto\",\n\t\t\t\t\t\timage_url: `data:${item.mimeType};base64,${item.data}`,\n\t\t\t\t\t} satisfies ResponseInputImage;\n\t\t\t\t});\n\t\t\t\tif (content.length === 0) continue;\n\t\t\t\tmessages.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\tconst output: ResponseInput = [];\n\t\t\tconst assistantMsg = msg as AssistantMessage;\n\t\t\tconst isDifferentModel =\n\t\t\t\tassistantMsg.model !== model.id &&\n\t\t\t\tassistantMsg.provider === model.provider &&\n\t\t\t\tassistantMsg.api === model.api;\n\t\t\tlet textBlockIndex = 0;\n\n\t\t\tfor (const block of msg.content) {\n\t\t\t\tif (block.type === \"thinking\") {\n\t\t\t\t\tif (block.thinkingSignature) {\n\t\t\t\t\t\tconst reasoningItem = JSON.parse(block.thinkingSignature) as ResponseReasoningItem;\n\t\t\t\t\t\toutput.push(reasoningItem);\n\t\t\t\t\t}\n\t\t\t\t} else if (block.type === \"text\") {\n\t\t\t\t\tconst textBlock = block as TextContent;\n\t\t\t\t\tconst parsedSignature = parseTextSignature(textBlock.textSignature);\n\t\t\t\t\tconst fallbackMessageId =\n\t\t\t\t\t\ttextBlockIndex === 0 ? `msg_pi_${msgIndex}` : `msg_pi_${msgIndex}_${textBlockIndex}`;\n\t\t\t\t\ttextBlockIndex++;\n\t\t\t\t\t// OpenAI requires id to be max 64 characters\n\t\t\t\t\tlet msgId = parsedSignature?.id;\n\t\t\t\t\tif (!msgId) {\n\t\t\t\t\t\tmsgId = fallbackMessageId;\n\t\t\t\t\t} else if (msgId.length > 64) {\n\t\t\t\t\t\tmsgId = `msg_${shortHash(msgId)}`;\n\t\t\t\t\t}\n\t\t\t\t\toutput.push({\n\t\t\t\t\t\ttype: \"message\",\n\t\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\t\tcontent: [{ type: \"output_text\", text: sanitizeSurrogates(textBlock.text), annotations: [] }],\n\t\t\t\t\t\tstatus: \"completed\",\n\t\t\t\t\t\tid: msgId,\n\t\t\t\t\t\tphase: parsedSignature?.phase,\n\t\t\t\t\t} satisfies ResponseOutputMessage);\n\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\tconst toolCall = block as ToolCall;\n\t\t\t\t\tconst [callId, itemIdRaw] = toolCall.id.split(\"|\");\n\t\t\t\t\tlet itemId: string | undefined = itemIdRaw;\n\n\t\t\t\t\t// For different-model messages, set id to undefined to avoid pairing validation.\n\t\t\t\t\t// OpenAI tracks which fc_xxx IDs were paired with rs_xxx reasoning items.\n\t\t\t\t\t// By omitting the id, we avoid triggering that validation (like cross-provider does).\n\t\t\t\t\tif (isDifferentModel && itemId?.startsWith(\"fc_\")) {\n\t\t\t\t\t\titemId = undefined;\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.push({\n\t\t\t\t\t\ttype: \"function_call\",\n\t\t\t\t\t\tid: itemId,\n\t\t\t\t\t\tcall_id: callId,\n\t\t\t\t\t\tname: toolCall.name,\n\t\t\t\t\t\targuments: JSON.stringify(toolCall.arguments),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (output.length === 0) continue;\n\t\t\tmessages.push(...output);\n\t\t} else if (msg.role === \"toolResult\") {\n\t\t\tconst textResult = msg.content\n\t\t\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\\n\");\n\t\t\tconst hasImages = msg.content.some((c): c is ImageContent => c.type === \"image\");\n\t\t\tconst hasText = textResult.length > 0;\n\t\t\tconst [callId] = msg.toolCallId.split(\"|\");\n\n\t\t\tlet output: string | ResponseFunctionCallOutputItemList;\n\t\t\tif (hasImages && model.input.includes(\"image\")) {\n\t\t\t\tconst contentParts: ResponseFunctionCallOutputItemList = [];\n\n\t\t\t\tif (hasText) {\n\t\t\t\t\tcontentParts.push({\n\t\t\t\t\t\ttype: \"input_text\",\n\t\t\t\t\t\ttext: sanitizeSurrogates(textResult),\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tfor (const block of msg.content) {\n\t\t\t\t\tif (block.type === \"image\") {\n\t\t\t\t\t\tcontentParts.push({\n\t\t\t\t\t\t\ttype: \"input_image\",\n\t\t\t\t\t\t\tdetail: \"auto\",\n\t\t\t\t\t\t\timage_url: `data:${block.mimeType};base64,${block.data}`,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\toutput = contentParts;\n\t\t\t} else {\n\t\t\t\toutput = sanitizeSurrogates(hasText ? textResult : \"(see attached image)\");\n\t\t\t}\n\n\t\t\tmessages.push({\n\t\t\t\ttype: \"function_call_output\",\n\t\t\t\tcall_id: callId,\n\t\t\t\toutput,\n\t\t\t});\n\t\t}\n\t\tmsgIndex++;\n\t}\n\n\treturn messages;\n}\n\n// =============================================================================\n// Tool conversion\n// =============================================================================\n\nexport function convertResponsesTools(tools: Tool[], options?: ConvertResponsesToolsOptions): OpenAITool[] {\n\tconst strict = options?.strict === undefined ? false : options.strict;\n\treturn tools.map((tool) => ({\n\t\ttype: \"function\",\n\t\tname: tool.name,\n\t\tdescription: tool.description,\n\t\tparameters: tool.parameters as any, // TypeBox already generates JSON Schema\n\t\tstrict,\n\t}));\n}\n\n// =============================================================================\n// Stream processing\n// =============================================================================\n\nconst REASONING_SUMMARY_DELIMITER_ONLY = /^<!--\\s*-->$/;\n\nfunction isReasoningSummaryDelimiterOnly(text: string): boolean {\n\treturn REASONING_SUMMARY_DELIMITER_ONLY.test(text.trim());\n}\n\nfunction normalizeReasoningSummaryText(parts: readonly { text?: string }[] | undefined): string {\n\treturn (parts ?? [])\n\t\t.map((part) => part.text ?? \"\")\n\t\t.filter((text) => text.trim().length > 0 && !isReasoningSummaryDelimiterOnly(text))\n\t\t.join(\"\\n\\n\");\n}\n\nexport async function processResponsesStream<TApi extends Api>(\n\topenaiStream: AsyncIterable<ResponseStreamEvent>,\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n\tmodel: Model<TApi>,\n\toptions?: OpenAIResponsesStreamOptions,\n): Promise<void> {\n\tlet currentItem: ResponseReasoningItem | ResponseOutputMessage | ResponseFunctionToolCall | null = null;\n\tlet currentBlock: ThinkingContent | TextContent | (ToolCall & { partialJson: string }) | null = null;\n\tlet currentReasoningSummaryPartText = \"\";\n\tlet sawTerminalResponseEvent = false;\n\tconst blocks = output.content;\n\tconst blockIndex = () => blocks.length - 1;\n\tconst ensureMessageOutputTextPart = (): ResponseOutputText | undefined => {\n\t\tif (currentItem?.type !== \"message\") return undefined;\n\t\tconst lastPart = currentItem.content[currentItem.content.length - 1];\n\t\tif (lastPart?.type === \"output_text\") return lastPart;\n\t\tconst part: ResponseOutputText = { type: \"output_text\", text: \"\", annotations: [] };\n\t\tcurrentItem.content.push(part);\n\t\treturn part;\n\t};\n\tconst ensureMessageRefusalPart = (): ResponseOutputRefusal | undefined => {\n\t\tif (currentItem?.type !== \"message\") return undefined;\n\t\tconst lastPart = currentItem.content[currentItem.content.length - 1];\n\t\tif (lastPart?.type === \"refusal\") return lastPart;\n\t\tconst part: ResponseOutputRefusal = { type: \"refusal\", refusal: \"\" };\n\t\tcurrentItem.content.push(part);\n\t\treturn part;\n\t};\n\tconst finalizeResponse = (\n\t\tresponse: Extract<ResponseStreamEvent, { type: \"response.completed\" | \"response.incomplete\" }>[\"response\"],\n\t): void => {\n\t\tsawTerminalResponseEvent = true;\n\t\tif (response?.id) {\n\t\t\toutput.responseId = response.id;\n\t\t}\n\t\tif (response?.usage) {\n\t\t\tconst inputDetails = response.usage.input_tokens_details as InputTokenDetailsWithOrchestration | undefined;\n\t\t\tconst outputDetails = response.usage.output_tokens_details as OutputTokenDetailsWithOrchestration | undefined;\n\t\t\tconst cachedTokens = inputDetails?.cached_tokens || 0;\n\t\t\tlet inputTokens = (response.usage.input_tokens || 0) - cachedTokens;\n\t\t\tlet outputTokens = response.usage.output_tokens || 0;\n\t\t\tlet cacheReadTokens = cachedTokens;\n\t\t\tlet totalTokens = response.usage.total_tokens || 0;\n\t\t\tif (model.provider === \"fugu\") {\n\t\t\t\tconst orchestrationInputTokens = inputDetails?.orchestration_input_tokens || 0;\n\t\t\t\tconst orchestrationInputCachedTokens = inputDetails?.orchestration_input_cached_tokens || 0;\n\t\t\t\tconst orchestrationOutputTokens = outputDetails?.orchestration_output_tokens || 0;\n\t\t\t\tinputTokens += orchestrationInputTokens;\n\t\t\t\tcacheReadTokens += orchestrationInputCachedTokens;\n\t\t\t\toutputTokens += orchestrationOutputTokens;\n\t\t\t\ttotalTokens += orchestrationInputTokens + orchestrationInputCachedTokens + orchestrationOutputTokens;\n\t\t\t}\n\t\t\toutput.usage = {\n\t\t\t\t// OpenAI includes cached tokens in input_tokens, so subtract to get non-cached input.\n\t\t\t\t// Sakana Fugu Ultra also reports billable orchestration tokens in token details fields.\n\t\t\t\t// Source: https://console.sakana.ai/pricing#usage-field-details\n\t\t\t\tinput: inputTokens,\n\t\t\t\toutput: outputTokens,\n\t\t\t\tcacheRead: cacheReadTokens,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: (response.usage as any).cost || 0 },\n\t\t\t};\n\t\t}\n\t\tcalculateCost(model, output.usage, {\n\t\t\t// response.usage is absent on some streams; this call sits outside the guard above.\n\t\t\tproviderSuppliedTotal: Boolean((response.usage as { cost?: number } | undefined)?.cost),\n\t\t});\n\t\tapplyFuguUltraPricing(model, output.usage);\n\t\tif (options?.applyServiceTierPricing) {\n\t\t\tconst serviceTier = options.resolveServiceTier\n\t\t\t\t? options.resolveServiceTier(response?.service_tier, options.serviceTier)\n\t\t\t\t: (response?.service_tier ?? options.serviceTier);\n\t\t\toptions.applyServiceTierPricing(output.usage, serviceTier);\n\t\t}\n\t\t// Map status to stop reason\n\t\toutput.stopReason = mapStopReason(response?.status);\n\t\tif (output.content.some((b) => b.type === \"toolCall\") && output.stopReason === \"stop\") {\n\t\t\toutput.stopReason = \"toolUse\";\n\t\t}\n\t};\n\n\tfor await (const event of openaiStream) {\n\t\tif (event.type === \"response.created\") {\n\t\t\toutput.responseId = event.response.id;\n\t\t} else if (event.type === \"response.output_item.added\") {\n\t\t\tconst item = event.item;\n\t\t\tif (item.type === \"reasoning\") {\n\t\t\t\tcurrentItem = item;\n\t\t\t\tcurrentBlock = { type: \"thinking\", thinking: \"\" };\n\t\t\t\tcurrentReasoningSummaryPartText = \"\";\n\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\tstream.push({ type: \"thinking_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t} else if (item.type === \"message\") {\n\t\t\t\tcurrentItem = item;\n\t\t\t\tcurrentBlock = { type: \"text\", text: \"\" };\n\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\tstream.push({ type: \"text_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t} else if (item.type === \"function_call\") {\n\t\t\t\tcurrentItem = item;\n\t\t\t\tcurrentBlock = {\n\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\tid: `${item.call_id}|${item.id}`,\n\t\t\t\t\tname: item.name,\n\t\t\t\t\targuments: {},\n\t\t\t\t\tpartialJson: item.arguments || \"\",\n\t\t\t\t};\n\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\tstream.push({ type: \"toolcall_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t}\n\t\t} else if (event.type === \"response.reasoning_summary_part.added\") {\n\t\t\tif (currentItem && currentItem.type === \"reasoning\") {\n\t\t\t\tcurrentItem.summary = currentItem.summary || [];\n\t\t\t\tcurrentItem.summary.push(event.part);\n\t\t\t\tcurrentReasoningSummaryPartText = event.part.text ?? \"\";\n\t\t\t}\n\t\t} else if (event.type === \"response.reasoning_summary_text.delta\") {\n\t\t\tif (currentItem?.type === \"reasoning\") {\n\t\t\t\tcurrentItem.summary = currentItem.summary || [];\n\t\t\t\tconst lastPart = currentItem.summary[currentItem.summary.length - 1];\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tlastPart.text += event.delta;\n\t\t\t\t\tcurrentReasoningSummaryPartText += event.delta;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (event.type === \"response.reasoning_summary_part.done\") {\n\t\t\tif (currentItem?.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tcurrentItem.summary = currentItem.summary || [];\n\t\t\t\tconst lastPart = currentItem.summary[currentItem.summary.length - 1];\n\t\t\t\tconst partText = lastPart?.text ?? currentReasoningSummaryPartText;\n\t\t\t\tif (partText.trim().length > 0 && !isReasoningSummaryDelimiterOnly(partText)) {\n\t\t\t\t\tconst delta = `${partText}\\n\\n`;\n\t\t\t\t\tcurrentBlock.thinking += delta;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tcurrentReasoningSummaryPartText = \"\";\n\t\t\t}\n\t\t} else if (event.type === \"response.reasoning_text.delta\") {\n\t\t\tif (currentItem?.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tcurrentBlock.thinking += event.delta;\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tdelta: event.delta,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (event.type === \"response.content_part.added\") {\n\t\t\tif (currentItem?.type === \"message\") {\n\t\t\t\tcurrentItem.content = currentItem.content || [];\n\t\t\t\t// Filter out ReasoningText, only accept output_text and refusal\n\t\t\t\tif (event.part.type === \"output_text\" || event.part.type === \"refusal\") {\n\t\t\t\t\tcurrentItem.content.push(event.part);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (event.type === \"response.output_text.delta\") {\n\t\t\tif (currentItem?.type === \"message\" && currentBlock?.type === \"text\") {\n\t\t\t\tconst lastPart = ensureMessageOutputTextPart();\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tcurrentBlock.text += event.delta;\n\t\t\t\t\tlastPart.text += event.delta;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta: event.delta,\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} else if (event.type === \"response.refusal.delta\") {\n\t\t\tif (currentItem?.type === \"message\" && currentBlock?.type === \"text\") {\n\t\t\t\tconst lastPart = ensureMessageRefusalPart();\n\t\t\t\tif (lastPart) {\n\t\t\t\t\tcurrentBlock.text += event.delta;\n\t\t\t\t\tlastPart.refusal += event.delta;\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tdelta: event.delta,\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} else if (event.type === \"response.function_call_arguments.delta\") {\n\t\t\tif (currentItem?.type === \"function_call\" && currentBlock?.type === \"toolCall\") {\n\t\t\t\tcurrentBlock.partialJson += event.delta;\n\t\t\t\tcurrentBlock.arguments = parseStreamingJson(currentBlock.partialJson);\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tdelta: event.delta,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (event.type === \"response.function_call_arguments.done\") {\n\t\t\tif (currentItem?.type === \"function_call\" && currentBlock?.type === \"toolCall\") {\n\t\t\t\tconst previousPartialJson = currentBlock.partialJson;\n\t\t\t\tcurrentBlock.partialJson = event.arguments;\n\t\t\t\tcurrentBlock.arguments = parseStreamingJson(currentBlock.partialJson);\n\n\t\t\t\tif (event.arguments.startsWith(previousPartialJson)) {\n\t\t\t\t\tconst delta = event.arguments.slice(previousPartialJson.length);\n\t\t\t\t\tif (delta.length > 0) {\n\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\tdelta,\n\t\t\t\t\t\t\tpartial: output,\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} else if (event.type === \"response.output_item.done\") {\n\t\t\tconst item = event.item;\n\n\t\t\tif (item.type === \"reasoning\" && currentBlock?.type === \"thinking\") {\n\t\t\t\tconst summaryText = normalizeReasoningSummaryText(item.summary);\n\t\t\t\tconst contentText = item.content?.map((c) => c.text).join(\"\\n\\n\") || \"\";\n\t\t\t\tcurrentBlock.thinking = summaryText || contentText || currentBlock.thinking;\n\t\t\t\tcurrentBlock.thinkingSignature = JSON.stringify(item);\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tcontent: currentBlock.thinking,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t\tcurrentBlock = null;\n\t\t\t} else if (item.type === \"message\" && currentBlock?.type === \"text\") {\n\t\t\t\tcurrentBlock.text = item.content.map((c) => (c.type === \"output_text\" ? c.text : c.refusal)).join(\"\");\n\t\t\t\tcurrentBlock.textSignature = encodeTextSignatureV1(item.id, item.phase ?? undefined);\n\t\t\t\tstream.push({\n\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\tcontent: currentBlock.text,\n\t\t\t\t\tpartial: output,\n\t\t\t\t});\n\t\t\t\tcurrentBlock = null;\n\t\t\t} else if (item.type === \"function_call\") {\n\t\t\t\tconst args =\n\t\t\t\t\tcurrentBlock?.type === \"toolCall\" && currentBlock.partialJson\n\t\t\t\t\t\t? parseStreamingJson(currentBlock.partialJson)\n\t\t\t\t\t\t: parseStreamingJson(item.arguments || \"{}\");\n\n\t\t\t\tlet toolCall: ToolCall;\n\t\t\t\tif (currentBlock?.type === \"toolCall\") {\n\t\t\t\t\t// Finalize in-place and strip the scratch buffer so replay only\n\t\t\t\t\t// carries parsed arguments.\n\t\t\t\t\tcurrentBlock.arguments = args;\n\t\t\t\t\tdelete (currentBlock as { partialJson?: string }).partialJson;\n\t\t\t\t\ttoolCall = currentBlock;\n\t\t\t\t} else {\n\t\t\t\t\ttoolCall = {\n\t\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\t\tid: `${item.call_id}|${item.id}`,\n\t\t\t\t\t\tname: item.name,\n\t\t\t\t\t\targuments: args,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tcurrentBlock = null;\n\t\t\t\tstream.push({ type: \"toolcall_end\", contentIndex: blockIndex(), toolCall, partial: output });\n\t\t\t}\n\t\t} else if (event.type === \"response.completed\" || event.type === \"response.incomplete\") {\n\t\t\tfinalizeResponse(event.response);\n\t\t} else if (event.type === \"error\") {\n\t\t\tthrow new Error(`Error Code ${event.code}: ${event.message}` || \"Unknown error\");\n\t\t} else if (event.type === \"response.failed\") {\n\t\t\tsawTerminalResponseEvent = true;\n\t\t\tconst error = event.response?.error;\n\t\t\tconst details = event.response?.incomplete_details;\n\t\t\tconst msg = error\n\t\t\t\t? `${error.code || \"unknown\"}: ${error.message || \"no message\"}`\n\t\t\t\t: details?.reason\n\t\t\t\t\t? `incomplete: ${details.reason}`\n\t\t\t\t\t: \"Unknown error (no error details in response)\";\n\t\t\tthrow new Error(msg);\n\t\t}\n\t}\n\tif (!sawTerminalResponseEvent) {\n\t\tthrow new Error(\"OpenAI Responses stream ended before a terminal response event\");\n\t}\n}\n\nfunction mapStopReason(status: OpenAI.Responses.ResponseStatus | undefined): StopReason {\n\tif (!status) return \"stop\";\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn \"stop\";\n\t\tcase \"incomplete\":\n\t\t\treturn \"length\";\n\t\tcase \"failed\":\n\t\tcase \"cancelled\":\n\t\t\treturn \"error\";\n\t\t// These two are wonky ...\n\t\tcase \"in_progress\":\n\t\tcase \"queued\":\n\t\t\treturn \"stop\";\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = status;\n\t\t\tthrow new Error(`Unhandled stop reason: ${_exhaustive}`);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -26,6 +26,7 @@ export interface ToolArgumentValidationOptions {
|
|
|
26
26
|
model?: string;
|
|
27
27
|
provider?: string;
|
|
28
28
|
telemetry?: (event: ToolArgumentValidationTelemetryEvent) => void;
|
|
29
|
+
/** Internal emergency diagnostic kill; user settings do not disable deterministic repair. */
|
|
29
30
|
repairEnabled?: boolean;
|
|
30
31
|
}
|
|
31
32
|
export declare class ToolArgumentValidationError extends Error {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAEN,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACvB,MAAM,2BAA2B,CAAC;AAQnC,MAAM,MAAM,6BAA6B,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;AAC7E,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAC9D,MAAM,MAAM,4BAA4B,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE9E,MAAM,WAAW,6BAA6B;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oCAAoC;IACpD,OAAO,EAAE,6BAA6B,CAAC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5B,YAAY,EAAE,yBAAyB,EAAE,CAAC;IAC1C,cAAc,EAAE,kBAAkB,EAAE,CAAC;IACrC,YAAY,CAAC,EAAE,6BAA6B,EAAE,CAAC;IAC/C,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,gBAAgB,EAAE,4BAA4B,CAAC;CAC/C;AAED,MAAM,WAAW,6BAA6B;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,oCAAoC,KAAK,IAAI,CAAC;IAClE,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,qBAAa,2BAA4B,SAAQ,KAAK;IACrD,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC,SAAgB,UAAU,EAAE,MAAM,CAAC;IAEnC,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAMhG;CACD;AAqTD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,IAAI,EAAE,EACb,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,6BAA6B,GACrC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACpC,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,6BAA6B,GACrC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsDzB","sourcesContent":["import { Compile } from \"typebox/compile\";\nimport type { TLocalizedValidationError } from \"typebox/error\";\nimport type { Tool, ToolCall } from \"../types.ts\";\nimport { analyzeToolArgumentErrors } from \"./tool-repair/analyzer.ts\";\nimport {\n\tformatToolRepairNote,\n\ttype ToolRepairFailureModeName,\n\ttype ToolRepairModeName,\n} from \"./tool-repair/registry.ts\";\nimport { repairToolArguments } from \"./tool-repair/repairer.ts\";\n\nconst validatorCache = new WeakMap<object, ReturnType<typeof Compile>>();\nconst EXPECTED_FRAGMENT_MAX_LENGTH = 320;\nconst RECEIVED_VALUE_MAX_LENGTH = 200;\nconst MISSING_VALUE = Symbol(\"missing\");\n\nexport type ToolArgumentValidationOutcome = \"clean\" | \"repaired\" | \"bounced\";\nexport type ToolArgumentTeachState = \"none\" | \"note\" | \"rule\";\nexport type ToolArgumentExecutionOutcome = \"not_run\" | \"succeeded\" | \"failed\";\n\nexport interface ToolArgumentFailureShapeEntry {\n\tpath: string;\n\texpectedType: string;\n\treceivedType: string;\n\tkeyword?: string;\n}\n\nexport interface ToolArgumentValidationTelemetryEvent {\n\toutcome: ToolArgumentValidationOutcome;\n\tprovider?: string;\n\tmodel?: string;\n\ttool: string;\n\tsource?: ToolCall[\"source\"];\n\tfailureModes: ToolRepairFailureModeName[];\n\trepairsApplied: ToolRepairModeName[];\n\tfailureShape?: ToolArgumentFailureShapeEntry[];\n\terrorKeywords?: string[];\n\ttaught: ToolArgumentTeachState;\n\texecutionOutcome: ToolArgumentExecutionOutcome;\n}\n\nexport interface ToolArgumentValidationOptions {\n\tmodel?: string;\n\tprovider?: string;\n\ttelemetry?: (event: ToolArgumentValidationTelemetryEvent) => void;\n\trepairEnabled?: boolean;\n}\n\nexport class ToolArgumentValidationError extends Error {\n\tpublic readonly toolName: string;\n\tpublic readonly signature: string;\n\tpublic readonly enrichment: string;\n\n\tconstructor(message: string, options: { toolName: string; signature: string; enrichment: string }) {\n\t\tsuper(message);\n\t\tthis.name = \"ToolArgumentValidationError\";\n\t\tthis.toolName = options.toolName;\n\t\tthis.signature = options.signature;\n\t\tthis.enrichment = options.enrichment;\n\t}\n}\n\nfunction emitToolArgumentValidationTelemetry(\n\toptions: ToolArgumentValidationOptions | undefined,\n\tevent: Omit<ToolArgumentValidationTelemetryEvent, \"model\" | \"provider\" | \"taught\" | \"executionOutcome\">,\n): void {\n\ttry {\n\t\toptions?.telemetry?.({\n\t\t\t...event,\n\t\t\tmodel: options.model,\n\t\t\tprovider: options.provider,\n\t\t\ttaught: \"none\",\n\t\t\texecutionOutcome: \"not_run\",\n\t\t});\n\t} catch {\n\t\t// Telemetry is observe-only; never fail validation because a sink failed.\n\t}\n}\n\nfunction uniqueRepairModes(modes: Iterable<ToolRepairModeName>): ToolRepairModeName[] {\n\treturn [...new Set(modes)];\n}\n\nfunction uniqueFailureModes(modes: Iterable<ToolRepairModeName>): ToolRepairFailureModeName[] {\n\tconst uniqueModes = uniqueRepairModes(modes);\n\treturn uniqueModes.length > 0 ? uniqueModes : [\"other\"];\n}\n\nfunction getValidator(schema: Tool[\"parameters\"]): ReturnType<typeof Compile> {\n\tconst key = schema as object;\n\tconst cached = validatorCache.get(key);\n\tif (cached) {\n\t\treturn cached;\n\t}\n\tconst validator = Compile(schema);\n\tvalidatorCache.set(key, validator);\n\treturn validator;\n}\n\nfunction formatValidationPath(error: TLocalizedValidationError): string {\n\tif (error.keyword === \"required\") {\n\t\tconst requiredProperties = (error.params as { requiredProperties?: string[] }).requiredProperties;\n\t\tconst requiredProperty = requiredProperties?.[0];\n\t\tif (requiredProperty) {\n\t\t\tconst basePath = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\t\t\treturn basePath ? `${basePath}.${requiredProperty}` : requiredProperty;\n\t\t}\n\t}\n\tconst path = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\treturn path || \"root\";\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value)\n\t\t? (value as Record<string, unknown>)\n\t\t: undefined;\n}\n\nfunction truncateText(text: string, maxLength: number): string {\n\tif (text.length <= maxLength) {\n\t\treturn text;\n\t}\n\treturn `${text.slice(0, maxLength)}...[truncated]`;\n}\n\nfunction formatCompactJson(value: unknown, maxLength: number): string {\n\tif (value === MISSING_VALUE) {\n\t\treturn \"<missing>\";\n\t}\n\tif (value === undefined) {\n\t\treturn \"undefined\";\n\t}\n\treturn truncateText(JSON.stringify(value), maxLength);\n}\n\nfunction validationPathSegments(error: TLocalizedValidationError): string[] {\n\tconst path = formatValidationPath(error);\n\treturn path === \"root\" ? [] : path.split(\".\");\n}\n\nfunction schemaAtPath(schema: unknown, pathSegments: readonly string[]): unknown {\n\tlet current: unknown = schema;\n\tfor (const segment of pathSegments) {\n\t\tconst record = asRecord(current);\n\t\tif (!record) {\n\t\t\treturn current;\n\t\t}\n\n\t\tconst properties = asRecord(record.properties);\n\t\tif (properties && segment in properties) {\n\t\t\tcurrent = properties[segment];\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (record.items !== undefined) {\n\t\t\tcurrent = record.items;\n\t\t\tcontinue;\n\t\t}\n\n\t\treturn current;\n\t}\n\treturn current;\n}\n\nfunction receivedValueAtPath(args: unknown, pathSegments: readonly string[]): unknown {\n\tlet current: unknown = args;\n\tfor (const segment of pathSegments) {\n\t\tconst record = asRecord(current);\n\t\tif (record) {\n\t\t\tif (!(segment in record)) {\n\t\t\t\treturn MISSING_VALUE;\n\t\t\t}\n\t\t\tcurrent = record[segment];\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (Array.isArray(current)) {\n\t\t\tconst index = Number(segment);\n\t\t\tif (!Number.isInteger(index) || index < 0 || index >= current.length) {\n\t\t\t\treturn MISSING_VALUE;\n\t\t\t}\n\t\t\tcurrent = current[index];\n\t\t\tcontinue;\n\t\t}\n\n\t\treturn MISSING_VALUE;\n\t}\n\treturn current;\n}\n\nfunction receivedTypeOf(value: unknown): string {\n\tif (value === MISSING_VALUE) return \"missing\";\n\tif (value === null) return \"null\";\n\tif (Array.isArray(value)) return \"array\";\n\treturn typeof value;\n}\n\nfunction expectedTypeOf(schema: unknown): string {\n\tconst record = asRecord(schema);\n\tif (!record) return \"unknown\";\n\tif (Array.isArray(record.type)) return record.type.filter((type) => typeof type === \"string\").join(\"|\") || \"unknown\";\n\tif (typeof record.type === \"string\") return record.type;\n\tif (literalValues(record)) return \"enum\";\n\tif (record.properties !== undefined) return \"object\";\n\tif (record.items !== undefined) return \"array\";\n\treturn \"unknown\";\n}\n\nfunction formatFailureShape(\n\terrors: readonly TLocalizedValidationError[],\n\targs: unknown,\n\tschema: unknown,\n): ToolArgumentFailureShapeEntry[] {\n\tconst seen = new Set<string>();\n\tconst shape: ToolArgumentFailureShapeEntry[] = [];\n\tfor (const error of errors) {\n\t\tconst path = formatValidationPath(error);\n\t\tconst pathSegments = path === \"root\" ? [] : path.split(\".\");\n\t\tconst expectedSchema = schemaAtPath(schema, pathSegments);\n\t\tconst value = receivedValueAtPath(args, pathSegments);\n\t\tconst entry = {\n\t\t\tpath,\n\t\t\texpectedType: expectedTypeOf(expectedSchema),\n\t\t\treceivedType: receivedTypeOf(value),\n\t\t\tkeyword: error.keyword,\n\t\t};\n\t\tconst key = `${entry.path}\\0${entry.expectedType}\\0${entry.receivedType}\\0${entry.keyword}`;\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tshape.push(entry);\n\t}\n\treturn shape;\n}\n\nfunction errorKeywords(errors: readonly TLocalizedValidationError[]): string[] {\n\treturn [...new Set(errors.map((error) => error.keyword))].sort();\n}\n\nfunction literalValues(schema: unknown): unknown[] | undefined {\n\tconst record = asRecord(schema);\n\tif (!record) {\n\t\treturn undefined;\n\t}\n\tif (Array.isArray(record.enum)) {\n\t\treturn record.enum;\n\t}\n\tif (record.const !== undefined) {\n\t\treturn [record.const];\n\t}\n\tconst anyOf = Array.isArray(record.anyOf) ? record.anyOf : Array.isArray(record.oneOf) ? record.oneOf : undefined;\n\tif (anyOf) {\n\t\tconst values: unknown[] = [];\n\t\tfor (const option of anyOf) {\n\t\t\tconst optionRecord = asRecord(option);\n\t\t\tif (!optionRecord || optionRecord.const === undefined) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tvalues.push(optionRecord.const);\n\t\t}\n\t\treturn values;\n\t}\n\treturn undefined;\n}\n\nfunction compactSchemaFragment(schema: unknown): Record<string, unknown> {\n\tconst record = asRecord(schema);\n\tif (!record) {\n\t\treturn {};\n\t}\n\n\tconst fragment: Record<string, unknown> = {};\n\tconst values = literalValues(record);\n\tif (values) {\n\t\tfragment.enum = values;\n\t\treturn fragment;\n\t}\n\n\tfor (const key of [\"type\", \"required\", \"minimum\", \"maximum\", \"minLength\", \"maxLength\", \"format\"] as const) {\n\t\tif (record[key] !== undefined) {\n\t\t\tfragment[key] = record[key];\n\t\t}\n\t}\n\n\tconst properties = asRecord(record.properties);\n\tif (properties) {\n\t\tfragment.properties = Object.keys(properties);\n\t}\n\tif (record.items !== undefined) {\n\t\tfragment.items = compactSchemaFragment(record.items);\n\t}\n\treturn fragment;\n}\n\nfunction minimalExample(schema: unknown): unknown {\n\tconst record = asRecord(schema);\n\tif (!record) {\n\t\treturn undefined;\n\t}\n\tif (record.default !== undefined) {\n\t\treturn record.default;\n\t}\n\tconst values = literalValues(record);\n\tif (values?.length) {\n\t\treturn values[0];\n\t}\n\n\tconst type = Array.isArray(record.type) ? record.type[0] : record.type;\n\tswitch (type) {\n\t\tcase \"string\":\n\t\t\treturn \"\";\n\t\tcase \"number\":\n\t\t\treturn typeof record.minimum === \"number\" ? record.minimum : 0;\n\t\tcase \"integer\":\n\t\t\treturn typeof record.minimum === \"number\" ? Math.ceil(record.minimum) : 0;\n\t\tcase \"boolean\":\n\t\t\treturn true;\n\t\tcase \"array\":\n\t\t\treturn [];\n\t\tcase \"object\": {\n\t\t\tconst properties = asRecord(record.properties) ?? {};\n\t\t\tconst required = Array.isArray(record.required)\n\t\t\t\t? record.required.filter((key) => typeof key === \"string\")\n\t\t\t\t: [];\n\t\t\treturn Object.fromEntries(required.map((key) => [key, minimalExample(properties[key]) ?? null]));\n\t\t}\n\t\tcase \"null\":\n\t\t\treturn null;\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nfunction formatValidationErrors(errors: readonly TLocalizedValidationError[], args: unknown, schema: unknown): string {\n\treturn (\n\t\terrors\n\t\t\t.map((error) => {\n\t\t\t\tconst path = formatValidationPath(error);\n\t\t\t\tconst pathSegments = validationPathSegments(error);\n\t\t\t\tconst expectedSchema = schemaAtPath(schema, pathSegments);\n\t\t\t\tconst expectedFragment = formatCompactJson(\n\t\t\t\t\tcompactSchemaFragment(expectedSchema),\n\t\t\t\t\tEXPECTED_FRAGMENT_MAX_LENGTH,\n\t\t\t\t);\n\t\t\t\tconst example = minimalExample(expectedSchema);\n\t\t\t\tconst received = formatCompactJson(receivedValueAtPath(args, pathSegments), RECEIVED_VALUE_MAX_LENGTH);\n\t\t\t\tconst exampleText =\n\t\t\t\t\texample === undefined ? \"\" : `; Example: ${formatCompactJson(example, RECEIVED_VALUE_MAX_LENGTH)}`;\n\t\t\t\treturn ` - ${path}: ${error.message}; Expected schema: ${expectedFragment}${exampleText}; Received: ${received}`;\n\t\t\t})\n\t\t\t.join(\"\\n\") || \"Unknown validation error\"\n\t);\n}\n\nfunction validationFailureSignature(errors: readonly TLocalizedValidationError[]): string {\n\treturn JSON.stringify(\n\t\terrors.map((error) => ({\n\t\t\tpath: formatValidationPath(error),\n\t\t\tkeyword: error.keyword,\n\t\t\tmessage: error.message,\n\t\t})),\n\t);\n}\n\nfunction formatValidationEnrichment(tool: Tool): string {\n\tconst example = minimalExample(tool.parameters);\n\tconst exampleText = example === undefined ? \"\" : `\\nValid example:\\n${formatCompactJson(example, 2000)}`;\n\treturn `Full tool schema:\\n${formatCompactJson(tool.parameters, 4000)}${exampleText}`;\n}\n\n/**\n * Finds a tool by name and validates the tool call arguments against its TypeBox schema\n * @param tools Array of tool definitions\n * @param toolCall The tool call from the LLM\n * @returns The validated arguments\n * @throws Error if tool is not found or validation fails\n */\nexport function validateToolCall(\n\ttools: Tool[],\n\ttoolCall: ToolCall,\n\toptions?: ToolArgumentValidationOptions,\n): Record<string, unknown> {\n\tconst tool = tools.find((t) => t.name === toolCall.name);\n\tif (!tool) {\n\t\tthrow new Error(`Tool \"${toolCall.name}\" not found`);\n\t}\n\treturn validateToolArguments(tool, toolCall, options);\n}\n\n/**\n * Validates tool call arguments against the tool's TypeBox schema.\n *\n * The hot path is validate-first and allocation-free: valid arguments return the exact\n * argument object emitted by the model. Only invalid calls enter the deterministic\n * repair layer, which applies named, guard-checked shape repairs on a clone.\n *\n * @param tool The tool definition with TypeBox schema\n * @param toolCall The tool call from the LLM\n * @returns The validated (and potentially repaired) arguments\n * @throws Error with formatted message if validation fails\n */\nexport function validateToolArguments(\n\ttool: Tool,\n\ttoolCall: ToolCall,\n\toptions?: ToolArgumentValidationOptions,\n): Record<string, unknown> {\n\tconst args = toolCall.arguments;\n\tconst validator = getValidator(tool.parameters);\n\n\tif (validator.Check(args)) {\n\t\treturn args;\n\t}\n\n\tconst validationErrors = [...validator.Errors(args)] as TLocalizedValidationError[];\n\tconst repairIssues = analyzeToolArgumentErrors(toolCall.name, tool.parameters, args, validationErrors);\n\tconst failureModes = uniqueFailureModes(repairIssues.flatMap((issue) => issue.modes));\n\tconst repaired =\n\t\toptions?.repairEnabled === false\n\t\t\t? undefined\n\t\t\t: repairToolArguments(toolCall.name, tool.parameters, args, validationErrors, (candidate) =>\n\t\t\t\t\tvalidator.Check(candidate),\n\t\t\t\t);\n\tif (repaired) {\n\t\tconst repairsApplied = uniqueRepairModes(repaired.repairsApplied);\n\t\ttoolCall.repairNotes = repaired.repairs.map(\n\t\t\t(repair) =>\n\t\t\t\t`[harness] ${repair.name}: ${formatToolRepairNote(repair.name, repair.path)}; executed with repaired arguments.`,\n\t\t);\n\t\temitToolArgumentValidationTelemetry(options, {\n\t\t\toutcome: \"repaired\",\n\t\t\ttool: toolCall.name,\n\t\t\tsource: toolCall.source,\n\t\t\tfailureModes,\n\t\t\trepairsApplied,\n\t\t});\n\t\treturn repaired.args;\n\t}\n\n\temitToolArgumentValidationTelemetry(options, {\n\t\toutcome: \"bounced\",\n\t\ttool: toolCall.name,\n\t\tsource: toolCall.source,\n\t\tfailureModes,\n\t\trepairsApplied: [],\n\t\tfailureShape: formatFailureShape(validationErrors, toolCall.arguments, tool.parameters),\n\t\terrorKeywords: errorKeywords(validationErrors),\n\t});\n\n\tconst errorMessage = `Validation failed for tool \"${toolCall.name}\":\\n${formatValidationErrors(\n\t\tvalidationErrors,\n\t\ttoolCall.arguments,\n\t\ttool.parameters,\n\t)}\\n\\nReceived arguments:\\n${truncateText(JSON.stringify(toolCall.arguments, null, 2), 2000)}`;\n\n\tthrow new ToolArgumentValidationError(errorMessage, {\n\t\ttoolName: toolCall.name,\n\t\tsignature: validationFailureSignature(validationErrors),\n\t\tenrichment: formatValidationEnrichment(tool),\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAEN,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACvB,MAAM,2BAA2B,CAAC;AAQnC,MAAM,MAAM,6BAA6B,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;AAC7E,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAC9D,MAAM,MAAM,4BAA4B,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE9E,MAAM,WAAW,6BAA6B;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oCAAoC;IACpD,OAAO,EAAE,6BAA6B,CAAC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5B,YAAY,EAAE,yBAAyB,EAAE,CAAC;IAC1C,cAAc,EAAE,kBAAkB,EAAE,CAAC;IACrC,YAAY,CAAC,EAAE,6BAA6B,EAAE,CAAC;IAC/C,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,gBAAgB,EAAE,4BAA4B,CAAC;CAC/C;AAED,MAAM,WAAW,6BAA6B;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,oCAAoC,KAAK,IAAI,CAAC;IAClE,6FAA6F;IAC7F,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,qBAAa,2BAA4B,SAAQ,KAAK;IACrD,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC,SAAgB,UAAU,EAAE,MAAM,CAAC;IAEnC,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAMhG;CACD;AAqTD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,IAAI,EAAE,EACb,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,6BAA6B,GACrC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACpC,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,6BAA6B,GACrC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsDzB","sourcesContent":["import { Compile } from \"typebox/compile\";\nimport type { TLocalizedValidationError } from \"typebox/error\";\nimport type { Tool, ToolCall } from \"../types.ts\";\nimport { analyzeToolArgumentErrors } from \"./tool-repair/analyzer.ts\";\nimport {\n\tformatToolRepairNote,\n\ttype ToolRepairFailureModeName,\n\ttype ToolRepairModeName,\n} from \"./tool-repair/registry.ts\";\nimport { repairToolArguments } from \"./tool-repair/repairer.ts\";\n\nconst validatorCache = new WeakMap<object, ReturnType<typeof Compile>>();\nconst EXPECTED_FRAGMENT_MAX_LENGTH = 320;\nconst RECEIVED_VALUE_MAX_LENGTH = 200;\nconst MISSING_VALUE = Symbol(\"missing\");\n\nexport type ToolArgumentValidationOutcome = \"clean\" | \"repaired\" | \"bounced\";\nexport type ToolArgumentTeachState = \"none\" | \"note\" | \"rule\";\nexport type ToolArgumentExecutionOutcome = \"not_run\" | \"succeeded\" | \"failed\";\n\nexport interface ToolArgumentFailureShapeEntry {\n\tpath: string;\n\texpectedType: string;\n\treceivedType: string;\n\tkeyword?: string;\n}\n\nexport interface ToolArgumentValidationTelemetryEvent {\n\toutcome: ToolArgumentValidationOutcome;\n\tprovider?: string;\n\tmodel?: string;\n\ttool: string;\n\tsource?: ToolCall[\"source\"];\n\tfailureModes: ToolRepairFailureModeName[];\n\trepairsApplied: ToolRepairModeName[];\n\tfailureShape?: ToolArgumentFailureShapeEntry[];\n\terrorKeywords?: string[];\n\ttaught: ToolArgumentTeachState;\n\texecutionOutcome: ToolArgumentExecutionOutcome;\n}\n\nexport interface ToolArgumentValidationOptions {\n\tmodel?: string;\n\tprovider?: string;\n\ttelemetry?: (event: ToolArgumentValidationTelemetryEvent) => void;\n\t/** Internal emergency diagnostic kill; user settings do not disable deterministic repair. */\n\trepairEnabled?: boolean;\n}\n\nexport class ToolArgumentValidationError extends Error {\n\tpublic readonly toolName: string;\n\tpublic readonly signature: string;\n\tpublic readonly enrichment: string;\n\n\tconstructor(message: string, options: { toolName: string; signature: string; enrichment: string }) {\n\t\tsuper(message);\n\t\tthis.name = \"ToolArgumentValidationError\";\n\t\tthis.toolName = options.toolName;\n\t\tthis.signature = options.signature;\n\t\tthis.enrichment = options.enrichment;\n\t}\n}\n\nfunction emitToolArgumentValidationTelemetry(\n\toptions: ToolArgumentValidationOptions | undefined,\n\tevent: Omit<ToolArgumentValidationTelemetryEvent, \"model\" | \"provider\" | \"taught\" | \"executionOutcome\">,\n): void {\n\ttry {\n\t\toptions?.telemetry?.({\n\t\t\t...event,\n\t\t\tmodel: options.model,\n\t\t\tprovider: options.provider,\n\t\t\ttaught: \"none\",\n\t\t\texecutionOutcome: \"not_run\",\n\t\t});\n\t} catch {\n\t\t// Telemetry is observe-only; never fail validation because a sink failed.\n\t}\n}\n\nfunction uniqueRepairModes(modes: Iterable<ToolRepairModeName>): ToolRepairModeName[] {\n\treturn [...new Set(modes)];\n}\n\nfunction uniqueFailureModes(modes: Iterable<ToolRepairModeName>): ToolRepairFailureModeName[] {\n\tconst uniqueModes = uniqueRepairModes(modes);\n\treturn uniqueModes.length > 0 ? uniqueModes : [\"other\"];\n}\n\nfunction getValidator(schema: Tool[\"parameters\"]): ReturnType<typeof Compile> {\n\tconst key = schema as object;\n\tconst cached = validatorCache.get(key);\n\tif (cached) {\n\t\treturn cached;\n\t}\n\tconst validator = Compile(schema);\n\tvalidatorCache.set(key, validator);\n\treturn validator;\n}\n\nfunction formatValidationPath(error: TLocalizedValidationError): string {\n\tif (error.keyword === \"required\") {\n\t\tconst requiredProperties = (error.params as { requiredProperties?: string[] }).requiredProperties;\n\t\tconst requiredProperty = requiredProperties?.[0];\n\t\tif (requiredProperty) {\n\t\t\tconst basePath = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\t\t\treturn basePath ? `${basePath}.${requiredProperty}` : requiredProperty;\n\t\t}\n\t}\n\tconst path = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\treturn path || \"root\";\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value)\n\t\t? (value as Record<string, unknown>)\n\t\t: undefined;\n}\n\nfunction truncateText(text: string, maxLength: number): string {\n\tif (text.length <= maxLength) {\n\t\treturn text;\n\t}\n\treturn `${text.slice(0, maxLength)}...[truncated]`;\n}\n\nfunction formatCompactJson(value: unknown, maxLength: number): string {\n\tif (value === MISSING_VALUE) {\n\t\treturn \"<missing>\";\n\t}\n\tif (value === undefined) {\n\t\treturn \"undefined\";\n\t}\n\treturn truncateText(JSON.stringify(value), maxLength);\n}\n\nfunction validationPathSegments(error: TLocalizedValidationError): string[] {\n\tconst path = formatValidationPath(error);\n\treturn path === \"root\" ? [] : path.split(\".\");\n}\n\nfunction schemaAtPath(schema: unknown, pathSegments: readonly string[]): unknown {\n\tlet current: unknown = schema;\n\tfor (const segment of pathSegments) {\n\t\tconst record = asRecord(current);\n\t\tif (!record) {\n\t\t\treturn current;\n\t\t}\n\n\t\tconst properties = asRecord(record.properties);\n\t\tif (properties && segment in properties) {\n\t\t\tcurrent = properties[segment];\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (record.items !== undefined) {\n\t\t\tcurrent = record.items;\n\t\t\tcontinue;\n\t\t}\n\n\t\treturn current;\n\t}\n\treturn current;\n}\n\nfunction receivedValueAtPath(args: unknown, pathSegments: readonly string[]): unknown {\n\tlet current: unknown = args;\n\tfor (const segment of pathSegments) {\n\t\tconst record = asRecord(current);\n\t\tif (record) {\n\t\t\tif (!(segment in record)) {\n\t\t\t\treturn MISSING_VALUE;\n\t\t\t}\n\t\t\tcurrent = record[segment];\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (Array.isArray(current)) {\n\t\t\tconst index = Number(segment);\n\t\t\tif (!Number.isInteger(index) || index < 0 || index >= current.length) {\n\t\t\t\treturn MISSING_VALUE;\n\t\t\t}\n\t\t\tcurrent = current[index];\n\t\t\tcontinue;\n\t\t}\n\n\t\treturn MISSING_VALUE;\n\t}\n\treturn current;\n}\n\nfunction receivedTypeOf(value: unknown): string {\n\tif (value === MISSING_VALUE) return \"missing\";\n\tif (value === null) return \"null\";\n\tif (Array.isArray(value)) return \"array\";\n\treturn typeof value;\n}\n\nfunction expectedTypeOf(schema: unknown): string {\n\tconst record = asRecord(schema);\n\tif (!record) return \"unknown\";\n\tif (Array.isArray(record.type)) return record.type.filter((type) => typeof type === \"string\").join(\"|\") || \"unknown\";\n\tif (typeof record.type === \"string\") return record.type;\n\tif (literalValues(record)) return \"enum\";\n\tif (record.properties !== undefined) return \"object\";\n\tif (record.items !== undefined) return \"array\";\n\treturn \"unknown\";\n}\n\nfunction formatFailureShape(\n\terrors: readonly TLocalizedValidationError[],\n\targs: unknown,\n\tschema: unknown,\n): ToolArgumentFailureShapeEntry[] {\n\tconst seen = new Set<string>();\n\tconst shape: ToolArgumentFailureShapeEntry[] = [];\n\tfor (const error of errors) {\n\t\tconst path = formatValidationPath(error);\n\t\tconst pathSegments = path === \"root\" ? [] : path.split(\".\");\n\t\tconst expectedSchema = schemaAtPath(schema, pathSegments);\n\t\tconst value = receivedValueAtPath(args, pathSegments);\n\t\tconst entry = {\n\t\t\tpath,\n\t\t\texpectedType: expectedTypeOf(expectedSchema),\n\t\t\treceivedType: receivedTypeOf(value),\n\t\t\tkeyword: error.keyword,\n\t\t};\n\t\tconst key = `${entry.path}\\0${entry.expectedType}\\0${entry.receivedType}\\0${entry.keyword}`;\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tshape.push(entry);\n\t}\n\treturn shape;\n}\n\nfunction errorKeywords(errors: readonly TLocalizedValidationError[]): string[] {\n\treturn [...new Set(errors.map((error) => error.keyword))].sort();\n}\n\nfunction literalValues(schema: unknown): unknown[] | undefined {\n\tconst record = asRecord(schema);\n\tif (!record) {\n\t\treturn undefined;\n\t}\n\tif (Array.isArray(record.enum)) {\n\t\treturn record.enum;\n\t}\n\tif (record.const !== undefined) {\n\t\treturn [record.const];\n\t}\n\tconst anyOf = Array.isArray(record.anyOf) ? record.anyOf : Array.isArray(record.oneOf) ? record.oneOf : undefined;\n\tif (anyOf) {\n\t\tconst values: unknown[] = [];\n\t\tfor (const option of anyOf) {\n\t\t\tconst optionRecord = asRecord(option);\n\t\t\tif (!optionRecord || optionRecord.const === undefined) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tvalues.push(optionRecord.const);\n\t\t}\n\t\treturn values;\n\t}\n\treturn undefined;\n}\n\nfunction compactSchemaFragment(schema: unknown): Record<string, unknown> {\n\tconst record = asRecord(schema);\n\tif (!record) {\n\t\treturn {};\n\t}\n\n\tconst fragment: Record<string, unknown> = {};\n\tconst values = literalValues(record);\n\tif (values) {\n\t\tfragment.enum = values;\n\t\treturn fragment;\n\t}\n\n\tfor (const key of [\"type\", \"required\", \"minimum\", \"maximum\", \"minLength\", \"maxLength\", \"format\"] as const) {\n\t\tif (record[key] !== undefined) {\n\t\t\tfragment[key] = record[key];\n\t\t}\n\t}\n\n\tconst properties = asRecord(record.properties);\n\tif (properties) {\n\t\tfragment.properties = Object.keys(properties);\n\t}\n\tif (record.items !== undefined) {\n\t\tfragment.items = compactSchemaFragment(record.items);\n\t}\n\treturn fragment;\n}\n\nfunction minimalExample(schema: unknown): unknown {\n\tconst record = asRecord(schema);\n\tif (!record) {\n\t\treturn undefined;\n\t}\n\tif (record.default !== undefined) {\n\t\treturn record.default;\n\t}\n\tconst values = literalValues(record);\n\tif (values?.length) {\n\t\treturn values[0];\n\t}\n\n\tconst type = Array.isArray(record.type) ? record.type[0] : record.type;\n\tswitch (type) {\n\t\tcase \"string\":\n\t\t\treturn \"\";\n\t\tcase \"number\":\n\t\t\treturn typeof record.minimum === \"number\" ? record.minimum : 0;\n\t\tcase \"integer\":\n\t\t\treturn typeof record.minimum === \"number\" ? Math.ceil(record.minimum) : 0;\n\t\tcase \"boolean\":\n\t\t\treturn true;\n\t\tcase \"array\":\n\t\t\treturn [];\n\t\tcase \"object\": {\n\t\t\tconst properties = asRecord(record.properties) ?? {};\n\t\t\tconst required = Array.isArray(record.required)\n\t\t\t\t? record.required.filter((key) => typeof key === \"string\")\n\t\t\t\t: [];\n\t\t\treturn Object.fromEntries(required.map((key) => [key, minimalExample(properties[key]) ?? null]));\n\t\t}\n\t\tcase \"null\":\n\t\t\treturn null;\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nfunction formatValidationErrors(errors: readonly TLocalizedValidationError[], args: unknown, schema: unknown): string {\n\treturn (\n\t\terrors\n\t\t\t.map((error) => {\n\t\t\t\tconst path = formatValidationPath(error);\n\t\t\t\tconst pathSegments = validationPathSegments(error);\n\t\t\t\tconst expectedSchema = schemaAtPath(schema, pathSegments);\n\t\t\t\tconst expectedFragment = formatCompactJson(\n\t\t\t\t\tcompactSchemaFragment(expectedSchema),\n\t\t\t\t\tEXPECTED_FRAGMENT_MAX_LENGTH,\n\t\t\t\t);\n\t\t\t\tconst example = minimalExample(expectedSchema);\n\t\t\t\tconst received = formatCompactJson(receivedValueAtPath(args, pathSegments), RECEIVED_VALUE_MAX_LENGTH);\n\t\t\t\tconst exampleText =\n\t\t\t\t\texample === undefined ? \"\" : `; Example: ${formatCompactJson(example, RECEIVED_VALUE_MAX_LENGTH)}`;\n\t\t\t\treturn ` - ${path}: ${error.message}; Expected schema: ${expectedFragment}${exampleText}; Received: ${received}`;\n\t\t\t})\n\t\t\t.join(\"\\n\") || \"Unknown validation error\"\n\t);\n}\n\nfunction validationFailureSignature(errors: readonly TLocalizedValidationError[]): string {\n\treturn JSON.stringify(\n\t\terrors.map((error) => ({\n\t\t\tpath: formatValidationPath(error),\n\t\t\tkeyword: error.keyword,\n\t\t\tmessage: error.message,\n\t\t})),\n\t);\n}\n\nfunction formatValidationEnrichment(tool: Tool): string {\n\tconst example = minimalExample(tool.parameters);\n\tconst exampleText = example === undefined ? \"\" : `\\nValid example:\\n${formatCompactJson(example, 2000)}`;\n\treturn `Full tool schema:\\n${formatCompactJson(tool.parameters, 4000)}${exampleText}`;\n}\n\n/**\n * Finds a tool by name and validates the tool call arguments against its TypeBox schema\n * @param tools Array of tool definitions\n * @param toolCall The tool call from the LLM\n * @returns The validated arguments\n * @throws Error if tool is not found or validation fails\n */\nexport function validateToolCall(\n\ttools: Tool[],\n\ttoolCall: ToolCall,\n\toptions?: ToolArgumentValidationOptions,\n): Record<string, unknown> {\n\tconst tool = tools.find((t) => t.name === toolCall.name);\n\tif (!tool) {\n\t\tthrow new Error(`Tool \"${toolCall.name}\" not found`);\n\t}\n\treturn validateToolArguments(tool, toolCall, options);\n}\n\n/**\n * Validates tool call arguments against the tool's TypeBox schema.\n *\n * The hot path is validate-first and allocation-free: valid arguments return the exact\n * argument object emitted by the model. Only invalid calls enter the deterministic\n * repair layer, which applies named, guard-checked shape repairs on a clone.\n *\n * @param tool The tool definition with TypeBox schema\n * @param toolCall The tool call from the LLM\n * @returns The validated (and potentially repaired) arguments\n * @throws Error with formatted message if validation fails\n */\nexport function validateToolArguments(\n\ttool: Tool,\n\ttoolCall: ToolCall,\n\toptions?: ToolArgumentValidationOptions,\n): Record<string, unknown> {\n\tconst args = toolCall.arguments;\n\tconst validator = getValidator(tool.parameters);\n\n\tif (validator.Check(args)) {\n\t\treturn args;\n\t}\n\n\tconst validationErrors = [...validator.Errors(args)] as TLocalizedValidationError[];\n\tconst repairIssues = analyzeToolArgumentErrors(toolCall.name, tool.parameters, args, validationErrors);\n\tconst failureModes = uniqueFailureModes(repairIssues.flatMap((issue) => issue.modes));\n\tconst repaired =\n\t\toptions?.repairEnabled === false\n\t\t\t? undefined\n\t\t\t: repairToolArguments(toolCall.name, tool.parameters, args, validationErrors, (candidate) =>\n\t\t\t\t\tvalidator.Check(candidate),\n\t\t\t\t);\n\tif (repaired) {\n\t\tconst repairsApplied = uniqueRepairModes(repaired.repairsApplied);\n\t\ttoolCall.repairNotes = repaired.repairs.map(\n\t\t\t(repair) =>\n\t\t\t\t`[harness] ${repair.name}: ${formatToolRepairNote(repair.name, repair.path)}; executed with repaired arguments.`,\n\t\t);\n\t\temitToolArgumentValidationTelemetry(options, {\n\t\t\toutcome: \"repaired\",\n\t\t\ttool: toolCall.name,\n\t\t\tsource: toolCall.source,\n\t\t\tfailureModes,\n\t\t\trepairsApplied,\n\t\t});\n\t\treturn repaired.args;\n\t}\n\n\temitToolArgumentValidationTelemetry(options, {\n\t\toutcome: \"bounced\",\n\t\ttool: toolCall.name,\n\t\tsource: toolCall.source,\n\t\tfailureModes,\n\t\trepairsApplied: [],\n\t\tfailureShape: formatFailureShape(validationErrors, toolCall.arguments, tool.parameters),\n\t\terrorKeywords: errorKeywords(validationErrors),\n\t});\n\n\tconst errorMessage = `Validation failed for tool \"${toolCall.name}\":\\n${formatValidationErrors(\n\t\tvalidationErrors,\n\t\ttoolCall.arguments,\n\t\ttool.parameters,\n\t)}\\n\\nReceived arguments:\\n${truncateText(JSON.stringify(toolCall.arguments, null, 2), 2000)}`;\n\n\tthrow new ToolArgumentValidationError(errorMessage, {\n\t\ttoolName: toolCall.name,\n\t\tsignature: validationFailureSignature(validationErrors),\n\t\tenrichment: formatValidationEnrichment(tool),\n\t});\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Compile } from \"typebox/compile\";\nimport type { TLocalizedValidationError } from \"typebox/error\";\nimport type { Tool, ToolCall } from \"../types.ts\";\nimport { analyzeToolArgumentErrors } from \"./tool-repair/analyzer.ts\";\nimport {\n\tformatToolRepairNote,\n\ttype ToolRepairFailureModeName,\n\ttype ToolRepairModeName,\n} from \"./tool-repair/registry.ts\";\nimport { repairToolArguments } from \"./tool-repair/repairer.ts\";\n\nconst validatorCache = new WeakMap<object, ReturnType<typeof Compile>>();\nconst EXPECTED_FRAGMENT_MAX_LENGTH = 320;\nconst RECEIVED_VALUE_MAX_LENGTH = 200;\nconst MISSING_VALUE = Symbol(\"missing\");\n\nexport type ToolArgumentValidationOutcome = \"clean\" | \"repaired\" | \"bounced\";\nexport type ToolArgumentTeachState = \"none\" | \"note\" | \"rule\";\nexport type ToolArgumentExecutionOutcome = \"not_run\" | \"succeeded\" | \"failed\";\n\nexport interface ToolArgumentFailureShapeEntry {\n\tpath: string;\n\texpectedType: string;\n\treceivedType: string;\n\tkeyword?: string;\n}\n\nexport interface ToolArgumentValidationTelemetryEvent {\n\toutcome: ToolArgumentValidationOutcome;\n\tprovider?: string;\n\tmodel?: string;\n\ttool: string;\n\tsource?: ToolCall[\"source\"];\n\tfailureModes: ToolRepairFailureModeName[];\n\trepairsApplied: ToolRepairModeName[];\n\tfailureShape?: ToolArgumentFailureShapeEntry[];\n\terrorKeywords?: string[];\n\ttaught: ToolArgumentTeachState;\n\texecutionOutcome: ToolArgumentExecutionOutcome;\n}\n\nexport interface ToolArgumentValidationOptions {\n\tmodel?: string;\n\tprovider?: string;\n\ttelemetry?: (event: ToolArgumentValidationTelemetryEvent) => void;\n\trepairEnabled?: boolean;\n}\n\nexport class ToolArgumentValidationError extends Error {\n\tpublic readonly toolName: string;\n\tpublic readonly signature: string;\n\tpublic readonly enrichment: string;\n\n\tconstructor(message: string, options: { toolName: string; signature: string; enrichment: string }) {\n\t\tsuper(message);\n\t\tthis.name = \"ToolArgumentValidationError\";\n\t\tthis.toolName = options.toolName;\n\t\tthis.signature = options.signature;\n\t\tthis.enrichment = options.enrichment;\n\t}\n}\n\nfunction emitToolArgumentValidationTelemetry(\n\toptions: ToolArgumentValidationOptions | undefined,\n\tevent: Omit<ToolArgumentValidationTelemetryEvent, \"model\" | \"provider\" | \"taught\" | \"executionOutcome\">,\n): void {\n\ttry {\n\t\toptions?.telemetry?.({\n\t\t\t...event,\n\t\t\tmodel: options.model,\n\t\t\tprovider: options.provider,\n\t\t\ttaught: \"none\",\n\t\t\texecutionOutcome: \"not_run\",\n\t\t});\n\t} catch {\n\t\t// Telemetry is observe-only; never fail validation because a sink failed.\n\t}\n}\n\nfunction uniqueRepairModes(modes: Iterable<ToolRepairModeName>): ToolRepairModeName[] {\n\treturn [...new Set(modes)];\n}\n\nfunction uniqueFailureModes(modes: Iterable<ToolRepairModeName>): ToolRepairFailureModeName[] {\n\tconst uniqueModes = uniqueRepairModes(modes);\n\treturn uniqueModes.length > 0 ? uniqueModes : [\"other\"];\n}\n\nfunction getValidator(schema: Tool[\"parameters\"]): ReturnType<typeof Compile> {\n\tconst key = schema as object;\n\tconst cached = validatorCache.get(key);\n\tif (cached) {\n\t\treturn cached;\n\t}\n\tconst validator = Compile(schema);\n\tvalidatorCache.set(key, validator);\n\treturn validator;\n}\n\nfunction formatValidationPath(error: TLocalizedValidationError): string {\n\tif (error.keyword === \"required\") {\n\t\tconst requiredProperties = (error.params as { requiredProperties?: string[] }).requiredProperties;\n\t\tconst requiredProperty = requiredProperties?.[0];\n\t\tif (requiredProperty) {\n\t\t\tconst basePath = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\t\t\treturn basePath ? `${basePath}.${requiredProperty}` : requiredProperty;\n\t\t}\n\t}\n\tconst path = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\treturn path || \"root\";\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value)\n\t\t? (value as Record<string, unknown>)\n\t\t: undefined;\n}\n\nfunction truncateText(text: string, maxLength: number): string {\n\tif (text.length <= maxLength) {\n\t\treturn text;\n\t}\n\treturn `${text.slice(0, maxLength)}...[truncated]`;\n}\n\nfunction formatCompactJson(value: unknown, maxLength: number): string {\n\tif (value === MISSING_VALUE) {\n\t\treturn \"<missing>\";\n\t}\n\tif (value === undefined) {\n\t\treturn \"undefined\";\n\t}\n\treturn truncateText(JSON.stringify(value), maxLength);\n}\n\nfunction validationPathSegments(error: TLocalizedValidationError): string[] {\n\tconst path = formatValidationPath(error);\n\treturn path === \"root\" ? [] : path.split(\".\");\n}\n\nfunction schemaAtPath(schema: unknown, pathSegments: readonly string[]): unknown {\n\tlet current: unknown = schema;\n\tfor (const segment of pathSegments) {\n\t\tconst record = asRecord(current);\n\t\tif (!record) {\n\t\t\treturn current;\n\t\t}\n\n\t\tconst properties = asRecord(record.properties);\n\t\tif (properties && segment in properties) {\n\t\t\tcurrent = properties[segment];\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (record.items !== undefined) {\n\t\t\tcurrent = record.items;\n\t\t\tcontinue;\n\t\t}\n\n\t\treturn current;\n\t}\n\treturn current;\n}\n\nfunction receivedValueAtPath(args: unknown, pathSegments: readonly string[]): unknown {\n\tlet current: unknown = args;\n\tfor (const segment of pathSegments) {\n\t\tconst record = asRecord(current);\n\t\tif (record) {\n\t\t\tif (!(segment in record)) {\n\t\t\t\treturn MISSING_VALUE;\n\t\t\t}\n\t\t\tcurrent = record[segment];\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (Array.isArray(current)) {\n\t\t\tconst index = Number(segment);\n\t\t\tif (!Number.isInteger(index) || index < 0 || index >= current.length) {\n\t\t\t\treturn MISSING_VALUE;\n\t\t\t}\n\t\t\tcurrent = current[index];\n\t\t\tcontinue;\n\t\t}\n\n\t\treturn MISSING_VALUE;\n\t}\n\treturn current;\n}\n\nfunction receivedTypeOf(value: unknown): string {\n\tif (value === MISSING_VALUE) return \"missing\";\n\tif (value === null) return \"null\";\n\tif (Array.isArray(value)) return \"array\";\n\treturn typeof value;\n}\n\nfunction expectedTypeOf(schema: unknown): string {\n\tconst record = asRecord(schema);\n\tif (!record) return \"unknown\";\n\tif (Array.isArray(record.type)) return record.type.filter((type) => typeof type === \"string\").join(\"|\") || \"unknown\";\n\tif (typeof record.type === \"string\") return record.type;\n\tif (literalValues(record)) return \"enum\";\n\tif (record.properties !== undefined) return \"object\";\n\tif (record.items !== undefined) return \"array\";\n\treturn \"unknown\";\n}\n\nfunction formatFailureShape(\n\terrors: readonly TLocalizedValidationError[],\n\targs: unknown,\n\tschema: unknown,\n): ToolArgumentFailureShapeEntry[] {\n\tconst seen = new Set<string>();\n\tconst shape: ToolArgumentFailureShapeEntry[] = [];\n\tfor (const error of errors) {\n\t\tconst path = formatValidationPath(error);\n\t\tconst pathSegments = path === \"root\" ? [] : path.split(\".\");\n\t\tconst expectedSchema = schemaAtPath(schema, pathSegments);\n\t\tconst value = receivedValueAtPath(args, pathSegments);\n\t\tconst entry = {\n\t\t\tpath,\n\t\t\texpectedType: expectedTypeOf(expectedSchema),\n\t\t\treceivedType: receivedTypeOf(value),\n\t\t\tkeyword: error.keyword,\n\t\t};\n\t\tconst key = `${entry.path}\\0${entry.expectedType}\\0${entry.receivedType}\\0${entry.keyword}`;\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tshape.push(entry);\n\t}\n\treturn shape;\n}\n\nfunction errorKeywords(errors: readonly TLocalizedValidationError[]): string[] {\n\treturn [...new Set(errors.map((error) => error.keyword))].sort();\n}\n\nfunction literalValues(schema: unknown): unknown[] | undefined {\n\tconst record = asRecord(schema);\n\tif (!record) {\n\t\treturn undefined;\n\t}\n\tif (Array.isArray(record.enum)) {\n\t\treturn record.enum;\n\t}\n\tif (record.const !== undefined) {\n\t\treturn [record.const];\n\t}\n\tconst anyOf = Array.isArray(record.anyOf) ? record.anyOf : Array.isArray(record.oneOf) ? record.oneOf : undefined;\n\tif (anyOf) {\n\t\tconst values: unknown[] = [];\n\t\tfor (const option of anyOf) {\n\t\t\tconst optionRecord = asRecord(option);\n\t\t\tif (!optionRecord || optionRecord.const === undefined) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tvalues.push(optionRecord.const);\n\t\t}\n\t\treturn values;\n\t}\n\treturn undefined;\n}\n\nfunction compactSchemaFragment(schema: unknown): Record<string, unknown> {\n\tconst record = asRecord(schema);\n\tif (!record) {\n\t\treturn {};\n\t}\n\n\tconst fragment: Record<string, unknown> = {};\n\tconst values = literalValues(record);\n\tif (values) {\n\t\tfragment.enum = values;\n\t\treturn fragment;\n\t}\n\n\tfor (const key of [\"type\", \"required\", \"minimum\", \"maximum\", \"minLength\", \"maxLength\", \"format\"] as const) {\n\t\tif (record[key] !== undefined) {\n\t\t\tfragment[key] = record[key];\n\t\t}\n\t}\n\n\tconst properties = asRecord(record.properties);\n\tif (properties) {\n\t\tfragment.properties = Object.keys(properties);\n\t}\n\tif (record.items !== undefined) {\n\t\tfragment.items = compactSchemaFragment(record.items);\n\t}\n\treturn fragment;\n}\n\nfunction minimalExample(schema: unknown): unknown {\n\tconst record = asRecord(schema);\n\tif (!record) {\n\t\treturn undefined;\n\t}\n\tif (record.default !== undefined) {\n\t\treturn record.default;\n\t}\n\tconst values = literalValues(record);\n\tif (values?.length) {\n\t\treturn values[0];\n\t}\n\n\tconst type = Array.isArray(record.type) ? record.type[0] : record.type;\n\tswitch (type) {\n\t\tcase \"string\":\n\t\t\treturn \"\";\n\t\tcase \"number\":\n\t\t\treturn typeof record.minimum === \"number\" ? record.minimum : 0;\n\t\tcase \"integer\":\n\t\t\treturn typeof record.minimum === \"number\" ? Math.ceil(record.minimum) : 0;\n\t\tcase \"boolean\":\n\t\t\treturn true;\n\t\tcase \"array\":\n\t\t\treturn [];\n\t\tcase \"object\": {\n\t\t\tconst properties = asRecord(record.properties) ?? {};\n\t\t\tconst required = Array.isArray(record.required)\n\t\t\t\t? record.required.filter((key) => typeof key === \"string\")\n\t\t\t\t: [];\n\t\t\treturn Object.fromEntries(required.map((key) => [key, minimalExample(properties[key]) ?? null]));\n\t\t}\n\t\tcase \"null\":\n\t\t\treturn null;\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nfunction formatValidationErrors(errors: readonly TLocalizedValidationError[], args: unknown, schema: unknown): string {\n\treturn (\n\t\terrors\n\t\t\t.map((error) => {\n\t\t\t\tconst path = formatValidationPath(error);\n\t\t\t\tconst pathSegments = validationPathSegments(error);\n\t\t\t\tconst expectedSchema = schemaAtPath(schema, pathSegments);\n\t\t\t\tconst expectedFragment = formatCompactJson(\n\t\t\t\t\tcompactSchemaFragment(expectedSchema),\n\t\t\t\t\tEXPECTED_FRAGMENT_MAX_LENGTH,\n\t\t\t\t);\n\t\t\t\tconst example = minimalExample(expectedSchema);\n\t\t\t\tconst received = formatCompactJson(receivedValueAtPath(args, pathSegments), RECEIVED_VALUE_MAX_LENGTH);\n\t\t\t\tconst exampleText =\n\t\t\t\t\texample === undefined ? \"\" : `; Example: ${formatCompactJson(example, RECEIVED_VALUE_MAX_LENGTH)}`;\n\t\t\t\treturn ` - ${path}: ${error.message}; Expected schema: ${expectedFragment}${exampleText}; Received: ${received}`;\n\t\t\t})\n\t\t\t.join(\"\\n\") || \"Unknown validation error\"\n\t);\n}\n\nfunction validationFailureSignature(errors: readonly TLocalizedValidationError[]): string {\n\treturn JSON.stringify(\n\t\terrors.map((error) => ({\n\t\t\tpath: formatValidationPath(error),\n\t\t\tkeyword: error.keyword,\n\t\t\tmessage: error.message,\n\t\t})),\n\t);\n}\n\nfunction formatValidationEnrichment(tool: Tool): string {\n\tconst example = minimalExample(tool.parameters);\n\tconst exampleText = example === undefined ? \"\" : `\\nValid example:\\n${formatCompactJson(example, 2000)}`;\n\treturn `Full tool schema:\\n${formatCompactJson(tool.parameters, 4000)}${exampleText}`;\n}\n\n/**\n * Finds a tool by name and validates the tool call arguments against its TypeBox schema\n * @param tools Array of tool definitions\n * @param toolCall The tool call from the LLM\n * @returns The validated arguments\n * @throws Error if tool is not found or validation fails\n */\nexport function validateToolCall(\n\ttools: Tool[],\n\ttoolCall: ToolCall,\n\toptions?: ToolArgumentValidationOptions,\n): Record<string, unknown> {\n\tconst tool = tools.find((t) => t.name === toolCall.name);\n\tif (!tool) {\n\t\tthrow new Error(`Tool \"${toolCall.name}\" not found`);\n\t}\n\treturn validateToolArguments(tool, toolCall, options);\n}\n\n/**\n * Validates tool call arguments against the tool's TypeBox schema.\n *\n * The hot path is validate-first and allocation-free: valid arguments return the exact\n * argument object emitted by the model. Only invalid calls enter the deterministic\n * repair layer, which applies named, guard-checked shape repairs on a clone.\n *\n * @param tool The tool definition with TypeBox schema\n * @param toolCall The tool call from the LLM\n * @returns The validated (and potentially repaired) arguments\n * @throws Error with formatted message if validation fails\n */\nexport function validateToolArguments(\n\ttool: Tool,\n\ttoolCall: ToolCall,\n\toptions?: ToolArgumentValidationOptions,\n): Record<string, unknown> {\n\tconst args = toolCall.arguments;\n\tconst validator = getValidator(tool.parameters);\n\n\tif (validator.Check(args)) {\n\t\treturn args;\n\t}\n\n\tconst validationErrors = [...validator.Errors(args)] as TLocalizedValidationError[];\n\tconst repairIssues = analyzeToolArgumentErrors(toolCall.name, tool.parameters, args, validationErrors);\n\tconst failureModes = uniqueFailureModes(repairIssues.flatMap((issue) => issue.modes));\n\tconst repaired =\n\t\toptions?.repairEnabled === false\n\t\t\t? undefined\n\t\t\t: repairToolArguments(toolCall.name, tool.parameters, args, validationErrors, (candidate) =>\n\t\t\t\t\tvalidator.Check(candidate),\n\t\t\t\t);\n\tif (repaired) {\n\t\tconst repairsApplied = uniqueRepairModes(repaired.repairsApplied);\n\t\ttoolCall.repairNotes = repaired.repairs.map(\n\t\t\t(repair) =>\n\t\t\t\t`[harness] ${repair.name}: ${formatToolRepairNote(repair.name, repair.path)}; executed with repaired arguments.`,\n\t\t);\n\t\temitToolArgumentValidationTelemetry(options, {\n\t\t\toutcome: \"repaired\",\n\t\t\ttool: toolCall.name,\n\t\t\tsource: toolCall.source,\n\t\t\tfailureModes,\n\t\t\trepairsApplied,\n\t\t});\n\t\treturn repaired.args;\n\t}\n\n\temitToolArgumentValidationTelemetry(options, {\n\t\toutcome: \"bounced\",\n\t\ttool: toolCall.name,\n\t\tsource: toolCall.source,\n\t\tfailureModes,\n\t\trepairsApplied: [],\n\t\tfailureShape: formatFailureShape(validationErrors, toolCall.arguments, tool.parameters),\n\t\terrorKeywords: errorKeywords(validationErrors),\n\t});\n\n\tconst errorMessage = `Validation failed for tool \"${toolCall.name}\":\\n${formatValidationErrors(\n\t\tvalidationErrors,\n\t\ttoolCall.arguments,\n\t\ttool.parameters,\n\t)}\\n\\nReceived arguments:\\n${truncateText(JSON.stringify(toolCall.arguments, null, 2), 2000)}`;\n\n\tthrow new ToolArgumentValidationError(errorMessage, {\n\t\ttoolName: toolCall.name,\n\t\tsignature: validationFailureSignature(validationErrors),\n\t\tenrichment: formatValidationEnrichment(tool),\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG1C,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EACN,oBAAoB,GAGpB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEhE,MAAM,cAAc,GAAG,IAAI,OAAO,EAAsC,CAAC;AACzE,MAAM,4BAA4B,GAAG,GAAG,CAAC;AACzC,MAAM,yBAAyB,GAAG,GAAG,CAAC;AACtC,MAAM,aAAa,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;AAmCxC,MAAM,OAAO,2BAA4B,SAAQ,KAAK;IACrC,QAAQ,CAAS;IACjB,SAAS,CAAS;IAClB,UAAU,CAAS;IAEnC,YAAY,OAAe,EAAE,OAAoE,EAAE;QAClG,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC;QAC1C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAAA,CACrC;CACD;AAED,SAAS,mCAAmC,CAC3C,OAAkD,EAClD,KAAuG,EAChG;IACP,IAAI,CAAC;QACJ,OAAO,EAAE,SAAS,EAAE,CAAC;YACpB,GAAG,KAAK;YACR,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,MAAM,EAAE,MAAM;YACd,gBAAgB,EAAE,SAAS;SAC3B,CAAC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACR,0EAA0E;IAC3E,CAAC;AAAA,CACD;AAED,SAAS,iBAAiB,CAAC,KAAmC,EAAwB;IACrF,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AAAA,CAC3B;AAED,SAAS,kBAAkB,CAAC,KAAmC,EAA+B;IAC7F,MAAM,WAAW,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAC7C,OAAO,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AAAA,CACxD;AAED,SAAS,YAAY,CAAC,MAA0B,EAA8B;IAC7E,MAAM,GAAG,GAAG,MAAgB,CAAC;IAC7B,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,MAAM,EAAE,CAAC;QACZ,OAAO,MAAM,CAAC;IACf,CAAC;IACD,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACnC,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,SAAS,oBAAoB,CAAC,KAAgC,EAAU;IACvE,IAAI,KAAK,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QAClC,MAAM,kBAAkB,GAAI,KAAK,CAAC,MAA4C,CAAC,kBAAkB,CAAC;QAClG,MAAM,gBAAgB,GAAG,kBAAkB,EAAE,CAAC,CAAC,CAAC,CAAC;QACjD,IAAI,gBAAgB,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAC3E,OAAO,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;QACxE,CAAC;IACF,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACvE,OAAO,IAAI,IAAI,MAAM,CAAC;AAAA,CACtB;AAED,SAAS,QAAQ,CAAC,KAAc,EAAuC;IACtE,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAC1E,CAAC,CAAE,KAAiC;QACpC,CAAC,CAAC,SAAS,CAAC;AAAA,CACb;AAED,SAAS,YAAY,CAAC,IAAY,EAAE,SAAiB,EAAU;IAC9D,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,gBAAgB,CAAC;AAAA,CACnD;AAED,SAAS,iBAAiB,CAAC,KAAc,EAAE,SAAiB,EAAU;IACrE,IAAI,KAAK,KAAK,aAAa,EAAE,CAAC;QAC7B,OAAO,WAAW,CAAC;IACpB,CAAC;IACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,WAAW,CAAC;IACpB,CAAC;IACD,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC;AAAA,CACtD;AAED,SAAS,sBAAsB,CAAC,KAAgC,EAAY;IAC3E,MAAM,IAAI,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACzC,OAAO,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAAA,CAC9C;AAED,SAAS,YAAY,CAAC,MAAe,EAAE,YAA+B,EAAW;IAChF,IAAI,OAAO,GAAY,MAAM,CAAC;IAC9B,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,OAAO,OAAO,CAAC;QAChB,CAAC;QAED,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC/C,IAAI,UAAU,IAAI,OAAO,IAAI,UAAU,EAAE,CAAC;YACzC,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;YAC9B,SAAS;QACV,CAAC;QAED,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC;YACvB,SAAS;QACV,CAAC;QAED,OAAO,OAAO,CAAC;IAChB,CAAC;IACD,OAAO,OAAO,CAAC;AAAA,CACf;AAED,SAAS,mBAAmB,CAAC,IAAa,EAAE,YAA+B,EAAW;IACrF,IAAI,OAAO,GAAY,IAAI,CAAC;IAC5B,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC,EAAE,CAAC;gBAC1B,OAAO,aAAa,CAAC;YACtB,CAAC;YACD,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;YAC1B,SAAS;QACV,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;YAC9B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACtE,OAAO,aAAa,CAAC;YACtB,CAAC;YACD,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;YACzB,SAAS;QACV,CAAC;QAED,OAAO,aAAa,CAAC;IACtB,CAAC;IACD,OAAO,OAAO,CAAC;AAAA,CACf;AAED,SAAS,cAAc,CAAC,KAAc,EAAU;IAC/C,IAAI,KAAK,KAAK,aAAa;QAAE,OAAO,SAAS,CAAC;IAC9C,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACzC,OAAO,OAAO,KAAK,CAAC;AAAA,CACpB;AAED,SAAS,cAAc,CAAC,MAAe,EAAU;IAChD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC;IACrH,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC;IACxD,IAAI,aAAa,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IACzC,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IACrD,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IAC/C,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,SAAS,kBAAkB,CAC1B,MAA4C,EAC5C,IAAa,EACb,MAAe,EACmB;IAClC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,KAAK,GAAoC,EAAE,CAAC;IAClD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,YAAY,GAAG,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5D,MAAM,cAAc,GAAG,YAAY,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG;YACb,IAAI;YACJ,YAAY,EAAE,cAAc,CAAC,cAAc,CAAC;YAC5C,YAAY,EAAE,cAAc,CAAC,KAAK,CAAC;YACnC,OAAO,EAAE,KAAK,CAAC,OAAO;SACtB,CAAC;QACF,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,YAAY,KAAK,KAAK,CAAC,YAAY,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;QAC5F,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED,SAAS,aAAa,CAAC,MAA4C,EAAY;IAC9E,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAAA,CACjE;AAED,SAAS,aAAa,CAAC,MAAe,EAAyB;IAC9D,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,OAAO,MAAM,CAAC,IAAI,CAAC;IACpB,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAClH,IAAI,KAAK,EAAE,CAAC;QACX,MAAM,MAAM,GAAc,EAAE,CAAC;QAC7B,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;YAC5B,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;YACtC,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBACvD,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,MAAM,CAAC;IACf,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,SAAS,qBAAqB,CAAC,MAAe,EAA2B;IACxE,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,OAAO,EAAE,CAAC;IACX,CAAC;IAED,MAAM,QAAQ,GAA4B,EAAE,CAAC;IAC7C,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,MAAM,EAAE,CAAC;QACZ,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC;QACvB,OAAO,QAAQ,CAAC;IACjB,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,CAAU,EAAE,CAAC;QAC3G,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;YAC/B,QAAQ,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACF,CAAC;IAED,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC/C,IAAI,UAAU,EAAE,CAAC;QAChB,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAChC,QAAQ,CAAC,KAAK,GAAG,qBAAqB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,QAAQ,CAAC;AAAA,CAChB;AAED,SAAS,cAAc,CAAC,MAAe,EAAW;IACjD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,MAAM,CAAC,OAAO,CAAC;IACvB,CAAC;IACD,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,MAAM,EAAE,MAAM,EAAE,CAAC;QACpB,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;IACvE,QAAQ,IAAI,EAAE,CAAC;QACd,KAAK,QAAQ;YACZ,OAAO,EAAE,CAAC;QACX,KAAK,QAAQ;YACZ,OAAO,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,KAAK,SAAS;YACb,OAAO,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3E,KAAK,SAAS;YACb,OAAO,IAAI,CAAC;QACb,KAAK,OAAO;YACX,OAAO,EAAE,CAAC;QACX,KAAK,QAAQ,EAAE,CAAC;YACf,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;YACrD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;gBAC9C,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC;gBAC1D,CAAC,CAAC,EAAE,CAAC;YACN,OAAO,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;QAClG,CAAC;QACD,KAAK,MAAM;YACV,OAAO,IAAI,CAAC;QACb;YACC,OAAO,SAAS,CAAC;IACnB,CAAC;AAAA,CACD;AAED,SAAS,sBAAsB,CAAC,MAA4C,EAAE,IAAa,EAAE,MAAe,EAAU;IACrH,OAAO,CACN,MAAM;SACJ,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,YAAY,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;QACnD,MAAM,cAAc,GAAG,YAAY,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAC1D,MAAM,gBAAgB,GAAG,iBAAiB,CACzC,qBAAqB,CAAC,cAAc,CAAC,EACrC,4BAA4B,CAC5B,CAAC;QACF,MAAM,OAAO,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,iBAAiB,CAAC,mBAAmB,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,yBAAyB,CAAC,CAAC;QACvG,MAAM,WAAW,GAChB,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,iBAAiB,CAAC,OAAO,EAAE,yBAAyB,CAAC,EAAE,CAAC;QACpG,OAAO,OAAO,IAAI,KAAK,KAAK,CAAC,OAAO,sBAAsB,gBAAgB,GAAG,WAAW,eAAe,QAAQ,EAAE,CAAC;IAAA,CAClH,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,IAAI,0BAA0B,CAC1C,CAAC;AAAA,CACF;AAED,SAAS,0BAA0B,CAAC,MAA4C,EAAU;IACzF,OAAO,IAAI,CAAC,SAAS,CACpB,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACtB,IAAI,EAAE,oBAAoB,CAAC,KAAK,CAAC;QACjC,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,OAAO,EAAE,KAAK,CAAC,OAAO;KACtB,CAAC,CAAC,CACH,CAAC;AAAA,CACF;AAED,SAAS,0BAA0B,CAAC,IAAU,EAAU;IACvD,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,qBAAqB,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;IACzG,OAAO,sBAAsB,iBAAiB,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,WAAW,EAAE,CAAC;AAAA,CACtF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAC/B,KAAa,EACb,QAAkB,EAClB,OAAuC,EACb;IAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC,CAAC;IACzD,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,SAAS,QAAQ,CAAC,IAAI,aAAa,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAAA,CACtD;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CACpC,IAAU,EACV,QAAkB,EAClB,OAAuC,EACb;IAC1B,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC;IAChC,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAEhD,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,gBAAgB,GAAG,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAgC,CAAC;IACpF,MAAM,YAAY,GAAG,yBAAyB,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,gBAAgB,CAAC,CAAC;IACvG,MAAM,YAAY,GAAG,kBAAkB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IACtF,MAAM,QAAQ,GACb,OAAO,EAAE,aAAa,KAAK,KAAK;QAC/B,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,mBAAmB,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,SAAS,EAAE,EAAE,CAC1F,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAC1B,CAAC;IACL,IAAI,QAAQ,EAAE,CAAC;QACd,MAAM,cAAc,GAAG,iBAAiB,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAClE,QAAQ,CAAC,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAC1C,CAAC,MAAM,EAAE,EAAE,CACV,aAAa,MAAM,CAAC,IAAI,KAAK,oBAAoB,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,qCAAqC,CACjH,CAAC;QACF,mCAAmC,CAAC,OAAO,EAAE;YAC5C,OAAO,EAAE,UAAU;YACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,YAAY;YACZ,cAAc;SACd,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,CAAC;IACtB,CAAC;IAED,mCAAmC,CAAC,OAAO,EAAE;QAC5C,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,YAAY;QACZ,cAAc,EAAE,EAAE;QAClB,YAAY,EAAE,kBAAkB,CAAC,gBAAgB,EAAE,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC;QACvF,aAAa,EAAE,aAAa,CAAC,gBAAgB,CAAC;KAC9C,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,+BAA+B,QAAQ,CAAC,IAAI,OAAO,sBAAsB,CAC7F,gBAAgB,EAChB,QAAQ,CAAC,SAAS,EAClB,IAAI,CAAC,UAAU,CACf,4BAA4B,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;IAE/F,MAAM,IAAI,2BAA2B,CAAC,YAAY,EAAE;QACnD,QAAQ,EAAE,QAAQ,CAAC,IAAI;QACvB,SAAS,EAAE,0BAA0B,CAAC,gBAAgB,CAAC;QACvD,UAAU,EAAE,0BAA0B,CAAC,IAAI,CAAC;KAC5C,CAAC,CAAC;AAAA,CACH","sourcesContent":["import { Compile } from \"typebox/compile\";\nimport type { TLocalizedValidationError } from \"typebox/error\";\nimport type { Tool, ToolCall } from \"../types.ts\";\nimport { analyzeToolArgumentErrors } from \"./tool-repair/analyzer.ts\";\nimport {\n\tformatToolRepairNote,\n\ttype ToolRepairFailureModeName,\n\ttype ToolRepairModeName,\n} from \"./tool-repair/registry.ts\";\nimport { repairToolArguments } from \"./tool-repair/repairer.ts\";\n\nconst validatorCache = new WeakMap<object, ReturnType<typeof Compile>>();\nconst EXPECTED_FRAGMENT_MAX_LENGTH = 320;\nconst RECEIVED_VALUE_MAX_LENGTH = 200;\nconst MISSING_VALUE = Symbol(\"missing\");\n\nexport type ToolArgumentValidationOutcome = \"clean\" | \"repaired\" | \"bounced\";\nexport type ToolArgumentTeachState = \"none\" | \"note\" | \"rule\";\nexport type ToolArgumentExecutionOutcome = \"not_run\" | \"succeeded\" | \"failed\";\n\nexport interface ToolArgumentFailureShapeEntry {\n\tpath: string;\n\texpectedType: string;\n\treceivedType: string;\n\tkeyword?: string;\n}\n\nexport interface ToolArgumentValidationTelemetryEvent {\n\toutcome: ToolArgumentValidationOutcome;\n\tprovider?: string;\n\tmodel?: string;\n\ttool: string;\n\tsource?: ToolCall[\"source\"];\n\tfailureModes: ToolRepairFailureModeName[];\n\trepairsApplied: ToolRepairModeName[];\n\tfailureShape?: ToolArgumentFailureShapeEntry[];\n\terrorKeywords?: string[];\n\ttaught: ToolArgumentTeachState;\n\texecutionOutcome: ToolArgumentExecutionOutcome;\n}\n\nexport interface ToolArgumentValidationOptions {\n\tmodel?: string;\n\tprovider?: string;\n\ttelemetry?: (event: ToolArgumentValidationTelemetryEvent) => void;\n\t/** Internal emergency diagnostic kill; user settings do not disable deterministic repair. */\n\trepairEnabled?: boolean;\n}\n\nexport class ToolArgumentValidationError extends Error {\n\tpublic readonly toolName: string;\n\tpublic readonly signature: string;\n\tpublic readonly enrichment: string;\n\n\tconstructor(message: string, options: { toolName: string; signature: string; enrichment: string }) {\n\t\tsuper(message);\n\t\tthis.name = \"ToolArgumentValidationError\";\n\t\tthis.toolName = options.toolName;\n\t\tthis.signature = options.signature;\n\t\tthis.enrichment = options.enrichment;\n\t}\n}\n\nfunction emitToolArgumentValidationTelemetry(\n\toptions: ToolArgumentValidationOptions | undefined,\n\tevent: Omit<ToolArgumentValidationTelemetryEvent, \"model\" | \"provider\" | \"taught\" | \"executionOutcome\">,\n): void {\n\ttry {\n\t\toptions?.telemetry?.({\n\t\t\t...event,\n\t\t\tmodel: options.model,\n\t\t\tprovider: options.provider,\n\t\t\ttaught: \"none\",\n\t\t\texecutionOutcome: \"not_run\",\n\t\t});\n\t} catch {\n\t\t// Telemetry is observe-only; never fail validation because a sink failed.\n\t}\n}\n\nfunction uniqueRepairModes(modes: Iterable<ToolRepairModeName>): ToolRepairModeName[] {\n\treturn [...new Set(modes)];\n}\n\nfunction uniqueFailureModes(modes: Iterable<ToolRepairModeName>): ToolRepairFailureModeName[] {\n\tconst uniqueModes = uniqueRepairModes(modes);\n\treturn uniqueModes.length > 0 ? uniqueModes : [\"other\"];\n}\n\nfunction getValidator(schema: Tool[\"parameters\"]): ReturnType<typeof Compile> {\n\tconst key = schema as object;\n\tconst cached = validatorCache.get(key);\n\tif (cached) {\n\t\treturn cached;\n\t}\n\tconst validator = Compile(schema);\n\tvalidatorCache.set(key, validator);\n\treturn validator;\n}\n\nfunction formatValidationPath(error: TLocalizedValidationError): string {\n\tif (error.keyword === \"required\") {\n\t\tconst requiredProperties = (error.params as { requiredProperties?: string[] }).requiredProperties;\n\t\tconst requiredProperty = requiredProperties?.[0];\n\t\tif (requiredProperty) {\n\t\t\tconst basePath = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\t\t\treturn basePath ? `${basePath}.${requiredProperty}` : requiredProperty;\n\t\t}\n\t}\n\tconst path = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\treturn path || \"root\";\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value)\n\t\t? (value as Record<string, unknown>)\n\t\t: undefined;\n}\n\nfunction truncateText(text: string, maxLength: number): string {\n\tif (text.length <= maxLength) {\n\t\treturn text;\n\t}\n\treturn `${text.slice(0, maxLength)}...[truncated]`;\n}\n\nfunction formatCompactJson(value: unknown, maxLength: number): string {\n\tif (value === MISSING_VALUE) {\n\t\treturn \"<missing>\";\n\t}\n\tif (value === undefined) {\n\t\treturn \"undefined\";\n\t}\n\treturn truncateText(JSON.stringify(value), maxLength);\n}\n\nfunction validationPathSegments(error: TLocalizedValidationError): string[] {\n\tconst path = formatValidationPath(error);\n\treturn path === \"root\" ? [] : path.split(\".\");\n}\n\nfunction schemaAtPath(schema: unknown, pathSegments: readonly string[]): unknown {\n\tlet current: unknown = schema;\n\tfor (const segment of pathSegments) {\n\t\tconst record = asRecord(current);\n\t\tif (!record) {\n\t\t\treturn current;\n\t\t}\n\n\t\tconst properties = asRecord(record.properties);\n\t\tif (properties && segment in properties) {\n\t\t\tcurrent = properties[segment];\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (record.items !== undefined) {\n\t\t\tcurrent = record.items;\n\t\t\tcontinue;\n\t\t}\n\n\t\treturn current;\n\t}\n\treturn current;\n}\n\nfunction receivedValueAtPath(args: unknown, pathSegments: readonly string[]): unknown {\n\tlet current: unknown = args;\n\tfor (const segment of pathSegments) {\n\t\tconst record = asRecord(current);\n\t\tif (record) {\n\t\t\tif (!(segment in record)) {\n\t\t\t\treturn MISSING_VALUE;\n\t\t\t}\n\t\t\tcurrent = record[segment];\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (Array.isArray(current)) {\n\t\t\tconst index = Number(segment);\n\t\t\tif (!Number.isInteger(index) || index < 0 || index >= current.length) {\n\t\t\t\treturn MISSING_VALUE;\n\t\t\t}\n\t\t\tcurrent = current[index];\n\t\t\tcontinue;\n\t\t}\n\n\t\treturn MISSING_VALUE;\n\t}\n\treturn current;\n}\n\nfunction receivedTypeOf(value: unknown): string {\n\tif (value === MISSING_VALUE) return \"missing\";\n\tif (value === null) return \"null\";\n\tif (Array.isArray(value)) return \"array\";\n\treturn typeof value;\n}\n\nfunction expectedTypeOf(schema: unknown): string {\n\tconst record = asRecord(schema);\n\tif (!record) return \"unknown\";\n\tif (Array.isArray(record.type)) return record.type.filter((type) => typeof type === \"string\").join(\"|\") || \"unknown\";\n\tif (typeof record.type === \"string\") return record.type;\n\tif (literalValues(record)) return \"enum\";\n\tif (record.properties !== undefined) return \"object\";\n\tif (record.items !== undefined) return \"array\";\n\treturn \"unknown\";\n}\n\nfunction formatFailureShape(\n\terrors: readonly TLocalizedValidationError[],\n\targs: unknown,\n\tschema: unknown,\n): ToolArgumentFailureShapeEntry[] {\n\tconst seen = new Set<string>();\n\tconst shape: ToolArgumentFailureShapeEntry[] = [];\n\tfor (const error of errors) {\n\t\tconst path = formatValidationPath(error);\n\t\tconst pathSegments = path === \"root\" ? [] : path.split(\".\");\n\t\tconst expectedSchema = schemaAtPath(schema, pathSegments);\n\t\tconst value = receivedValueAtPath(args, pathSegments);\n\t\tconst entry = {\n\t\t\tpath,\n\t\t\texpectedType: expectedTypeOf(expectedSchema),\n\t\t\treceivedType: receivedTypeOf(value),\n\t\t\tkeyword: error.keyword,\n\t\t};\n\t\tconst key = `${entry.path}\\0${entry.expectedType}\\0${entry.receivedType}\\0${entry.keyword}`;\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tshape.push(entry);\n\t}\n\treturn shape;\n}\n\nfunction errorKeywords(errors: readonly TLocalizedValidationError[]): string[] {\n\treturn [...new Set(errors.map((error) => error.keyword))].sort();\n}\n\nfunction literalValues(schema: unknown): unknown[] | undefined {\n\tconst record = asRecord(schema);\n\tif (!record) {\n\t\treturn undefined;\n\t}\n\tif (Array.isArray(record.enum)) {\n\t\treturn record.enum;\n\t}\n\tif (record.const !== undefined) {\n\t\treturn [record.const];\n\t}\n\tconst anyOf = Array.isArray(record.anyOf) ? record.anyOf : Array.isArray(record.oneOf) ? record.oneOf : undefined;\n\tif (anyOf) {\n\t\tconst values: unknown[] = [];\n\t\tfor (const option of anyOf) {\n\t\t\tconst optionRecord = asRecord(option);\n\t\t\tif (!optionRecord || optionRecord.const === undefined) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tvalues.push(optionRecord.const);\n\t\t}\n\t\treturn values;\n\t}\n\treturn undefined;\n}\n\nfunction compactSchemaFragment(schema: unknown): Record<string, unknown> {\n\tconst record = asRecord(schema);\n\tif (!record) {\n\t\treturn {};\n\t}\n\n\tconst fragment: Record<string, unknown> = {};\n\tconst values = literalValues(record);\n\tif (values) {\n\t\tfragment.enum = values;\n\t\treturn fragment;\n\t}\n\n\tfor (const key of [\"type\", \"required\", \"minimum\", \"maximum\", \"minLength\", \"maxLength\", \"format\"] as const) {\n\t\tif (record[key] !== undefined) {\n\t\t\tfragment[key] = record[key];\n\t\t}\n\t}\n\n\tconst properties = asRecord(record.properties);\n\tif (properties) {\n\t\tfragment.properties = Object.keys(properties);\n\t}\n\tif (record.items !== undefined) {\n\t\tfragment.items = compactSchemaFragment(record.items);\n\t}\n\treturn fragment;\n}\n\nfunction minimalExample(schema: unknown): unknown {\n\tconst record = asRecord(schema);\n\tif (!record) {\n\t\treturn undefined;\n\t}\n\tif (record.default !== undefined) {\n\t\treturn record.default;\n\t}\n\tconst values = literalValues(record);\n\tif (values?.length) {\n\t\treturn values[0];\n\t}\n\n\tconst type = Array.isArray(record.type) ? record.type[0] : record.type;\n\tswitch (type) {\n\t\tcase \"string\":\n\t\t\treturn \"\";\n\t\tcase \"number\":\n\t\t\treturn typeof record.minimum === \"number\" ? record.minimum : 0;\n\t\tcase \"integer\":\n\t\t\treturn typeof record.minimum === \"number\" ? Math.ceil(record.minimum) : 0;\n\t\tcase \"boolean\":\n\t\t\treturn true;\n\t\tcase \"array\":\n\t\t\treturn [];\n\t\tcase \"object\": {\n\t\t\tconst properties = asRecord(record.properties) ?? {};\n\t\t\tconst required = Array.isArray(record.required)\n\t\t\t\t? record.required.filter((key) => typeof key === \"string\")\n\t\t\t\t: [];\n\t\t\treturn Object.fromEntries(required.map((key) => [key, minimalExample(properties[key]) ?? null]));\n\t\t}\n\t\tcase \"null\":\n\t\t\treturn null;\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nfunction formatValidationErrors(errors: readonly TLocalizedValidationError[], args: unknown, schema: unknown): string {\n\treturn (\n\t\terrors\n\t\t\t.map((error) => {\n\t\t\t\tconst path = formatValidationPath(error);\n\t\t\t\tconst pathSegments = validationPathSegments(error);\n\t\t\t\tconst expectedSchema = schemaAtPath(schema, pathSegments);\n\t\t\t\tconst expectedFragment = formatCompactJson(\n\t\t\t\t\tcompactSchemaFragment(expectedSchema),\n\t\t\t\t\tEXPECTED_FRAGMENT_MAX_LENGTH,\n\t\t\t\t);\n\t\t\t\tconst example = minimalExample(expectedSchema);\n\t\t\t\tconst received = formatCompactJson(receivedValueAtPath(args, pathSegments), RECEIVED_VALUE_MAX_LENGTH);\n\t\t\t\tconst exampleText =\n\t\t\t\t\texample === undefined ? \"\" : `; Example: ${formatCompactJson(example, RECEIVED_VALUE_MAX_LENGTH)}`;\n\t\t\t\treturn ` - ${path}: ${error.message}; Expected schema: ${expectedFragment}${exampleText}; Received: ${received}`;\n\t\t\t})\n\t\t\t.join(\"\\n\") || \"Unknown validation error\"\n\t);\n}\n\nfunction validationFailureSignature(errors: readonly TLocalizedValidationError[]): string {\n\treturn JSON.stringify(\n\t\terrors.map((error) => ({\n\t\t\tpath: formatValidationPath(error),\n\t\t\tkeyword: error.keyword,\n\t\t\tmessage: error.message,\n\t\t})),\n\t);\n}\n\nfunction formatValidationEnrichment(tool: Tool): string {\n\tconst example = minimalExample(tool.parameters);\n\tconst exampleText = example === undefined ? \"\" : `\\nValid example:\\n${formatCompactJson(example, 2000)}`;\n\treturn `Full tool schema:\\n${formatCompactJson(tool.parameters, 4000)}${exampleText}`;\n}\n\n/**\n * Finds a tool by name and validates the tool call arguments against its TypeBox schema\n * @param tools Array of tool definitions\n * @param toolCall The tool call from the LLM\n * @returns The validated arguments\n * @throws Error if tool is not found or validation fails\n */\nexport function validateToolCall(\n\ttools: Tool[],\n\ttoolCall: ToolCall,\n\toptions?: ToolArgumentValidationOptions,\n): Record<string, unknown> {\n\tconst tool = tools.find((t) => t.name === toolCall.name);\n\tif (!tool) {\n\t\tthrow new Error(`Tool \"${toolCall.name}\" not found`);\n\t}\n\treturn validateToolArguments(tool, toolCall, options);\n}\n\n/**\n * Validates tool call arguments against the tool's TypeBox schema.\n *\n * The hot path is validate-first and allocation-free: valid arguments return the exact\n * argument object emitted by the model. Only invalid calls enter the deterministic\n * repair layer, which applies named, guard-checked shape repairs on a clone.\n *\n * @param tool The tool definition with TypeBox schema\n * @param toolCall The tool call from the LLM\n * @returns The validated (and potentially repaired) arguments\n * @throws Error with formatted message if validation fails\n */\nexport function validateToolArguments(\n\ttool: Tool,\n\ttoolCall: ToolCall,\n\toptions?: ToolArgumentValidationOptions,\n): Record<string, unknown> {\n\tconst args = toolCall.arguments;\n\tconst validator = getValidator(tool.parameters);\n\n\tif (validator.Check(args)) {\n\t\treturn args;\n\t}\n\n\tconst validationErrors = [...validator.Errors(args)] as TLocalizedValidationError[];\n\tconst repairIssues = analyzeToolArgumentErrors(toolCall.name, tool.parameters, args, validationErrors);\n\tconst failureModes = uniqueFailureModes(repairIssues.flatMap((issue) => issue.modes));\n\tconst repaired =\n\t\toptions?.repairEnabled === false\n\t\t\t? undefined\n\t\t\t: repairToolArguments(toolCall.name, tool.parameters, args, validationErrors, (candidate) =>\n\t\t\t\t\tvalidator.Check(candidate),\n\t\t\t\t);\n\tif (repaired) {\n\t\tconst repairsApplied = uniqueRepairModes(repaired.repairsApplied);\n\t\ttoolCall.repairNotes = repaired.repairs.map(\n\t\t\t(repair) =>\n\t\t\t\t`[harness] ${repair.name}: ${formatToolRepairNote(repair.name, repair.path)}; executed with repaired arguments.`,\n\t\t);\n\t\temitToolArgumentValidationTelemetry(options, {\n\t\t\toutcome: \"repaired\",\n\t\t\ttool: toolCall.name,\n\t\t\tsource: toolCall.source,\n\t\t\tfailureModes,\n\t\t\trepairsApplied,\n\t\t});\n\t\treturn repaired.args;\n\t}\n\n\temitToolArgumentValidationTelemetry(options, {\n\t\toutcome: \"bounced\",\n\t\ttool: toolCall.name,\n\t\tsource: toolCall.source,\n\t\tfailureModes,\n\t\trepairsApplied: [],\n\t\tfailureShape: formatFailureShape(validationErrors, toolCall.arguments, tool.parameters),\n\t\terrorKeywords: errorKeywords(validationErrors),\n\t});\n\n\tconst errorMessage = `Validation failed for tool \"${toolCall.name}\":\\n${formatValidationErrors(\n\t\tvalidationErrors,\n\t\ttoolCall.arguments,\n\t\ttool.parameters,\n\t)}\\n\\nReceived arguments:\\n${truncateText(JSON.stringify(toolCall.arguments, null, 2), 2000)}`;\n\n\tthrow new ToolArgumentValidationError(errorMessage, {\n\t\ttoolName: toolCall.name,\n\t\tsignature: validationFailureSignature(validationErrors),\n\t\tenrichment: formatValidationEnrichment(tool),\n\t});\n}\n"]}
|