@copilotkit/aimock 1.33.0 → 1.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +4 -0
  3. package/dist/agui-types.d.cts.map +1 -1
  4. package/dist/bedrock-converse.cjs +2 -2
  5. package/dist/bedrock-converse.cjs.map +1 -1
  6. package/dist/bedrock-converse.d.cts.map +1 -1
  7. package/dist/bedrock-converse.d.ts.map +1 -1
  8. package/dist/bedrock-converse.js +3 -3
  9. package/dist/bedrock-converse.js.map +1 -1
  10. package/dist/bedrock.cjs +2 -2
  11. package/dist/bedrock.cjs.map +1 -1
  12. package/dist/bedrock.d.cts.map +1 -1
  13. package/dist/bedrock.d.ts.map +1 -1
  14. package/dist/bedrock.js +3 -3
  15. package/dist/bedrock.js.map +1 -1
  16. package/dist/cohere.cjs +2 -2
  17. package/dist/cohere.cjs.map +1 -1
  18. package/dist/cohere.js +3 -3
  19. package/dist/cohere.js.map +1 -1
  20. package/dist/config-loader.d.cts.map +1 -1
  21. package/dist/config-loader.d.ts.map +1 -1
  22. package/dist/gemini-interactions.cjs +71 -70
  23. package/dist/gemini-interactions.cjs.map +1 -1
  24. package/dist/gemini-interactions.d.cts.map +1 -1
  25. package/dist/gemini-interactions.d.ts.map +1 -1
  26. package/dist/gemini-interactions.js +71 -70
  27. package/dist/gemini-interactions.js.map +1 -1
  28. package/dist/gemini.cjs +1 -1
  29. package/dist/gemini.cjs.map +1 -1
  30. package/dist/gemini.js +2 -2
  31. package/dist/gemini.js.map +1 -1
  32. package/dist/messages.cjs +1 -1
  33. package/dist/messages.cjs.map +1 -1
  34. package/dist/messages.js +2 -2
  35. package/dist/messages.js.map +1 -1
  36. package/dist/ollama.cjs +3 -3
  37. package/dist/ollama.cjs.map +1 -1
  38. package/dist/ollama.d.cts.map +1 -1
  39. package/dist/ollama.d.ts.map +1 -1
  40. package/dist/ollama.js +4 -4
  41. package/dist/ollama.js.map +1 -1
  42. package/dist/responses.cjs +1 -1
  43. package/dist/responses.cjs.map +1 -1
  44. package/dist/responses.js +2 -2
  45. package/dist/responses.js.map +1 -1
  46. package/dist/router.cjs +236 -33
  47. package/dist/router.cjs.map +1 -1
  48. package/dist/router.d.cts +54 -2
  49. package/dist/router.d.cts.map +1 -1
  50. package/dist/router.d.ts +54 -2
  51. package/dist/router.d.ts.map +1 -1
  52. package/dist/router.js +236 -34
  53. package/dist/router.js.map +1 -1
  54. package/dist/server.cjs +1 -1
  55. package/dist/server.cjs.map +1 -1
  56. package/dist/server.d.cts.map +1 -1
  57. package/dist/server.d.ts.map +1 -1
  58. package/dist/server.js +2 -2
  59. package/dist/server.js.map +1 -1
  60. package/dist/stream-collapse.cjs +56 -6
  61. package/dist/stream-collapse.cjs.map +1 -1
  62. package/dist/stream-collapse.d.cts +10 -3
  63. package/dist/stream-collapse.d.cts.map +1 -1
  64. package/dist/stream-collapse.d.ts +10 -3
  65. package/dist/stream-collapse.d.ts.map +1 -1
  66. package/dist/stream-collapse.js +56 -6
  67. package/dist/stream-collapse.js.map +1 -1
  68. package/dist/vector-types.d.ts.map +1 -1
  69. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"responses.js","names":[],"sources":["../src/responses.ts"],"sourcesContent":["/**\n * OpenAI Responses API support for aimock.\n *\n * Translates incoming /v1/responses requests into the ChatCompletionRequest\n * format used by the fixture router, and converts fixture responses back into\n * the Responses API streaming (or non-streaming) format expected by @ai-sdk/openai.\n */\n\nimport type * as http from \"node:http\";\nimport type {\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n HandlerDefaults,\n ResponseOverrides,\n StreamingProfile,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n generateId,\n generateToolCallId,\n extractOverrides,\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n serializeErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n resolveReasoningForModel,\n strictOverrideField,\n getContext,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport { writeErrorResponse, delay, calculateDelay } from \"./sse-writer.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\nimport type { RecordedTimings } from \"./types.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n// ─── Responses API request types ────────────────────────────────────────────\n\ninterface ResponsesInputItem {\n role?: string;\n type?: string;\n content?: string | ResponsesContentPart[];\n call_id?: string;\n name?: string;\n arguments?: string;\n output?: string;\n id?: string;\n}\n\ninterface ResponsesContentPart {\n type: string;\n text?: string;\n}\n\ninterface ResponsesRequest {\n model: string;\n input: string | ResponsesInputItem[];\n instructions?: string;\n tools?: ResponsesToolDef[];\n tool_choice?: string | object;\n stream?: boolean;\n temperature?: number;\n max_output_tokens?: number;\n response_format?: { type: string; [key: string]: unknown };\n [key: string]: unknown;\n}\n\ninterface ResponsesToolDef {\n type: \"function\";\n name: string;\n description?: string;\n parameters?: object;\n strict?: boolean;\n}\n\n// ─── Input conversion: Responses → ChatCompletions messages ─────────────────\n\nfunction extractTextContent(content: string | ResponsesContentPart[] | undefined): string {\n if (!content) return \"\";\n if (typeof content === \"string\") return content;\n return content\n .filter((p) => p.type === \"input_text\" || p.type === \"output_text\")\n .map((p) => p.text ?? \"\")\n .join(\"\");\n}\n\nexport function responsesInputToMessages(req: ResponsesRequest): ChatMessage[] {\n const messages: ChatMessage[] = [];\n // Track item_reference placeholders so we can upgrade or clean them up\n const itemReferencePlaceholders = new WeakSet<ChatMessage>();\n\n // instructions field → system message\n if (req.instructions) {\n messages.push({ role: \"system\", content: req.instructions });\n }\n\n // The OpenAI Responses API accepts either a plain string or an array of input items.\n // When a string is passed, treat it as a single user message.\n if (typeof req.input === \"string\") {\n messages.push({ role: \"user\", content: req.input });\n return messages;\n }\n\n for (const item of req.input) {\n if (item.role === \"system\" || item.role === \"developer\") {\n messages.push({ role: \"system\", content: extractTextContent(item.content) });\n } else if (item.role === \"user\") {\n messages.push({ role: \"user\", content: extractTextContent(item.content) });\n } else if (item.role === \"assistant\") {\n messages.push({ role: \"assistant\", content: extractTextContent(item.content) });\n } else if (item.type === \"function_call\") {\n // Previous assistant tool call — emit as assistant message with tool_calls\n messages.push({\n role: \"assistant\",\n content: null,\n tool_calls: [\n {\n id: item.call_id ?? generateToolCallId(),\n type: \"function\",\n function: { name: item.name ?? \"\", arguments: item.arguments ?? \"\" },\n },\n ],\n });\n } else if (item.type === \"function_call_output\") {\n // Bug 1 fix: If there's no preceding assistant message with a matching\n // tool_call for this call_id, synthesize one. This happens when the AI SDK\n // sends [user, item_reference, function_call_output] — the item_reference\n // placeholder (see below) has no tool_calls, so we need a real assistant\n // message with the tool_call for turnIndex counting.\n const hasMatchingToolCall = messages.some(\n (m) => m.role === \"assistant\" && m.tool_calls?.some((tc) => tc.id === item.call_id),\n );\n if (!hasMatchingToolCall) {\n // Check if the last message is an item_reference placeholder — if so,\n // upgrade it to carry the tool_call instead of synthesizing a duplicate.\n const lastMsg = messages[messages.length - 1];\n if (\n lastMsg &&\n lastMsg.role === \"assistant\" &&\n itemReferencePlaceholders.has(lastMsg) &&\n !lastMsg.tool_calls\n ) {\n lastMsg.content = null;\n lastMsg.tool_calls = [\n {\n id: item.call_id ?? generateToolCallId(),\n type: \"function\",\n function: { name: \"\", arguments: \"\" },\n },\n ];\n itemReferencePlaceholders.delete(lastMsg);\n } else {\n // Multi-fco case: look for a recent assistant with tool_calls that\n // belongs to the same turn. After the first fco upgrades a placeholder,\n // subsequent fco's see [assistant(call_A), tool(call_A)] — the last\n // assistant with tool_calls (right before the trailing tool messages)\n // is the correct target.\n let appended = false;\n for (let k = messages.length - 1; k >= 0; k--) {\n const m = messages[k];\n if (m.role === \"assistant\" && m.tool_calls) {\n m.tool_calls.push({\n id: item.call_id ?? generateToolCallId(),\n type: \"function\",\n function: { name: \"\", arguments: \"\" },\n });\n appended = true;\n break;\n }\n // Stop scanning if we hit a user message — different turn\n if (m.role === \"user\") break;\n }\n if (!appended) {\n messages.push({\n role: \"assistant\",\n content: null,\n tool_calls: [\n {\n id: item.call_id ?? generateToolCallId(),\n type: \"function\",\n function: { name: \"\", arguments: \"\" },\n },\n ],\n });\n }\n }\n }\n messages.push({\n role: \"tool\",\n content: item.output ?? \"\",\n tool_call_id: item.call_id,\n });\n } else if (item.type === \"item_reference\") {\n // Bug 6 fix: item_reference items represent prior assistant turns (text\n // or function_call). Push a placeholder so they count in assistantCount.\n // If a subsequent function_call_output arrives, the handler above will\n // upgrade this placeholder to carry tool_calls (avoiding double-count).\n const placeholder: ChatMessage = { role: \"assistant\", content: \"\" };\n itemReferencePlaceholders.add(placeholder);\n messages.push(placeholder);\n } else {\n // Skip local_shell_call, mcp_list_tools, etc. — not needed for fixture\n // matching.\n }\n }\n\n return messages;\n}\n\nfunction responsesToolsToCompletionsTools(\n tools?: ResponsesToolDef[],\n): ToolDefinition[] | undefined {\n if (!tools || tools.length === 0) return undefined;\n return tools\n .filter((t) => t.type === \"function\")\n .map((t) => ({\n type: \"function\" as const,\n function: { name: t.name, description: t.description, parameters: t.parameters },\n }));\n}\n\nexport function responsesToCompletionRequest(req: ResponsesRequest): ChatCompletionRequest {\n return {\n model: req.model,\n messages: responsesInputToMessages(req),\n stream: req.stream,\n temperature: req.temperature,\n max_tokens: req.max_output_tokens,\n tools: responsesToolsToCompletionsTools(req.tools),\n tool_choice: req.tool_choice,\n response_format: req.response_format,\n };\n}\n\n// ─── Response building: fixture → Responses API format ──────────────────────\n\nfunction responsesStatus(finishReason: string | undefined, defaultStatus: string): string {\n if (!finishReason) return defaultStatus;\n if (finishReason === \"stop\") return \"completed\";\n if (finishReason === \"tool_calls\") return \"completed\";\n if (finishReason === \"length\") return \"incomplete\";\n if (finishReason === \"content_filter\") return \"failed\";\n return finishReason;\n}\n\nfunction responsesUsage(overrides?: ResponseOverrides): {\n input_tokens: number;\n output_tokens: number;\n total_tokens: number;\n} {\n if (!overrides?.usage) return { input_tokens: 0, output_tokens: 0, total_tokens: 0 };\n const input = overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? 0;\n const output = overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? 0;\n return {\n input_tokens: input,\n output_tokens: output,\n total_tokens: overrides.usage.total_tokens ?? input + output,\n };\n}\n\nfunction responseId(): string {\n return generateId(\"resp\");\n}\n\nfunction itemId(): string {\n return generateId(\"msg\");\n}\n\n// Streaming events for Responses API\n\nexport interface ResponsesSSEEvent {\n type: string;\n [key: string]: unknown;\n}\n\nexport function buildTextStreamEvents(\n content: string,\n model: string,\n chunkSize: number,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): ResponsesSSEEvent[] {\n const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(\n model,\n chunkSize,\n reasoning,\n webSearches,\n overrides,\n );\n\n const { events: msgEvents, msgItem } = buildMessageOutputEvents(\n content,\n chunkSize,\n nextOutputIndex,\n );\n events.push(...msgEvents);\n\n events.push({\n type: \"response.completed\",\n response: {\n id: respId,\n object: \"response\",\n created_at: created,\n model: overrides?.model ?? model,\n status: responsesStatus(overrides?.finishReason, \"completed\"),\n output: [...prefixOutputItems, msgItem],\n usage: responsesUsage(overrides),\n },\n });\n\n return events;\n}\n\nexport function buildToolCallStreamEvents(\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): ResponsesSSEEvent[] {\n const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(\n model,\n chunkSize,\n reasoning,\n webSearches,\n overrides,\n );\n\n const fcOutputItems: object[] = [];\n\n for (let idx = 0; idx < toolCalls.length; idx++) {\n const tc = toolCalls[idx];\n const callId = tc.id || generateToolCallId();\n const fcId = generateId(\"fc\");\n const outputIndex = nextOutputIndex + idx;\n\n // output_item.added (function_call)\n events.push({\n type: \"response.output_item.added\",\n output_index: outputIndex,\n item: {\n type: \"function_call\",\n id: fcId,\n call_id: callId,\n name: tc.name,\n arguments: \"\",\n status: \"in_progress\",\n },\n });\n\n // function_call_arguments.delta\n const args = tc.arguments;\n for (let i = 0; i < args.length; i += chunkSize) {\n const slice = args.slice(i, i + chunkSize);\n events.push({\n type: \"response.function_call_arguments.delta\",\n item_id: fcId,\n output_index: outputIndex,\n delta: slice,\n });\n }\n\n // function_call_arguments.done\n events.push({\n type: \"response.function_call_arguments.done\",\n item_id: fcId,\n output_index: outputIndex,\n arguments: args,\n });\n\n const doneItem = {\n type: \"function_call\",\n id: fcId,\n call_id: callId,\n name: tc.name,\n arguments: args,\n status: \"completed\",\n };\n\n // output_item.done\n events.push({\n type: \"response.output_item.done\",\n output_index: outputIndex,\n item: doneItem,\n });\n\n fcOutputItems.push(doneItem);\n }\n\n // response.completed\n events.push({\n type: \"response.completed\",\n response: {\n id: respId,\n object: \"response\",\n created_at: created,\n model: overrides?.model ?? model,\n status: responsesStatus(overrides?.finishReason, \"completed\"),\n output: [...prefixOutputItems, ...fcOutputItems],\n usage: responsesUsage(overrides),\n },\n });\n\n return events;\n}\n\nfunction buildReasoningStreamEvents(\n reasoning: string,\n model: string,\n chunkSize: number,\n): ResponsesSSEEvent[] {\n const reasoningId = generateId(\"rs\");\n const events: ResponsesSSEEvent[] = [];\n\n events.push({\n type: \"response.output_item.added\",\n output_index: 0,\n item: {\n type: \"reasoning\",\n id: reasoningId,\n summary: [],\n },\n });\n\n events.push({\n type: \"response.reasoning_summary_part.added\",\n item_id: reasoningId,\n output_index: 0,\n summary_index: 0,\n part: { type: \"summary_text\", text: \"\" },\n });\n\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"response.reasoning_summary_text.delta\",\n item_id: reasoningId,\n output_index: 0,\n summary_index: 0,\n delta: slice,\n });\n }\n\n events.push({\n type: \"response.reasoning_summary_text.done\",\n item_id: reasoningId,\n output_index: 0,\n summary_index: 0,\n text: reasoning,\n });\n\n events.push({\n type: \"response.reasoning_summary_part.done\",\n item_id: reasoningId,\n output_index: 0,\n summary_index: 0,\n part: { type: \"summary_text\", text: reasoning },\n });\n\n events.push({\n type: \"response.output_item.done\",\n output_index: 0,\n item: {\n type: \"reasoning\",\n id: reasoningId,\n summary: [{ type: \"summary_text\", text: reasoning }],\n },\n });\n\n return events;\n}\n\nfunction buildWebSearchStreamEvents(\n queries: string[],\n startOutputIndex: number,\n): ResponsesSSEEvent[] {\n const events: ResponsesSSEEvent[] = [];\n\n for (let i = 0; i < queries.length; i++) {\n const searchId = generateId(\"ws\");\n const outputIndex = startOutputIndex + i;\n\n events.push({\n type: \"response.output_item.added\",\n output_index: outputIndex,\n item: {\n type: \"web_search_call\",\n id: searchId,\n status: \"in_progress\",\n action: { type: \"search\", query: queries[i] },\n },\n });\n\n events.push({\n type: \"response.output_item.done\",\n output_index: outputIndex,\n item: {\n type: \"web_search_call\",\n id: searchId,\n status: \"completed\",\n action: { type: \"search\", query: queries[i] },\n },\n });\n }\n\n return events;\n}\n\n// ─── Shared streaming helpers ────────────────────────────────────────────────\n\ninterface PreambleResult {\n respId: string;\n created: number;\n events: ResponsesSSEEvent[];\n prefixOutputItems: object[];\n nextOutputIndex: number;\n}\n\nfunction buildResponsePreamble(\n model: string,\n chunkSize: number,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): PreambleResult {\n const respId = overrides?.id ?? responseId();\n const created = overrides?.created ?? Math.floor(Date.now() / 1000);\n const effectiveModel = overrides?.model ?? model;\n const events: ResponsesSSEEvent[] = [];\n const prefixOutputItems: object[] = [];\n let nextOutputIndex = 0;\n\n events.push({\n type: \"response.created\",\n response: {\n id: respId,\n object: \"response\",\n created_at: created,\n model: effectiveModel,\n status: \"in_progress\",\n output: [],\n },\n });\n events.push({\n type: \"response.in_progress\",\n response: {\n id: respId,\n object: \"response\",\n created_at: created,\n model: effectiveModel,\n status: \"in_progress\",\n output: [],\n },\n });\n\n if (reasoning) {\n const reasoningEvents = buildReasoningStreamEvents(reasoning, model, chunkSize);\n events.push(...reasoningEvents);\n const doneEvent = reasoningEvents.find(\n (e) =>\n e.type === \"response.output_item.done\" &&\n (e.item as { type: string })?.type === \"reasoning\",\n );\n if (doneEvent) prefixOutputItems.push(doneEvent.item as object);\n nextOutputIndex++;\n }\n\n if (webSearches && webSearches.length > 0) {\n const searchEvents = buildWebSearchStreamEvents(webSearches, nextOutputIndex);\n events.push(...searchEvents);\n const doneEvents = searchEvents.filter(\n (e) =>\n e.type === \"response.output_item.done\" &&\n (e.item as { type: string })?.type === \"web_search_call\",\n );\n for (const de of doneEvents) prefixOutputItems.push(de.item as object);\n nextOutputIndex += webSearches.length;\n }\n\n return { respId, created, events, prefixOutputItems, nextOutputIndex };\n}\n\ninterface MessageBlockResult {\n events: ResponsesSSEEvent[];\n msgItem: object;\n}\n\nfunction buildMessageOutputEvents(\n content: string,\n chunkSize: number,\n outputIndex: number,\n): MessageBlockResult {\n const msgId = itemId();\n const events: ResponsesSSEEvent[] = [];\n\n events.push({\n type: \"response.output_item.added\",\n output_index: outputIndex,\n item: { type: \"message\", id: msgId, status: \"in_progress\", role: \"assistant\", content: [] },\n });\n events.push({\n type: \"response.content_part.added\",\n item_id: msgId,\n output_index: outputIndex,\n content_index: 0,\n part: { type: \"output_text\", text: \"\", annotations: [] },\n });\n\n for (let i = 0; i < content.length; i += chunkSize) {\n events.push({\n type: \"response.output_text.delta\",\n item_id: msgId,\n output_index: outputIndex,\n content_index: 0,\n delta: content.slice(i, i + chunkSize),\n });\n }\n\n events.push({\n type: \"response.output_text.done\",\n item_id: msgId,\n output_index: outputIndex,\n content_index: 0,\n text: content,\n });\n events.push({\n type: \"response.content_part.done\",\n item_id: msgId,\n output_index: outputIndex,\n content_index: 0,\n part: { type: \"output_text\", text: content, annotations: [] },\n });\n\n const msgItem = {\n type: \"message\",\n id: msgId,\n status: \"completed\",\n role: \"assistant\",\n content: [{ type: \"output_text\", text: content, annotations: [] }],\n };\n\n events.push({ type: \"response.output_item.done\", output_index: outputIndex, item: msgItem });\n\n return { events, msgItem };\n}\n\n// ─── Non-streaming response builders ────────────────────────────────────────\n\nfunction buildOutputPrefix(content: string, reasoning?: string, webSearches?: string[]): object[] {\n const output: object[] = [];\n\n if (reasoning) {\n output.push({\n type: \"reasoning\",\n id: generateId(\"rs\"),\n summary: [{ type: \"summary_text\", text: reasoning }],\n });\n }\n\n if (webSearches && webSearches.length > 0) {\n for (const query of webSearches) {\n output.push({\n type: \"web_search_call\",\n id: generateId(\"ws\"),\n status: \"completed\",\n action: { type: \"search\", query },\n });\n }\n }\n\n output.push({\n type: \"message\",\n id: itemId(),\n status: \"completed\",\n role: \"assistant\",\n content: [{ type: \"output_text\", text: content, annotations: [] }],\n });\n\n return output;\n}\n\nfunction buildResponseEnvelope(\n model: string,\n output: object[],\n overrides?: ResponseOverrides,\n): object {\n return {\n id: overrides?.id ?? responseId(),\n object: \"response\",\n created_at: overrides?.created ?? Math.floor(Date.now() / 1000),\n model: overrides?.model ?? model,\n status: responsesStatus(overrides?.finishReason, \"completed\"),\n output,\n usage: responsesUsage(overrides),\n };\n}\n\nfunction buildTextResponse(\n content: string,\n model: string,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): object {\n return buildResponseEnvelope(\n model,\n buildOutputPrefix(content, reasoning, webSearches),\n overrides,\n );\n}\n\nfunction buildToolCallResponse(\n toolCalls: ToolCall[],\n model: string,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): object {\n const output: object[] = [];\n if (reasoning) {\n output.push({\n type: \"reasoning\",\n id: generateId(\"rs\"),\n summary: [{ type: \"summary_text\", text: reasoning }],\n });\n }\n if (webSearches && webSearches.length > 0) {\n for (const query of webSearches) {\n output.push({\n type: \"web_search_call\",\n id: generateId(\"ws\"),\n status: \"completed\",\n action: { type: \"search\", query },\n });\n }\n }\n for (const tc of toolCalls) {\n output.push({\n type: \"function_call\",\n id: generateId(\"fc\"),\n call_id: tc.id || generateToolCallId(),\n name: tc.name,\n arguments: tc.arguments,\n status: \"completed\",\n });\n }\n return buildResponseEnvelope(model, output, overrides);\n}\n\nexport function buildContentWithToolCallsStreamEvents(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): ResponsesSSEEvent[] {\n const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(\n model,\n chunkSize,\n reasoning,\n webSearches,\n overrides,\n );\n\n const { events: msgEvents, msgItem } = buildMessageOutputEvents(\n content,\n chunkSize,\n nextOutputIndex,\n );\n events.push(...msgEvents);\n\n const fcOutputItems: object[] = [];\n for (let idx = 0; idx < toolCalls.length; idx++) {\n const tc = toolCalls[idx];\n const callId = tc.id || generateToolCallId();\n const fcId = generateId(\"fc\");\n const fcOutputIndex = nextOutputIndex + 1 + idx;\n const args = tc.arguments;\n\n events.push({\n type: \"response.output_item.added\",\n output_index: fcOutputIndex,\n item: {\n type: \"function_call\",\n id: fcId,\n call_id: callId,\n name: tc.name,\n arguments: \"\",\n status: \"in_progress\",\n },\n });\n\n for (let i = 0; i < args.length; i += chunkSize) {\n events.push({\n type: \"response.function_call_arguments.delta\",\n item_id: fcId,\n output_index: fcOutputIndex,\n delta: args.slice(i, i + chunkSize),\n });\n }\n\n events.push({\n type: \"response.function_call_arguments.done\",\n item_id: fcId,\n output_index: fcOutputIndex,\n arguments: args,\n });\n\n const doneItem = {\n type: \"function_call\",\n id: fcId,\n call_id: callId,\n name: tc.name,\n arguments: args,\n status: \"completed\",\n };\n events.push({ type: \"response.output_item.done\", output_index: fcOutputIndex, item: doneItem });\n fcOutputItems.push(doneItem);\n }\n\n events.push({\n type: \"response.completed\",\n response: {\n id: respId,\n object: \"response\",\n created_at: created,\n model: overrides?.model ?? model,\n status: responsesStatus(overrides?.finishReason, \"completed\"),\n output: [...prefixOutputItems, msgItem, ...fcOutputItems],\n usage: responsesUsage(overrides),\n },\n });\n\n return events;\n}\n\nfunction buildContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): object {\n const output = buildOutputPrefix(content, reasoning, webSearches);\n for (const tc of toolCalls) {\n output.push({\n type: \"function_call\",\n id: generateId(\"fc\"),\n call_id: tc.id || generateToolCallId(),\n name: tc.name,\n arguments: tc.arguments,\n status: \"completed\",\n });\n }\n return buildResponseEnvelope(model, output, overrides);\n}\n\n// ─── SSE writer for Responses API ───────────────────────────────────────────\n\ninterface ResponsesStreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n recordedTimings?: RecordedTimings;\n replaySpeed?: number;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n}\n\nasync function writeResponsesSSEStream(\n res: http.ServerResponse,\n events: ResponsesSSEEvent[],\n optionsOrLatency?: number | ResponsesStreamOptions,\n): Promise<boolean> {\n const opts: ResponsesStreamOptions =\n typeof optionsOrLatency === \"number\" ? { latency: optionsOrLatency } : (optionsOrLatency ?? {});\n const latency = opts.latency ?? 0;\n const profile = opts.streamingProfile;\n const { recordedTimings, replaySpeed } = opts;\n const signal = opts.signal;\n const onChunkSent = opts.onChunkSent;\n\n if (res.writableEnded) return true;\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n let chunkIndex = 0;\n for (const event of events) {\n const chunkDelay = calculateDelay(chunkIndex, profile, latency, recordedTimings, replaySpeed);\n if (chunkDelay > 0) await delay(chunkDelay, signal);\n if (signal?.aborted) return false;\n if (res.writableEnded) return true;\n res.write(`event: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`);\n onChunkSent?.();\n if (signal?.aborted) return false;\n chunkIndex++;\n }\n\n if (!res.writableEnded) {\n res.end();\n }\n return true;\n}\n\n// ─── Request handler ────────────────────────────────────────────────────────\n\nexport async function handleResponses(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n setCorsHeaders(res);\n\n let responsesReq: ResponsesRequest;\n try {\n responsesReq = JSON.parse(raw) as ResponsesRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Malformed JSON: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = responsesToCompletionRequest(responsesReq);\n completionReq._endpointType = \"chat\";\n completionReq._context = getContext(req);\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n defaults.logger.debug(\n `Responses fixture matched for ${req.method ?? \"POST\"} ${req.url ?? \"/v1/responses\"}`,\n );\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n } else {\n defaults.logger.debug(\n `No responses fixture matched for ${req.method ?? \"POST\"} ${req.url ?? \"/v1/responses\"}`,\n );\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n {\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictStatus = 503;\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(\n strictNoMatchLogLine(\n req.method ?? \"POST\",\n req.url ?? \"/v1/responses\",\n skippedBySequenceOrTurn,\n ),\n );\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: strictStatus,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n completionReq,\n \"openai\",\n req.url ?? \"/v1/responses\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, completionReq);\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n const fixtureTimings = fixture.recordedTimings;\n const effectiveReplaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n // Combined content + tool calls response\n if (isContentWithToolCallsResponse(response)) {\n const overrides = extractOverrides(response);\n // Gate reasoning emission on the requested model's capability (aimock#254).\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (responsesReq.stream !== true) {\n const body = buildContentWithToolCallsResponse(\n response.content,\n response.toolCalls,\n completionReq.model,\n effReasoning,\n response.webSearches,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildContentWithToolCallsStreamEvents(\n response.content,\n response.toolCalls,\n completionReq.model,\n chunkSize,\n effReasoning,\n response.webSearches,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeResponsesSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixtureTimings,\n replaySpeed: effectiveReplaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Text response\n if (isTextResponse(response)) {\n const overrides = extractOverrides(response);\n // Gate reasoning emission on the requested model's capability (aimock#254).\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (responsesReq.stream !== true) {\n const body = buildTextResponse(\n response.content,\n completionReq.model,\n effReasoning,\n response.webSearches,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildTextStreamEvents(\n response.content,\n completionReq.model,\n chunkSize,\n effReasoning,\n response.webSearches,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeResponsesSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixtureTimings,\n replaySpeed: effectiveReplaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Tool call response\n if (isToolCallResponse(response)) {\n const overrides = extractOverrides(response);\n // Gate reasoning emission on the requested model's capability (aimock#254).\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (responsesReq.stream !== true) {\n const body = buildToolCallResponse(\n response.toolCalls,\n completionReq.model,\n effReasoning,\n response.webSearches,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildToolCallStreamEvents(\n response.toolCalls,\n completionReq.model,\n chunkSize,\n effReasoning,\n response.webSearches,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeResponsesSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixtureTimings,\n replaySpeed: effectiveReplaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Unknown response type\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response did not match any known type\", type: \"server_error\" },\n }),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"responses.js","names":[],"sources":["../src/responses.ts"],"sourcesContent":["/**\n * OpenAI Responses API support for aimock.\n *\n * Translates incoming /v1/responses requests into the ChatCompletionRequest\n * format used by the fixture router, and converts fixture responses back into\n * the Responses API streaming (or non-streaming) format expected by @ai-sdk/openai.\n */\n\nimport type * as http from \"node:http\";\nimport type {\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n HandlerDefaults,\n ResponseOverrides,\n StreamingProfile,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n generateId,\n generateToolCallId,\n extractOverrides,\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n serializeErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n resolveReasoningForModel,\n strictOverrideField,\n getContext,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic, recordMatchOptions } from \"./router.js\";\nimport { writeErrorResponse, delay, calculateDelay } from \"./sse-writer.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\nimport type { RecordedTimings } from \"./types.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n// ─── Responses API request types ────────────────────────────────────────────\n\ninterface ResponsesInputItem {\n role?: string;\n type?: string;\n content?: string | ResponsesContentPart[];\n call_id?: string;\n name?: string;\n arguments?: string;\n output?: string;\n id?: string;\n}\n\ninterface ResponsesContentPart {\n type: string;\n text?: string;\n}\n\ninterface ResponsesRequest {\n model: string;\n input: string | ResponsesInputItem[];\n instructions?: string;\n tools?: ResponsesToolDef[];\n tool_choice?: string | object;\n stream?: boolean;\n temperature?: number;\n max_output_tokens?: number;\n response_format?: { type: string; [key: string]: unknown };\n [key: string]: unknown;\n}\n\ninterface ResponsesToolDef {\n type: \"function\";\n name: string;\n description?: string;\n parameters?: object;\n strict?: boolean;\n}\n\n// ─── Input conversion: Responses → ChatCompletions messages ─────────────────\n\nfunction extractTextContent(content: string | ResponsesContentPart[] | undefined): string {\n if (!content) return \"\";\n if (typeof content === \"string\") return content;\n return content\n .filter((p) => p.type === \"input_text\" || p.type === \"output_text\")\n .map((p) => p.text ?? \"\")\n .join(\"\");\n}\n\nexport function responsesInputToMessages(req: ResponsesRequest): ChatMessage[] {\n const messages: ChatMessage[] = [];\n // Track item_reference placeholders so we can upgrade or clean them up\n const itemReferencePlaceholders = new WeakSet<ChatMessage>();\n\n // instructions field → system message\n if (req.instructions) {\n messages.push({ role: \"system\", content: req.instructions });\n }\n\n // The OpenAI Responses API accepts either a plain string or an array of input items.\n // When a string is passed, treat it as a single user message.\n if (typeof req.input === \"string\") {\n messages.push({ role: \"user\", content: req.input });\n return messages;\n }\n\n for (const item of req.input) {\n if (item.role === \"system\" || item.role === \"developer\") {\n messages.push({ role: \"system\", content: extractTextContent(item.content) });\n } else if (item.role === \"user\") {\n messages.push({ role: \"user\", content: extractTextContent(item.content) });\n } else if (item.role === \"assistant\") {\n messages.push({ role: \"assistant\", content: extractTextContent(item.content) });\n } else if (item.type === \"function_call\") {\n // Previous assistant tool call — emit as assistant message with tool_calls\n messages.push({\n role: \"assistant\",\n content: null,\n tool_calls: [\n {\n id: item.call_id ?? generateToolCallId(),\n type: \"function\",\n function: { name: item.name ?? \"\", arguments: item.arguments ?? \"\" },\n },\n ],\n });\n } else if (item.type === \"function_call_output\") {\n // Bug 1 fix: If there's no preceding assistant message with a matching\n // tool_call for this call_id, synthesize one. This happens when the AI SDK\n // sends [user, item_reference, function_call_output] — the item_reference\n // placeholder (see below) has no tool_calls, so we need a real assistant\n // message with the tool_call for turnIndex counting.\n const hasMatchingToolCall = messages.some(\n (m) => m.role === \"assistant\" && m.tool_calls?.some((tc) => tc.id === item.call_id),\n );\n if (!hasMatchingToolCall) {\n // Check if the last message is an item_reference placeholder — if so,\n // upgrade it to carry the tool_call instead of synthesizing a duplicate.\n const lastMsg = messages[messages.length - 1];\n if (\n lastMsg &&\n lastMsg.role === \"assistant\" &&\n itemReferencePlaceholders.has(lastMsg) &&\n !lastMsg.tool_calls\n ) {\n lastMsg.content = null;\n lastMsg.tool_calls = [\n {\n id: item.call_id ?? generateToolCallId(),\n type: \"function\",\n function: { name: \"\", arguments: \"\" },\n },\n ];\n itemReferencePlaceholders.delete(lastMsg);\n } else {\n // Multi-fco case: look for a recent assistant with tool_calls that\n // belongs to the same turn. After the first fco upgrades a placeholder,\n // subsequent fco's see [assistant(call_A), tool(call_A)] — the last\n // assistant with tool_calls (right before the trailing tool messages)\n // is the correct target.\n let appended = false;\n for (let k = messages.length - 1; k >= 0; k--) {\n const m = messages[k];\n if (m.role === \"assistant\" && m.tool_calls) {\n m.tool_calls.push({\n id: item.call_id ?? generateToolCallId(),\n type: \"function\",\n function: { name: \"\", arguments: \"\" },\n });\n appended = true;\n break;\n }\n // Stop scanning if we hit a user message — different turn\n if (m.role === \"user\") break;\n }\n if (!appended) {\n messages.push({\n role: \"assistant\",\n content: null,\n tool_calls: [\n {\n id: item.call_id ?? generateToolCallId(),\n type: \"function\",\n function: { name: \"\", arguments: \"\" },\n },\n ],\n });\n }\n }\n }\n messages.push({\n role: \"tool\",\n content: item.output ?? \"\",\n tool_call_id: item.call_id,\n });\n } else if (item.type === \"item_reference\") {\n // Bug 6 fix: item_reference items represent prior assistant turns (text\n // or function_call). Push a placeholder so they count in assistantCount.\n // If a subsequent function_call_output arrives, the handler above will\n // upgrade this placeholder to carry tool_calls (avoiding double-count).\n const placeholder: ChatMessage = { role: \"assistant\", content: \"\" };\n itemReferencePlaceholders.add(placeholder);\n messages.push(placeholder);\n } else {\n // Skip local_shell_call, mcp_list_tools, etc. — not needed for fixture\n // matching.\n }\n }\n\n return messages;\n}\n\nfunction responsesToolsToCompletionsTools(\n tools?: ResponsesToolDef[],\n): ToolDefinition[] | undefined {\n if (!tools || tools.length === 0) return undefined;\n return tools\n .filter((t) => t.type === \"function\")\n .map((t) => ({\n type: \"function\" as const,\n function: { name: t.name, description: t.description, parameters: t.parameters },\n }));\n}\n\nexport function responsesToCompletionRequest(req: ResponsesRequest): ChatCompletionRequest {\n return {\n model: req.model,\n messages: responsesInputToMessages(req),\n stream: req.stream,\n temperature: req.temperature,\n max_tokens: req.max_output_tokens,\n tools: responsesToolsToCompletionsTools(req.tools),\n tool_choice: req.tool_choice,\n response_format: req.response_format,\n };\n}\n\n// ─── Response building: fixture → Responses API format ──────────────────────\n\nfunction responsesStatus(finishReason: string | undefined, defaultStatus: string): string {\n if (!finishReason) return defaultStatus;\n if (finishReason === \"stop\") return \"completed\";\n if (finishReason === \"tool_calls\") return \"completed\";\n if (finishReason === \"length\") return \"incomplete\";\n if (finishReason === \"content_filter\") return \"failed\";\n return finishReason;\n}\n\nfunction responsesUsage(overrides?: ResponseOverrides): {\n input_tokens: number;\n output_tokens: number;\n total_tokens: number;\n} {\n if (!overrides?.usage) return { input_tokens: 0, output_tokens: 0, total_tokens: 0 };\n const input = overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? 0;\n const output = overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? 0;\n return {\n input_tokens: input,\n output_tokens: output,\n total_tokens: overrides.usage.total_tokens ?? input + output,\n };\n}\n\nfunction responseId(): string {\n return generateId(\"resp\");\n}\n\nfunction itemId(): string {\n return generateId(\"msg\");\n}\n\n// Streaming events for Responses API\n\nexport interface ResponsesSSEEvent {\n type: string;\n [key: string]: unknown;\n}\n\nexport function buildTextStreamEvents(\n content: string,\n model: string,\n chunkSize: number,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): ResponsesSSEEvent[] {\n const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(\n model,\n chunkSize,\n reasoning,\n webSearches,\n overrides,\n );\n\n const { events: msgEvents, msgItem } = buildMessageOutputEvents(\n content,\n chunkSize,\n nextOutputIndex,\n );\n events.push(...msgEvents);\n\n events.push({\n type: \"response.completed\",\n response: {\n id: respId,\n object: \"response\",\n created_at: created,\n model: overrides?.model ?? model,\n status: responsesStatus(overrides?.finishReason, \"completed\"),\n output: [...prefixOutputItems, msgItem],\n usage: responsesUsage(overrides),\n },\n });\n\n return events;\n}\n\nexport function buildToolCallStreamEvents(\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): ResponsesSSEEvent[] {\n const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(\n model,\n chunkSize,\n reasoning,\n webSearches,\n overrides,\n );\n\n const fcOutputItems: object[] = [];\n\n for (let idx = 0; idx < toolCalls.length; idx++) {\n const tc = toolCalls[idx];\n const callId = tc.id || generateToolCallId();\n const fcId = generateId(\"fc\");\n const outputIndex = nextOutputIndex + idx;\n\n // output_item.added (function_call)\n events.push({\n type: \"response.output_item.added\",\n output_index: outputIndex,\n item: {\n type: \"function_call\",\n id: fcId,\n call_id: callId,\n name: tc.name,\n arguments: \"\",\n status: \"in_progress\",\n },\n });\n\n // function_call_arguments.delta\n const args = tc.arguments;\n for (let i = 0; i < args.length; i += chunkSize) {\n const slice = args.slice(i, i + chunkSize);\n events.push({\n type: \"response.function_call_arguments.delta\",\n item_id: fcId,\n output_index: outputIndex,\n delta: slice,\n });\n }\n\n // function_call_arguments.done\n events.push({\n type: \"response.function_call_arguments.done\",\n item_id: fcId,\n output_index: outputIndex,\n arguments: args,\n });\n\n const doneItem = {\n type: \"function_call\",\n id: fcId,\n call_id: callId,\n name: tc.name,\n arguments: args,\n status: \"completed\",\n };\n\n // output_item.done\n events.push({\n type: \"response.output_item.done\",\n output_index: outputIndex,\n item: doneItem,\n });\n\n fcOutputItems.push(doneItem);\n }\n\n // response.completed\n events.push({\n type: \"response.completed\",\n response: {\n id: respId,\n object: \"response\",\n created_at: created,\n model: overrides?.model ?? model,\n status: responsesStatus(overrides?.finishReason, \"completed\"),\n output: [...prefixOutputItems, ...fcOutputItems],\n usage: responsesUsage(overrides),\n },\n });\n\n return events;\n}\n\nfunction buildReasoningStreamEvents(\n reasoning: string,\n model: string,\n chunkSize: number,\n): ResponsesSSEEvent[] {\n const reasoningId = generateId(\"rs\");\n const events: ResponsesSSEEvent[] = [];\n\n events.push({\n type: \"response.output_item.added\",\n output_index: 0,\n item: {\n type: \"reasoning\",\n id: reasoningId,\n summary: [],\n },\n });\n\n events.push({\n type: \"response.reasoning_summary_part.added\",\n item_id: reasoningId,\n output_index: 0,\n summary_index: 0,\n part: { type: \"summary_text\", text: \"\" },\n });\n\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"response.reasoning_summary_text.delta\",\n item_id: reasoningId,\n output_index: 0,\n summary_index: 0,\n delta: slice,\n });\n }\n\n events.push({\n type: \"response.reasoning_summary_text.done\",\n item_id: reasoningId,\n output_index: 0,\n summary_index: 0,\n text: reasoning,\n });\n\n events.push({\n type: \"response.reasoning_summary_part.done\",\n item_id: reasoningId,\n output_index: 0,\n summary_index: 0,\n part: { type: \"summary_text\", text: reasoning },\n });\n\n events.push({\n type: \"response.output_item.done\",\n output_index: 0,\n item: {\n type: \"reasoning\",\n id: reasoningId,\n summary: [{ type: \"summary_text\", text: reasoning }],\n },\n });\n\n return events;\n}\n\nfunction buildWebSearchStreamEvents(\n queries: string[],\n startOutputIndex: number,\n): ResponsesSSEEvent[] {\n const events: ResponsesSSEEvent[] = [];\n\n for (let i = 0; i < queries.length; i++) {\n const searchId = generateId(\"ws\");\n const outputIndex = startOutputIndex + i;\n\n events.push({\n type: \"response.output_item.added\",\n output_index: outputIndex,\n item: {\n type: \"web_search_call\",\n id: searchId,\n status: \"in_progress\",\n action: { type: \"search\", query: queries[i] },\n },\n });\n\n events.push({\n type: \"response.output_item.done\",\n output_index: outputIndex,\n item: {\n type: \"web_search_call\",\n id: searchId,\n status: \"completed\",\n action: { type: \"search\", query: queries[i] },\n },\n });\n }\n\n return events;\n}\n\n// ─── Shared streaming helpers ────────────────────────────────────────────────\n\ninterface PreambleResult {\n respId: string;\n created: number;\n events: ResponsesSSEEvent[];\n prefixOutputItems: object[];\n nextOutputIndex: number;\n}\n\nfunction buildResponsePreamble(\n model: string,\n chunkSize: number,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): PreambleResult {\n const respId = overrides?.id ?? responseId();\n const created = overrides?.created ?? Math.floor(Date.now() / 1000);\n const effectiveModel = overrides?.model ?? model;\n const events: ResponsesSSEEvent[] = [];\n const prefixOutputItems: object[] = [];\n let nextOutputIndex = 0;\n\n events.push({\n type: \"response.created\",\n response: {\n id: respId,\n object: \"response\",\n created_at: created,\n model: effectiveModel,\n status: \"in_progress\",\n output: [],\n },\n });\n events.push({\n type: \"response.in_progress\",\n response: {\n id: respId,\n object: \"response\",\n created_at: created,\n model: effectiveModel,\n status: \"in_progress\",\n output: [],\n },\n });\n\n if (reasoning) {\n const reasoningEvents = buildReasoningStreamEvents(reasoning, model, chunkSize);\n events.push(...reasoningEvents);\n const doneEvent = reasoningEvents.find(\n (e) =>\n e.type === \"response.output_item.done\" &&\n (e.item as { type: string })?.type === \"reasoning\",\n );\n if (doneEvent) prefixOutputItems.push(doneEvent.item as object);\n nextOutputIndex++;\n }\n\n if (webSearches && webSearches.length > 0) {\n const searchEvents = buildWebSearchStreamEvents(webSearches, nextOutputIndex);\n events.push(...searchEvents);\n const doneEvents = searchEvents.filter(\n (e) =>\n e.type === \"response.output_item.done\" &&\n (e.item as { type: string })?.type === \"web_search_call\",\n );\n for (const de of doneEvents) prefixOutputItems.push(de.item as object);\n nextOutputIndex += webSearches.length;\n }\n\n return { respId, created, events, prefixOutputItems, nextOutputIndex };\n}\n\ninterface MessageBlockResult {\n events: ResponsesSSEEvent[];\n msgItem: object;\n}\n\nfunction buildMessageOutputEvents(\n content: string,\n chunkSize: number,\n outputIndex: number,\n): MessageBlockResult {\n const msgId = itemId();\n const events: ResponsesSSEEvent[] = [];\n\n events.push({\n type: \"response.output_item.added\",\n output_index: outputIndex,\n item: { type: \"message\", id: msgId, status: \"in_progress\", role: \"assistant\", content: [] },\n });\n events.push({\n type: \"response.content_part.added\",\n item_id: msgId,\n output_index: outputIndex,\n content_index: 0,\n part: { type: \"output_text\", text: \"\", annotations: [] },\n });\n\n for (let i = 0; i < content.length; i += chunkSize) {\n events.push({\n type: \"response.output_text.delta\",\n item_id: msgId,\n output_index: outputIndex,\n content_index: 0,\n delta: content.slice(i, i + chunkSize),\n });\n }\n\n events.push({\n type: \"response.output_text.done\",\n item_id: msgId,\n output_index: outputIndex,\n content_index: 0,\n text: content,\n });\n events.push({\n type: \"response.content_part.done\",\n item_id: msgId,\n output_index: outputIndex,\n content_index: 0,\n part: { type: \"output_text\", text: content, annotations: [] },\n });\n\n const msgItem = {\n type: \"message\",\n id: msgId,\n status: \"completed\",\n role: \"assistant\",\n content: [{ type: \"output_text\", text: content, annotations: [] }],\n };\n\n events.push({ type: \"response.output_item.done\", output_index: outputIndex, item: msgItem });\n\n return { events, msgItem };\n}\n\n// ─── Non-streaming response builders ────────────────────────────────────────\n\nfunction buildOutputPrefix(content: string, reasoning?: string, webSearches?: string[]): object[] {\n const output: object[] = [];\n\n if (reasoning) {\n output.push({\n type: \"reasoning\",\n id: generateId(\"rs\"),\n summary: [{ type: \"summary_text\", text: reasoning }],\n });\n }\n\n if (webSearches && webSearches.length > 0) {\n for (const query of webSearches) {\n output.push({\n type: \"web_search_call\",\n id: generateId(\"ws\"),\n status: \"completed\",\n action: { type: \"search\", query },\n });\n }\n }\n\n output.push({\n type: \"message\",\n id: itemId(),\n status: \"completed\",\n role: \"assistant\",\n content: [{ type: \"output_text\", text: content, annotations: [] }],\n });\n\n return output;\n}\n\nfunction buildResponseEnvelope(\n model: string,\n output: object[],\n overrides?: ResponseOverrides,\n): object {\n return {\n id: overrides?.id ?? responseId(),\n object: \"response\",\n created_at: overrides?.created ?? Math.floor(Date.now() / 1000),\n model: overrides?.model ?? model,\n status: responsesStatus(overrides?.finishReason, \"completed\"),\n output,\n usage: responsesUsage(overrides),\n };\n}\n\nfunction buildTextResponse(\n content: string,\n model: string,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): object {\n return buildResponseEnvelope(\n model,\n buildOutputPrefix(content, reasoning, webSearches),\n overrides,\n );\n}\n\nfunction buildToolCallResponse(\n toolCalls: ToolCall[],\n model: string,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): object {\n const output: object[] = [];\n if (reasoning) {\n output.push({\n type: \"reasoning\",\n id: generateId(\"rs\"),\n summary: [{ type: \"summary_text\", text: reasoning }],\n });\n }\n if (webSearches && webSearches.length > 0) {\n for (const query of webSearches) {\n output.push({\n type: \"web_search_call\",\n id: generateId(\"ws\"),\n status: \"completed\",\n action: { type: \"search\", query },\n });\n }\n }\n for (const tc of toolCalls) {\n output.push({\n type: \"function_call\",\n id: generateId(\"fc\"),\n call_id: tc.id || generateToolCallId(),\n name: tc.name,\n arguments: tc.arguments,\n status: \"completed\",\n });\n }\n return buildResponseEnvelope(model, output, overrides);\n}\n\nexport function buildContentWithToolCallsStreamEvents(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): ResponsesSSEEvent[] {\n const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(\n model,\n chunkSize,\n reasoning,\n webSearches,\n overrides,\n );\n\n const { events: msgEvents, msgItem } = buildMessageOutputEvents(\n content,\n chunkSize,\n nextOutputIndex,\n );\n events.push(...msgEvents);\n\n const fcOutputItems: object[] = [];\n for (let idx = 0; idx < toolCalls.length; idx++) {\n const tc = toolCalls[idx];\n const callId = tc.id || generateToolCallId();\n const fcId = generateId(\"fc\");\n const fcOutputIndex = nextOutputIndex + 1 + idx;\n const args = tc.arguments;\n\n events.push({\n type: \"response.output_item.added\",\n output_index: fcOutputIndex,\n item: {\n type: \"function_call\",\n id: fcId,\n call_id: callId,\n name: tc.name,\n arguments: \"\",\n status: \"in_progress\",\n },\n });\n\n for (let i = 0; i < args.length; i += chunkSize) {\n events.push({\n type: \"response.function_call_arguments.delta\",\n item_id: fcId,\n output_index: fcOutputIndex,\n delta: args.slice(i, i + chunkSize),\n });\n }\n\n events.push({\n type: \"response.function_call_arguments.done\",\n item_id: fcId,\n output_index: fcOutputIndex,\n arguments: args,\n });\n\n const doneItem = {\n type: \"function_call\",\n id: fcId,\n call_id: callId,\n name: tc.name,\n arguments: args,\n status: \"completed\",\n };\n events.push({ type: \"response.output_item.done\", output_index: fcOutputIndex, item: doneItem });\n fcOutputItems.push(doneItem);\n }\n\n events.push({\n type: \"response.completed\",\n response: {\n id: respId,\n object: \"response\",\n created_at: created,\n model: overrides?.model ?? model,\n status: responsesStatus(overrides?.finishReason, \"completed\"),\n output: [...prefixOutputItems, msgItem, ...fcOutputItems],\n usage: responsesUsage(overrides),\n },\n });\n\n return events;\n}\n\nfunction buildContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n reasoning?: string,\n webSearches?: string[],\n overrides?: ResponseOverrides,\n): object {\n const output = buildOutputPrefix(content, reasoning, webSearches);\n for (const tc of toolCalls) {\n output.push({\n type: \"function_call\",\n id: generateId(\"fc\"),\n call_id: tc.id || generateToolCallId(),\n name: tc.name,\n arguments: tc.arguments,\n status: \"completed\",\n });\n }\n return buildResponseEnvelope(model, output, overrides);\n}\n\n// ─── SSE writer for Responses API ───────────────────────────────────────────\n\ninterface ResponsesStreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n recordedTimings?: RecordedTimings;\n replaySpeed?: number;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n}\n\nasync function writeResponsesSSEStream(\n res: http.ServerResponse,\n events: ResponsesSSEEvent[],\n optionsOrLatency?: number | ResponsesStreamOptions,\n): Promise<boolean> {\n const opts: ResponsesStreamOptions =\n typeof optionsOrLatency === \"number\" ? { latency: optionsOrLatency } : (optionsOrLatency ?? {});\n const latency = opts.latency ?? 0;\n const profile = opts.streamingProfile;\n const { recordedTimings, replaySpeed } = opts;\n const signal = opts.signal;\n const onChunkSent = opts.onChunkSent;\n\n if (res.writableEnded) return true;\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n let chunkIndex = 0;\n for (const event of events) {\n const chunkDelay = calculateDelay(chunkIndex, profile, latency, recordedTimings, replaySpeed);\n if (chunkDelay > 0) await delay(chunkDelay, signal);\n if (signal?.aborted) return false;\n if (res.writableEnded) return true;\n res.write(`event: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`);\n onChunkSent?.();\n if (signal?.aborted) return false;\n chunkIndex++;\n }\n\n if (!res.writableEnded) {\n res.end();\n }\n return true;\n}\n\n// ─── Request handler ────────────────────────────────────────────────────────\n\nexport async function handleResponses(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n setCorsHeaders(res);\n\n let responsesReq: ResponsesRequest;\n try {\n responsesReq = JSON.parse(raw) as ResponsesRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Malformed JSON: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = responsesToCompletionRequest(responsesReq);\n completionReq._endpointType = \"chat\";\n completionReq._context = getContext(req);\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n // Record mode proxies on a miss to capture a fresh turn (see record gate\n // below), so keep turnIndex strict to prevent an earlier-turn fixture from\n // shadowing a longer request and skipping the new turn's recording.\n recordMatchOptions(!!defaults.record, defaults.logger),\n );\n\n if (fixture) {\n defaults.logger.debug(\n `Responses fixture matched for ${req.method ?? \"POST\"} ${req.url ?? \"/v1/responses\"}`,\n );\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n } else {\n defaults.logger.debug(\n `No responses fixture matched for ${req.method ?? \"POST\"} ${req.url ?? \"/v1/responses\"}`,\n );\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n {\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictStatus = 503;\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(\n strictNoMatchLogLine(\n req.method ?? \"POST\",\n req.url ?? \"/v1/responses\",\n skippedBySequenceOrTurn,\n ),\n );\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: strictStatus,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n completionReq,\n \"openai\",\n req.url ?? \"/v1/responses\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, completionReq);\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n const fixtureTimings = fixture.recordedTimings;\n const effectiveReplaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n // Combined content + tool calls response\n if (isContentWithToolCallsResponse(response)) {\n const overrides = extractOverrides(response);\n // Gate reasoning emission on the requested model's capability (aimock#254).\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (responsesReq.stream !== true) {\n const body = buildContentWithToolCallsResponse(\n response.content,\n response.toolCalls,\n completionReq.model,\n effReasoning,\n response.webSearches,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildContentWithToolCallsStreamEvents(\n response.content,\n response.toolCalls,\n completionReq.model,\n chunkSize,\n effReasoning,\n response.webSearches,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeResponsesSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixtureTimings,\n replaySpeed: effectiveReplaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Text response\n if (isTextResponse(response)) {\n const overrides = extractOverrides(response);\n // Gate reasoning emission on the requested model's capability (aimock#254).\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (responsesReq.stream !== true) {\n const body = buildTextResponse(\n response.content,\n completionReq.model,\n effReasoning,\n response.webSearches,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildTextStreamEvents(\n response.content,\n completionReq.model,\n chunkSize,\n effReasoning,\n response.webSearches,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeResponsesSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixtureTimings,\n replaySpeed: effectiveReplaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Tool call response\n if (isToolCallResponse(response)) {\n const overrides = extractOverrides(response);\n // Gate reasoning emission on the requested model's capability (aimock#254).\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (responsesReq.stream !== true) {\n const body = buildToolCallResponse(\n response.toolCalls,\n completionReq.model,\n effReasoning,\n response.webSearches,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildToolCallStreamEvents(\n response.toolCalls,\n completionReq.model,\n chunkSize,\n effReasoning,\n response.webSearches,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeResponsesSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixtureTimings,\n replaySpeed: effectiveReplaySpeed,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Unknown response type\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/responses\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response did not match any known type\", type: \"server_error\" },\n }),\n );\n}\n"],"mappings":"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"}
package/dist/router.cjs CHANGED
@@ -9,15 +9,23 @@ function getLastMessageByRole(messages, role) {
9
9
  * Concatenate the text content of every `system` role message in order.
10
10
  * Hosts that build a system context from multiple sources (persona, agent
11
11
  * context entries, tool guidance) often emit several system messages in one
12
- * request; this joins them with newlines so a substring matcher sees the
13
- * whole context as one body.
12
+ * request; this joins SEPARATE system messages with newlines so a substring
13
+ * matcher sees the whole context as one body.
14
+ *
15
+ * Empty handling is symmetric with {@link getTextContent}: a system message
16
+ * with no extractable text (`null`) contributes nothing, while a message that
17
+ * extracts to an empty string is a present-but-empty body. We skip only the
18
+ * `null` (no-text) case so a genuinely empty system message does not inject a
19
+ * stray newline; this matches getTextContent treating "no text" and "empty
20
+ * text" consistently.
14
21
  */
15
22
  function getSystemText(messages) {
16
23
  const parts = [];
17
24
  for (const m of messages) {
18
25
  if (m.role !== "system") continue;
19
26
  const text = getTextContent(m.content);
20
- if (text) parts.push(text);
27
+ if (text === null) continue;
28
+ parts.push(text);
21
29
  }
22
30
  return parts.join("\n");
23
31
  }
@@ -25,16 +33,76 @@ function getSystemText(messages) {
25
33
  * Extract the text content from a message's content field.
26
34
  * Handles both plain string content and array-of-parts content
27
35
  * (e.g. `[{type: "text", text: "..."}]` as sent by some SDKs).
36
+ *
37
+ * Multi-part text is joined with `""` (the parts form one logical body split
38
+ * across segments). Empty handling is symmetric with the string path: a string
39
+ * `""` returns `""`, and an array containing at least one text part whose
40
+ * combined text is empty likewise returns `""` (NOT `null`). `null` is reserved
41
+ * for "no text content at all" — null content, or an array with no text parts —
42
+ * so callers can distinguish "absent" from "present but empty" the same way for
43
+ * both content shapes.
28
44
  */
29
45
  function getTextContent(content) {
30
46
  if (typeof content === "string") return content;
31
47
  if (Array.isArray(content)) {
32
- const texts = content.filter((p) => p.type === "text" && typeof p.text === "string" && p.text !== "").map((p) => p.text);
48
+ const texts = content.filter((p) => p.type === "text" && typeof p.text === "string").map((p) => p.text);
33
49
  return texts.length > 0 ? texts.join("") : null;
34
50
  }
35
51
  return null;
36
52
  }
37
53
  /**
54
+ * Process-level opt-out: when `AIMOCK_STRICT_TURN_INDEX=1` (or `true`) is set,
55
+ * REPLAY selection restores the legacy hard turnIndex gate — a content-matching
56
+ * fixture whose `turnIndex` is defined and `!== assistantCount` is rejected,
57
+ * reproducing origin/main semantics. Follows the `AIMOCK_ALLOW_PRIVATE_URLS`
58
+ * precedent for parsing/precedence. Read per-call (not cached) so tests can flip
59
+ * it. Does NOT affect the record path, which is already strict regardless.
60
+ */
61
+ function strictTurnIndexEnv() {
62
+ const v = process.env.AIMOCK_STRICT_TURN_INDEX;
63
+ return v === "1" || v === "true";
64
+ }
65
+ /**
66
+ * Process-level set of fixtures for which the relaxed-turnIndex divergence
67
+ * warning has already fired, so each divergent fixture warns at most ONCE per
68
+ * process (throttle). Keyed by the selected fixture's OBJECT IDENTITY: the
69
+ * `Fixture` references in the server's fixtures array are stable across replays
70
+ * (the array is held by reference and only fully replaced on a fixtures reset),
71
+ * so identity uniquely distinguishes divergent fixtures and warns each exactly
72
+ * once. A `WeakSet` was chosen over the previous `JSON.stringify(match)` key for
73
+ * two reasons: (1) stringifying the match DROPS `predicate` functions and
74
+ * serialises any RegExp matcher to `{}`, so two distinct fixtures differing only
75
+ * by a predicate/regex collided to one key and the second's warning was silently
76
+ * suppressed; and (2) a string `Set` only grows, accumulating an entry per
77
+ * divergent shape on a long-lived server, whereas a `WeakSet` auto-evicts when a
78
+ * fixture object is released (e.g. after a fixtures reset drops the references).
79
+ * `let` because `WeakSet` has no `.clear()`, so the test hook reassigns a fresh
80
+ * one.
81
+ */
82
+ let warnedRelaxedFixtures = /* @__PURE__ */ new WeakSet();
83
+ /**
84
+ * Build the {@link MatchOptions} a request handler must pass to
85
+ * {@link matchFixtureDiagnostic} / {@link matchFixture}, derived from whether
86
+ * the handler is about to record on a miss.
87
+ *
88
+ * EVERY record-capable handler (OpenAI chat, Anthropic messages, Responses,
89
+ * Gemini, Bedrock, Bedrock-Converse, Cohere, Ollama, …) must build its match
90
+ * options through THIS helper rather than hand-rolling `{ strictTurnIndex }` at
91
+ * the call site. Recording proxies upstream on a miss to capture a fresh turn;
92
+ * if `strictTurnIndex` is left false during recording, an earlier-turn fixture
93
+ * can content-shadow a longer request, the `if (!fixture)` record branch never
94
+ * fires, and the new turn is SILENTLY never recorded. Funnelling the decision
95
+ * through one helper makes that wiring impossible for a future handler to miss:
96
+ * pass `recording = true` whenever the handler's own record gate is satisfied
97
+ * (i.e. it will call `proxyAndRecord` on a miss), `false` otherwise.
98
+ */
99
+ function recordMatchOptions(recording, logger) {
100
+ return {
101
+ strictTurnIndex: recording,
102
+ logger
103
+ };
104
+ }
105
+ /**
38
106
  * Match a fixture against a request, additionally reporting WHY a `null` result
39
107
  * occurred. Shares the exact predicate loop with {@link matchFixture}; a fixture
40
108
  * that passes every shape predicate but fails ONLY the sequenceIndex or
@@ -42,10 +110,12 @@ function getTextContent(content) {
42
110
  * thin wrapper that returns the `.fixture` field, so existing callers are
43
111
  * unaffected.
44
112
  */
45
- function matchFixtureDiagnostic(fixtures, req, matchCounts, requestTransform) {
113
+ function matchFixtureDiagnostic(fixtures, req, matchCounts, requestTransform, options) {
46
114
  const effective = requestTransform ? requestTransform(req) : req;
47
115
  const useExactMatch = !!requestTransform;
116
+ const strictTurnIndex = (options?.strictTurnIndex ?? false) || strictTurnIndexEnv();
48
117
  let skippedBySequenceOrTurn = 0;
118
+ const contentMatches = [];
49
119
  for (const fixture of fixtures) {
50
120
  const { match } = fixture;
51
121
  if (match.predicate !== void 0) {
@@ -77,23 +147,25 @@ function matchFixtureDiagnostic(fixtures, req, matchCounts, requestTransform) {
77
147
  }
78
148
  }
79
149
  if (match.systemMessage !== void 0) {
80
- const text = getSystemText(effective.messages);
81
- if (!text) continue;
82
150
  const sm = match.systemMessage;
83
- if (Array.isArray(sm)) {
84
- let allPresent = true;
85
- for (const needle of sm) if (!text.includes(needle)) {
86
- allPresent = false;
87
- break;
151
+ if (Array.isArray(sm) && sm.length === 0) {} else {
152
+ const text = getSystemText(effective.messages);
153
+ if (!text) continue;
154
+ if (Array.isArray(sm)) {
155
+ let allPresent = true;
156
+ for (const needle of sm) if (!text.includes(needle)) {
157
+ allPresent = false;
158
+ break;
159
+ }
160
+ if (!allPresent) continue;
161
+ } else if (typeof sm === "string") {
162
+ if (useExactMatch) {
163
+ if (text !== sm) continue;
164
+ } else if (!text.includes(sm)) continue;
165
+ } else {
166
+ sm.lastIndex = 0;
167
+ if (!sm.test(text)) continue;
88
168
  }
89
- if (!allPresent) continue;
90
- } else if (typeof sm === "string") {
91
- if (useExactMatch) {
92
- if (text !== sm) continue;
93
- } else if (!text.includes(sm)) continue;
94
- } else {
95
- sm.lastIndex = 0;
96
- if (!sm.test(text)) continue;
97
169
  }
98
170
  }
99
171
  if (match.toolCallId !== void 0) {
@@ -131,25 +203,155 @@ function matchFixtureDiagnostic(fixtures, req, matchCounts, requestTransform) {
131
203
  if (match.hasToolResult !== void 0) {
132
204
  if (effective.messages.some((m) => m.role === "tool") !== match.hasToolResult) continue;
133
205
  }
134
- let skippedByState = false;
135
206
  if (match.sequenceIndex !== void 0 && matchCounts !== void 0) {
136
- if ((matchCounts.get(fixture) ?? 0) !== match.sequenceIndex) skippedByState = true;
207
+ if ((matchCounts.get(fixture) ?? 0) !== match.sequenceIndex) {
208
+ skippedBySequenceOrTurn++;
209
+ continue;
210
+ }
137
211
  }
138
- if (!skippedByState && match.turnIndex !== void 0) {
139
- if (effective.messages.filter((m) => m.role === "assistant").length !== match.turnIndex) skippedByState = true;
212
+ if (strictTurnIndex && match.turnIndex !== void 0) {
213
+ if (effective.messages.filter((m) => m.role === "assistant").length !== match.turnIndex) {
214
+ skippedBySequenceOrTurn++;
215
+ continue;
216
+ }
217
+ }
218
+ contentMatches.push(fixture);
219
+ }
220
+ if (contentMatches.length === 0) return {
221
+ fixture: null,
222
+ skippedBySequenceOrTurn
223
+ };
224
+ const assistantCount = effective.messages.filter((m) => m.role === "assistant").length;
225
+ const { fixture: selected, byUniquePosition } = selectByTurnIndex(contentMatches, assistantCount);
226
+ const selectedTurn = selected.match.turnIndex;
227
+ const turnIndexRelaxed = selectedTurn !== void 0 && selectedTurn !== assistantCount;
228
+ const matchedBy = byUniquePosition ? "turnIndex" : "content";
229
+ if (turnIndexRelaxed && options?.logger) {
230
+ if (!warnedRelaxedFixtures.has(selected)) {
231
+ warnedRelaxedFixtures.add(selected);
232
+ const idx = fixtures.indexOf(selected);
233
+ const desc = describeMatch(selected.match, idx);
234
+ options.logger.warn(`turnIndex relaxed: served fixture ${desc} at assistantCount=${assistantCount} (scripted turnIndex=${selectedTurn}); set AIMOCK_STRICT_TURN_INDEX=1 to restore strict matching`);
140
235
  }
141
- if (skippedByState) {
142
- skippedBySequenceOrTurn++;
143
- continue;
236
+ }
237
+ return {
238
+ fixture: selected,
239
+ skippedBySequenceOrTurn,
240
+ turnIndexRelaxed,
241
+ matchedBy
242
+ };
243
+ }
244
+ /**
245
+ * Build a stable, human-readable identifier for a fixture's match shape for the
246
+ * relaxed-turnIndex warning. The previous `JSON.stringify(match)` was unfit: it
247
+ * DROPS `predicate` functions (non-serialisable) and serialises any RegExp
248
+ * matcher to `{}`, so a predicate- or regex-gated fixture's warning collapsed to
249
+ * an uninformative "served fixture {}" / `{"userMessage":{}}` blob.
250
+ *
251
+ * Instead we list the PRESENT matcher keys in declaration order, annotating each
252
+ * by VALUE KIND so predicates and regexes survive: `predicate(fn)`,
253
+ * `userMessage(regex)`, `userMessage("hello")`, `turnIndex=0`, etc. The
254
+ * fixture's array `index` (when known, i.e. `>= 0`) is prefixed as the stable
255
+ * positional identifier — the `Fixture` type carries no `id`/`name`, so its
256
+ * registration index is the only stable handle. String/number values are shown
257
+ * inline (truncated) so a content match remains recognisable; the whole string
258
+ * is capped to keep the log line bounded.
259
+ */
260
+ function describeMatch(match, index) {
261
+ const parts = [];
262
+ for (const [key, value] of Object.entries(match)) {
263
+ if (value === void 0) continue;
264
+ if (typeof value === "function") parts.push(`${key}(fn)`);
265
+ else if (value instanceof RegExp) parts.push(`${key}(${value})`);
266
+ else if (typeof value === "string") {
267
+ const v = value.length > 40 ? `${value.slice(0, 40)}…` : value;
268
+ parts.push(`${key}(${JSON.stringify(v)})`);
269
+ } else if (Array.isArray(value)) parts.push(`${key}(${value.length} item${value.length === 1 ? "" : "s"})`);
270
+ else parts.push(`${key}=${String(value)}`);
271
+ }
272
+ const keys = parts.length > 0 ? parts.join(", ") : "no matchers";
273
+ return `${index >= 0 ? `#${index} ` : ""}{ ${keys} }`.slice(0, 160);
274
+ }
275
+ /**
276
+ * Choose one fixture from a set that all CONTENT-matched the same request,
277
+ * using `turnIndex` purely as a position disambiguator (never as a reject
278
+ * gate).
279
+ *
280
+ * The selection rule is applied UNIFORMLY regardless of candidate count (a
281
+ * single candidate is NOT special-cased), so the same request never flips its
282
+ * answer just because an unrelated content-matching fixture was registered.
283
+ * Within every tier ties are broken by REGISTRATION ORDER — the
284
+ * earliest-registered eligible candidate wins — preserving the historical
285
+ * greedy "first matching fixture wins" contract.
286
+ *
287
+ * 1. Prefer the turnIndexed candidate whose `turnIndex` is closest to
288
+ * `assistantCount` WITHOUT exceeding it (the highest `turnIndex <=
289
+ * assistantCount`). A behind-the-count scripted turn (turnIndex <
290
+ * assistantCount) beats a plain fallback — an explicit position is a
291
+ * stronger signal than an unpositioned default. A negative `turnIndex` such
292
+ * as -1 is a valid at/behind position (the seed is `-Infinity`, never a `-1`
293
+ * sentinel that would mis-skip it). Earlier registration breaks ties among
294
+ * equal turnIndexes.
295
+ * 2. EXACT-turn tie-break: when the best at/behind scripted turn sits at the
296
+ * EXACT current position (`turnIndex === assistantCount`) a plain fallback
297
+ * also answers "right now", so the two are equally eligible and REGISTRATION
298
+ * ORDER decides — a later-registered `turnIndex:0` does NOT override an
299
+ * earlier-registered fallback, and vice-versa.
300
+ * 3. Otherwise every turnIndexed candidate is still AHEAD of the conversation.
301
+ * An explicit future turn must NOT answer an earlier point, so a plain
302
+ * fallback (eligible at every position) is the better answer — applied
303
+ * uniformly, INCLUDING when the fallback is the sole partner of a single
304
+ * future-turn fixture (the single/multi asymmetry this fixes).
305
+ * 4. Otherwise (pure script, every candidate turnIndexed and all ahead) the
306
+ * script genuinely has no earlier answer, so serve the lowest `turnIndex`
307
+ * candidate — the false-red-kill for a lone scripted turn whose run has
308
+ * FEWER assistant bubbles than its `turnIndex`; registration order breaks
309
+ * ties.
310
+ *
311
+ * A future-turn fixture therefore NEVER answers an earlier-point request when an
312
+ * eligible alternative (a fallback, or an at/behind scripted turn) exists — the
313
+ * future-turn guard is enforced uniformly for single and multiple candidates.
314
+ *
315
+ * Returns the selected fixture alongside `byUniquePosition`: `true` ONLY when the
316
+ * choice was decided by a UNIQUE positional criterion — the served fixture's
317
+ * `turnIndex` sits EXACTLY at `assistantCount`, no earlier fallback overrode it
318
+ * (tier 2), and no other candidate shared that exact position (so registration
319
+ * order did not break a tie). `matchFixtureDiagnostic` maps this to
320
+ * `matchedBy === "turnIndex"`; every other selection path (tie-break,
321
+ * registration order, behind/ahead scripted turn, fallback) is `"content"`.
322
+ */
323
+ function selectByTurnIndex(candidates, assistantCount) {
324
+ const fallbackIdx = candidates.findIndex((f) => f.match.turnIndex === void 0);
325
+ let bestIdx = -1;
326
+ let bestTurn = -Infinity;
327
+ for (let i = 0; i < candidates.length; i++) {
328
+ const t = candidates[i].match.turnIndex;
329
+ if (t === void 0) continue;
330
+ if (t <= assistantCount && t > bestTurn) {
331
+ bestIdx = i;
332
+ bestTurn = t;
144
333
  }
334
+ }
335
+ if (bestIdx !== -1) {
336
+ if (bestTurn === assistantCount && fallbackIdx !== -1 && fallbackIdx < bestIdx) return {
337
+ fixture: candidates[fallbackIdx],
338
+ byUniquePosition: false
339
+ };
340
+ const atExactPosition = bestTurn === assistantCount && candidates.filter((f) => f.match.turnIndex === assistantCount).length === 1;
145
341
  return {
146
- fixture,
147
- skippedBySequenceOrTurn
342
+ fixture: candidates[bestIdx],
343
+ byUniquePosition: atExactPosition
148
344
  };
149
345
  }
346
+ if (fallbackIdx !== -1) return {
347
+ fixture: candidates[fallbackIdx],
348
+ byUniquePosition: false
349
+ };
350
+ let lowest = candidates[0];
351
+ for (const f of candidates) if (f.match.turnIndex < lowest.match.turnIndex) lowest = f;
150
352
  return {
151
- fixture: null,
152
- skippedBySequenceOrTurn
353
+ fixture: lowest,
354
+ byUniquePosition: false
153
355
  };
154
356
  }
155
357
  /**
@@ -157,8 +359,8 @@ function matchFixtureDiagnostic(fixtures, req, matchCounts, requestTransform) {
157
359
  * wrapper over {@link matchFixtureDiagnostic} that discards the skip diagnostic
158
360
  * — preserves the historical signature for all existing callers.
159
361
  */
160
- function matchFixture(fixtures, req, matchCounts, requestTransform) {
161
- return matchFixtureDiagnostic(fixtures, req, matchCounts, requestTransform).fixture;
362
+ function matchFixture(fixtures, req, matchCounts, requestTransform, options) {
363
+ return matchFixtureDiagnostic(fixtures, req, matchCounts, requestTransform, options).fixture;
162
364
  }
163
365
 
164
366
  //#endregion
@@ -166,4 +368,5 @@ exports.getLastMessageByRole = getLastMessageByRole;
166
368
  exports.getTextContent = getTextContent;
167
369
  exports.matchFixture = matchFixture;
168
370
  exports.matchFixtureDiagnostic = matchFixtureDiagnostic;
371
+ exports.recordMatchOptions = recordMatchOptions;
169
372
  //# sourceMappingURL=router.cjs.map