@copilotkit/aimock 1.19.1 → 1.19.2
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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +10 -0
- package/dist/agui-types.d.cts.map +1 -1
- package/dist/agui-types.d.ts.map +1 -1
- package/dist/bedrock-converse.cjs +31 -31
- package/dist/bedrock-converse.cjs.map +1 -1
- package/dist/bedrock-converse.d.cts.map +1 -1
- package/dist/bedrock-converse.d.ts.map +1 -1
- package/dist/bedrock-converse.js +31 -31
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/helpers.cjs +17 -0
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +17 -0
- package/dist/helpers.js.map +1 -1
- package/dist/ollama.cjs +42 -26
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.d.cts.map +1 -1
- package/dist/ollama.d.ts.map +1 -1
- package/dist/ollama.js +42 -26
- package/dist/ollama.js.map +1 -1
- package/dist/responses.cjs +3 -0
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts.map +1 -1
- package/dist/responses.js +3 -0
- package/dist/responses.js.map +1 -1
- package/dist/types.d.cts +2 -0
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-types.d.cts.map +1 -1
- package/dist/ws-gemini-live.cjs +1 -1
- package/dist/ws-gemini-live.cjs.map +1 -1
- package/dist/ws-gemini-live.js +1 -1
- package/dist/ws-gemini-live.js.map +1 -1
- package/package.json +1 -1
package/dist/ollama.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ollama.js","names":[],"sources":["../src/ollama.ts"],"sourcesContent":["/**\n * Ollama API endpoint support.\n *\n * Translates incoming /api/chat and /api/generate requests into the\n * ChatCompletionRequest format used by the fixture router, and converts\n * fixture responses back into Ollama's NDJSON streaming or non-streaming format.\n *\n * Key differences from OpenAI:\n * - Ollama defaults to stream: true (opposite of OpenAI)\n * - Streaming uses NDJSON, not SSE\n * - Tool call arguments are objects, not JSON strings\n * - Tool calls have no id field\n */\n\nimport type * as http from \"node:http\";\nimport type {\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n HandlerDefaults,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n} from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport { writeNDJSONStream } from \"./ndjson-writer.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { Logger } from \"./logger.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n// ─── Ollama request types ────────────────────────────────────────────────────\n\ninterface OllamaMessage {\n role: \"system\" | \"user\" | \"assistant\" | \"tool\";\n content: string;\n}\n\ninterface OllamaToolDef {\n type: string;\n function: {\n name: string;\n description?: string;\n parameters?: object;\n };\n}\n\ninterface OllamaRequest {\n model: string;\n messages: OllamaMessage[];\n stream?: boolean; // default true!\n options?: { temperature?: number; num_predict?: number };\n tools?: OllamaToolDef[];\n}\n\ninterface OllamaGenerateRequest {\n model: string;\n prompt: string;\n stream?: boolean; // default true!\n options?: { temperature?: number; num_predict?: number };\n}\n\n// ─── Duration fields (zeroed, required on final/non-streaming responses) ────\n\nconst DURATION_FIELDS = {\n done_reason: \"stop\" as const,\n total_duration: 0,\n load_duration: 0,\n prompt_eval_count: 0,\n prompt_eval_duration: 0,\n eval_count: 0,\n eval_duration: 0,\n};\n\n// ─── Input conversion: Ollama → ChatCompletionRequest ────────────────────────\n\nexport function ollamaToCompletionRequest(req: OllamaRequest): ChatCompletionRequest {\n const messages: ChatMessage[] = [];\n\n for (const msg of req.messages) {\n messages.push({\n role: msg.role as ChatMessage[\"role\"],\n content: msg.content,\n });\n }\n\n // Convert tools\n let tools: ToolDefinition[] | undefined;\n if (req.tools && req.tools.length > 0) {\n tools = req.tools.map((t) => ({\n type: \"function\" as const,\n function: {\n name: t.function.name,\n description: t.function.description,\n parameters: t.function.parameters,\n },\n }));\n }\n\n return {\n model: req.model,\n messages,\n stream: req.stream ?? true,\n temperature: req.options?.temperature,\n max_tokens: req.options?.num_predict,\n tools,\n };\n}\n\nfunction ollamaGenerateToCompletionRequest(req: OllamaGenerateRequest): ChatCompletionRequest {\n return {\n model: req.model,\n messages: [{ role: \"user\", content: req.prompt }],\n stream: req.stream ?? true,\n temperature: req.options?.temperature,\n max_tokens: req.options?.num_predict,\n };\n}\n\n// ─── Response builders: /api/chat ────────────────────────────────────────────\n\nfunction buildOllamaChatTextChunks(\n content: string,\n model: string,\n chunkSize: number,\n reasoning?: string,\n): object[] {\n const chunks: object[] = [];\n\n // Reasoning chunks (before content)\n if (reasoning) {\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n chunks.push({\n model,\n message: { role: \"assistant\", content: \"\", reasoning_content: slice },\n done: false,\n });\n }\n }\n\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n chunks.push({\n model,\n message: { role: \"assistant\", content: slice },\n done: false,\n });\n }\n\n // Final chunk with done: true and all duration fields\n chunks.push({\n model,\n message: { role: \"assistant\", content: \"\" },\n done: true,\n ...DURATION_FIELDS,\n });\n\n return chunks;\n}\n\nfunction buildOllamaChatTextResponse(content: string, model: string, reasoning?: string): object {\n return {\n model,\n message: {\n role: \"assistant\",\n content,\n ...(reasoning ? { reasoning_content: reasoning } : {}),\n },\n done: true,\n ...DURATION_FIELDS,\n };\n}\n\nfunction buildOllamaChatToolCallChunks(\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n): object[] {\n const ollamaToolCalls = toolCalls.map((tc) => {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n function: {\n name: tc.name,\n arguments: argsObj,\n },\n };\n });\n\n // Tool calls are sent in a single chunk (no streaming of individual args)\n const chunks: object[] = [];\n chunks.push({\n model,\n message: {\n role: \"assistant\",\n content: \"\",\n tool_calls: ollamaToolCalls,\n },\n done: false,\n });\n\n // Final chunk\n chunks.push({\n model,\n message: { role: \"assistant\", content: \"\" },\n done: true,\n ...DURATION_FIELDS,\n });\n\n return chunks;\n}\n\nfunction buildOllamaChatToolCallResponse(\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n): object {\n const ollamaToolCalls = toolCalls.map((tc) => {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n function: {\n name: tc.name,\n arguments: argsObj,\n },\n };\n });\n\n return {\n model,\n message: {\n role: \"assistant\",\n content: \"\",\n tool_calls: ollamaToolCalls,\n },\n done: true,\n ...DURATION_FIELDS,\n };\n}\n\n// ─── Response builders: /api/chat — content + tool calls ────────────────────\n\nfunction buildOllamaChatContentWithToolCallsChunks(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n logger: Logger,\n): object[] {\n const chunks: object[] = [];\n\n // Content chunks first\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n chunks.push({\n model,\n message: { role: \"assistant\", content: slice },\n done: false,\n });\n }\n\n // Tool calls in a single chunk (same as tool-call-only path)\n const ollamaToolCalls = toolCalls.map((tc) => {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n function: {\n name: tc.name,\n arguments: argsObj,\n },\n };\n });\n\n chunks.push({\n model,\n message: {\n role: \"assistant\",\n content: \"\",\n tool_calls: ollamaToolCalls,\n },\n done: false,\n });\n\n // Final chunk\n chunks.push({\n model,\n message: { role: \"assistant\", content: \"\" },\n done: true,\n ...DURATION_FIELDS,\n });\n\n return chunks;\n}\n\nfunction buildOllamaChatContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n): object {\n const ollamaToolCalls = toolCalls.map((tc) => {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n function: {\n name: tc.name,\n arguments: argsObj,\n },\n };\n });\n\n return {\n model,\n message: {\n role: \"assistant\",\n content,\n tool_calls: ollamaToolCalls,\n },\n done: true,\n ...DURATION_FIELDS,\n };\n}\n\n// ─── Response builders: /api/generate ────────────────────────────────────────\n\nfunction buildOllamaGenerateTextChunks(\n content: string,\n model: string,\n chunkSize: number,\n reasoning?: string,\n): object[] {\n const chunks: object[] = [];\n const createdAt = new Date().toISOString();\n\n // Reasoning chunks (before content)\n if (reasoning) {\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n chunks.push({\n model,\n created_at: createdAt,\n response: \"\",\n reasoning_content: slice,\n done: false,\n });\n }\n }\n\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n chunks.push({\n model,\n created_at: createdAt,\n response: slice,\n done: false,\n });\n }\n\n // Final chunk\n chunks.push({\n model,\n created_at: createdAt,\n response: \"\",\n done: true,\n ...DURATION_FIELDS,\n context: [],\n });\n\n return chunks;\n}\n\nfunction buildOllamaGenerateTextResponse(\n content: string,\n model: string,\n reasoning?: string,\n): object {\n return {\n model,\n created_at: new Date().toISOString(),\n response: content,\n ...(reasoning ? { reasoning_content: reasoning } : {}),\n done: true,\n ...DURATION_FIELDS,\n context: [],\n };\n}\n\n// ─── Request handler: /api/chat ──────────────────────────────────────────────\n\nexport async function handleOllama(\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 const { logger } = defaults;\n setCorsHeaders(res);\n\n const urlPath = req.url ?? \"/api/chat\";\n\n let ollamaReq: OllamaRequest;\n try {\n ollamaReq = JSON.parse(raw) as OllamaRequest;\n } catch {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\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\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n if (!ollamaReq.messages || !Array.isArray(ollamaReq.messages)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\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: \"Invalid request: messages array is required\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = ollamaToCompletionRequest(ollamaReq);\n completionReq._endpointType = \"chat\";\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n logger.debug(`No fixture matched for request`);\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: urlPath,\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n completionReq,\n \"ollama\",\n urlPath,\n fixtures,\n defaults,\n raw,\n );\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n const strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n if (defaults.strict) {\n logger.error(`STRICT: No fixture matched for ${req.method ?? \"POST\"} ${urlPath}`);\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: strictStatus, fixture: null },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\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\n // Ollama defaults to streaming when stream is absent or true\n const streaming = ollamaReq.stream !== false;\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, JSON.stringify(response));\n return;\n }\n\n // Content + tool calls response (must be checked before text/tool-only branches)\n if (isContentWithToolCallsResponse(response)) {\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (!streaming) {\n const body = buildOllamaChatContentWithToolCallsResponse(\n response.content,\n response.toolCalls,\n completionReq.model,\n logger,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildOllamaChatContentWithToolCallsChunks(\n response.content,\n response.toolCalls,\n completionReq.model,\n chunkSize,\n logger,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeNDJSONStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (!streaming) {\n const body = buildOllamaChatTextResponse(\n response.content,\n completionReq.model,\n response.reasoning,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildOllamaChatTextChunks(\n response.content,\n completionReq.model,\n chunkSize,\n response.reasoning,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeNDJSONStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (!streaming) {\n const body = buildOllamaChatToolCallResponse(response.toolCalls, completionReq.model, logger);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildOllamaChatToolCallChunks(response.toolCalls, completionReq.model, logger);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeNDJSONStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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: urlPath,\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: {\n message: \"Fixture response did not match any known type\",\n type: \"server_error\",\n },\n }),\n );\n}\n\n// ─── Request handler: /api/generate ──────────────────────────────────────────\n\nexport async function handleOllamaGenerate(\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 const urlPath = req.url ?? \"/api/generate\";\n\n let generateReq: OllamaGenerateRequest;\n try {\n generateReq = JSON.parse(raw) as OllamaGenerateRequest;\n } catch {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\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\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n if (!generateReq.prompt || typeof generateReq.prompt !== \"string\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\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: \"Invalid request: prompt field is required\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = ollamaGenerateToCompletionRequest(generateReq);\n completionReq._endpointType = \"chat\";\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(`No fixture matched for request`);\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: urlPath,\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n completionReq,\n \"ollama\",\n urlPath,\n fixtures,\n defaults,\n raw,\n );\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n const strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n if (defaults.strict) {\n defaults.logger.error(`STRICT: No fixture matched for ${req.method ?? \"POST\"} ${urlPath}`);\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: strictStatus, fixture: null },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\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\n // Ollama defaults to streaming when stream is absent or true\n const streaming = generateReq.stream !== false;\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, JSON.stringify(response));\n return;\n }\n\n // Text response (only type supported for /api/generate)\n if (isTextResponse(response)) {\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (!streaming) {\n const body = buildOllamaGenerateTextResponse(\n response.content,\n completionReq.model,\n response.reasoning,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildOllamaGenerateTextChunks(\n response.content,\n completionReq.model,\n chunkSize,\n response.reasoning,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeNDJSONStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 fixtures matched but not supported on /api/generate\n if (isToolCallResponse(response) || isContentWithToolCallsResponse(response)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 400, fixture },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: \"Tool call fixtures are not supported on /api/generate — use /api/chat instead\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Unknown response type\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\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: {\n message: \"Fixture response did not match any known type\",\n type: \"server_error\",\n },\n }),\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ollama.js","names":[],"sources":["../src/ollama.ts"],"sourcesContent":["/**\n * Ollama API endpoint support.\n *\n * Translates incoming /api/chat and /api/generate requests into the\n * ChatCompletionRequest format used by the fixture router, and converts\n * fixture responses back into Ollama's NDJSON streaming or non-streaming format.\n *\n * Key differences from OpenAI:\n * - Ollama defaults to stream: true (opposite of OpenAI)\n * - Streaming uses NDJSON, not SSE\n * - Tool call arguments are objects, not JSON strings\n * - Tool calls have no id field\n */\n\nimport type * as http from \"node:http\";\nimport type {\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n HandlerDefaults,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n} from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport { writeNDJSONStream } from \"./ndjson-writer.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { Logger } from \"./logger.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n// ─── Ollama request types ────────────────────────────────────────────────────\n\ninterface OllamaMessage {\n role: \"system\" | \"user\" | \"assistant\" | \"tool\";\n content: string;\n}\n\ninterface OllamaToolDef {\n type: string;\n function: {\n name: string;\n description?: string;\n parameters?: object;\n };\n}\n\ninterface OllamaRequest {\n model: string;\n messages: OllamaMessage[];\n stream?: boolean; // default true!\n options?: { temperature?: number; num_predict?: number };\n tools?: OllamaToolDef[];\n}\n\ninterface OllamaGenerateRequest {\n model: string;\n prompt: string;\n stream?: boolean; // default true!\n options?: { temperature?: number; num_predict?: number };\n}\n\n// ─── Duration fields (zeroed, required on final/non-streaming responses) ────\n\nconst DURATION_FIELDS = {\n done_reason: \"stop\" as const,\n total_duration: 0,\n load_duration: 0,\n prompt_eval_count: 0,\n prompt_eval_duration: 0,\n eval_count: 0,\n eval_duration: 0,\n};\n\n// ─── Input conversion: Ollama → ChatCompletionRequest ────────────────────────\n\nexport function ollamaToCompletionRequest(req: OllamaRequest): ChatCompletionRequest {\n const messages: ChatMessage[] = [];\n\n for (const msg of req.messages) {\n messages.push({\n role: msg.role as ChatMessage[\"role\"],\n content: msg.content,\n });\n }\n\n // Convert tools\n let tools: ToolDefinition[] | undefined;\n if (req.tools && req.tools.length > 0) {\n tools = req.tools.map((t) => ({\n type: \"function\" as const,\n function: {\n name: t.function.name,\n description: t.function.description,\n parameters: t.function.parameters,\n },\n }));\n }\n\n return {\n model: req.model,\n messages,\n stream: req.stream ?? true,\n temperature: req.options?.temperature,\n max_tokens: req.options?.num_predict,\n tools,\n };\n}\n\nfunction ollamaGenerateToCompletionRequest(req: OllamaGenerateRequest): ChatCompletionRequest {\n return {\n model: req.model,\n messages: [{ role: \"user\", content: req.prompt }],\n stream: req.stream ?? true,\n temperature: req.options?.temperature,\n max_tokens: req.options?.num_predict,\n };\n}\n\n// ─── Response builders: /api/chat ────────────────────────────────────────────\n\nfunction buildOllamaChatTextChunks(\n content: string,\n model: string,\n chunkSize: number,\n reasoning?: string,\n): object[] {\n const chunks: object[] = [];\n const createdAt = new Date().toISOString();\n\n // Reasoning chunks (before content)\n if (reasoning) {\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n chunks.push({\n model,\n created_at: createdAt,\n message: { role: \"assistant\", content: \"\", reasoning_content: slice },\n done: false,\n });\n }\n }\n\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n chunks.push({\n model,\n created_at: createdAt,\n message: { role: \"assistant\", content: slice },\n done: false,\n });\n }\n\n // Final chunk with done: true and all duration fields\n chunks.push({\n model,\n created_at: createdAt,\n message: { role: \"assistant\", content: \"\" },\n done: true,\n ...DURATION_FIELDS,\n });\n\n return chunks;\n}\n\nfunction buildOllamaChatTextResponse(content: string, model: string, reasoning?: string): object {\n return {\n model,\n created_at: new Date().toISOString(),\n message: {\n role: \"assistant\",\n content,\n ...(reasoning ? { reasoning_content: reasoning } : {}),\n },\n done: true,\n ...DURATION_FIELDS,\n };\n}\n\nfunction buildOllamaChatToolCallChunks(\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n): object[] {\n const ollamaToolCalls = toolCalls.map((tc) => {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n function: {\n name: tc.name,\n arguments: argsObj,\n },\n };\n });\n\n // Tool calls are sent in a single chunk (no streaming of individual args)\n const chunks: object[] = [];\n const createdAt = new Date().toISOString();\n chunks.push({\n model,\n created_at: createdAt,\n message: {\n role: \"assistant\",\n content: \"\",\n tool_calls: ollamaToolCalls,\n },\n done: false,\n });\n\n // Final chunk\n chunks.push({\n model,\n created_at: createdAt,\n message: { role: \"assistant\", content: \"\" },\n done: true,\n ...DURATION_FIELDS,\n });\n\n return chunks;\n}\n\nfunction buildOllamaChatToolCallResponse(\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n): object {\n const ollamaToolCalls = toolCalls.map((tc) => {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n function: {\n name: tc.name,\n arguments: argsObj,\n },\n };\n });\n\n return {\n model,\n created_at: new Date().toISOString(),\n message: {\n role: \"assistant\",\n content: \"\",\n tool_calls: ollamaToolCalls,\n },\n done: true,\n ...DURATION_FIELDS,\n };\n}\n\n// ─── Response builders: /api/chat — content + tool calls ────────────────────\n\nfunction buildOllamaChatContentWithToolCallsChunks(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n logger: Logger,\n): object[] {\n const chunks: object[] = [];\n const createdAt = new Date().toISOString();\n\n // Content chunks first\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n chunks.push({\n model,\n created_at: createdAt,\n message: { role: \"assistant\", content: slice },\n done: false,\n });\n }\n\n // Tool calls in a single chunk (same as tool-call-only path)\n const ollamaToolCalls = toolCalls.map((tc) => {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n function: {\n name: tc.name,\n arguments: argsObj,\n },\n };\n });\n\n chunks.push({\n model,\n created_at: createdAt,\n message: {\n role: \"assistant\",\n content: \"\",\n tool_calls: ollamaToolCalls,\n },\n done: false,\n });\n\n // Final chunk\n chunks.push({\n model,\n created_at: createdAt,\n message: { role: \"assistant\", content: \"\" },\n done: true,\n ...DURATION_FIELDS,\n });\n\n return chunks;\n}\n\nfunction buildOllamaChatContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n): object {\n const ollamaToolCalls = toolCalls.map((tc) => {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n function: {\n name: tc.name,\n arguments: argsObj,\n },\n };\n });\n\n return {\n model,\n created_at: new Date().toISOString(),\n message: {\n role: \"assistant\",\n content,\n tool_calls: ollamaToolCalls,\n },\n done: true,\n ...DURATION_FIELDS,\n };\n}\n\n// ─── Response builders: /api/generate ────────────────────────────────────────\n\nfunction buildOllamaGenerateTextChunks(\n content: string,\n model: string,\n chunkSize: number,\n reasoning?: string,\n): object[] {\n const chunks: object[] = [];\n const createdAt = new Date().toISOString();\n\n // Reasoning chunks (before content)\n if (reasoning) {\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n chunks.push({\n model,\n created_at: createdAt,\n response: \"\",\n reasoning_content: slice,\n done: false,\n });\n }\n }\n\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n chunks.push({\n model,\n created_at: createdAt,\n response: slice,\n done: false,\n });\n }\n\n // Final chunk\n chunks.push({\n model,\n created_at: createdAt,\n response: \"\",\n done: true,\n ...DURATION_FIELDS,\n context: [],\n });\n\n return chunks;\n}\n\nfunction buildOllamaGenerateTextResponse(\n content: string,\n model: string,\n reasoning?: string,\n): object {\n return {\n model,\n created_at: new Date().toISOString(),\n response: content,\n ...(reasoning ? { reasoning_content: reasoning } : {}),\n done: true,\n ...DURATION_FIELDS,\n context: [],\n };\n}\n\n// ─── Request handler: /api/chat ──────────────────────────────────────────────\n\nexport async function handleOllama(\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 const { logger } = defaults;\n setCorsHeaders(res);\n\n const urlPath = req.url ?? \"/api/chat\";\n\n let ollamaReq: OllamaRequest;\n try {\n ollamaReq = JSON.parse(raw) as OllamaRequest;\n } catch {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\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\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n if (!ollamaReq.messages || !Array.isArray(ollamaReq.messages)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\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: \"Invalid request: messages array is required\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = ollamaToCompletionRequest(ollamaReq);\n completionReq._endpointType = \"chat\";\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n logger.debug(`No fixture matched for request`);\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: urlPath,\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n completionReq,\n \"ollama\",\n urlPath,\n fixtures,\n defaults,\n raw,\n );\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n const strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n if (defaults.strict) {\n logger.error(`STRICT: No fixture matched for ${req.method ?? \"POST\"} ${urlPath}`);\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: strictStatus, fixture: null },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\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\n // Ollama defaults to streaming when stream is absent or true\n const streaming = ollamaReq.stream !== false;\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, JSON.stringify(response));\n return;\n }\n\n // Content + tool calls response (must be checked before text/tool-only branches)\n if (isContentWithToolCallsResponse(response)) {\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (!streaming) {\n const body = buildOllamaChatContentWithToolCallsResponse(\n response.content,\n response.toolCalls,\n completionReq.model,\n logger,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildOllamaChatContentWithToolCallsChunks(\n response.content,\n response.toolCalls,\n completionReq.model,\n chunkSize,\n logger,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeNDJSONStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (!streaming) {\n const body = buildOllamaChatTextResponse(\n response.content,\n completionReq.model,\n response.reasoning,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildOllamaChatTextChunks(\n response.content,\n completionReq.model,\n chunkSize,\n response.reasoning,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeNDJSONStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (!streaming) {\n const body = buildOllamaChatToolCallResponse(response.toolCalls, completionReq.model, logger);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildOllamaChatToolCallChunks(response.toolCalls, completionReq.model, logger);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeNDJSONStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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: urlPath,\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: {\n message: \"Fixture response did not match any known type\",\n type: \"server_error\",\n },\n }),\n );\n}\n\n// ─── Request handler: /api/generate ──────────────────────────────────────────\n\nexport async function handleOllamaGenerate(\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 const urlPath = req.url ?? \"/api/generate\";\n\n let generateReq: OllamaGenerateRequest;\n try {\n generateReq = JSON.parse(raw) as OllamaGenerateRequest;\n } catch {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\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\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n if (!generateReq.prompt || typeof generateReq.prompt !== \"string\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\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: \"Invalid request: prompt field is required\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = ollamaGenerateToCompletionRequest(generateReq);\n completionReq._endpointType = \"chat\";\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(`No fixture matched for request`);\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: urlPath,\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n completionReq,\n \"ollama\",\n urlPath,\n fixtures,\n defaults,\n raw,\n );\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n const strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n if (defaults.strict) {\n defaults.logger.error(`STRICT: No fixture matched for ${req.method ?? \"POST\"} ${urlPath}`);\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: strictStatus, fixture: null },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\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\n // Ollama defaults to streaming when stream is absent or true\n const streaming = generateReq.stream !== false;\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, JSON.stringify(response));\n return;\n }\n\n // Text response (only type supported for /api/generate)\n if (isTextResponse(response)) {\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (!streaming) {\n const body = buildOllamaGenerateTextResponse(\n response.content,\n completionReq.model,\n response.reasoning,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const chunks = buildOllamaGenerateTextChunks(\n response.content,\n completionReq.model,\n chunkSize,\n response.reasoning,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeNDJSONStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\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 fixtures matched but not supported on /api/generate\n if (isToolCallResponse(response) || isContentWithToolCallsResponse(response)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 400, fixture },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: \"Tool call fixtures are not supported on /api/generate — use /api/chat instead\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Unknown response type\n journal.add({\n method: req.method ?? \"POST\",\n path: urlPath,\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: {\n message: \"Fixture response did not match any known type\",\n type: \"server_error\",\n },\n }),\n );\n}\n"],"mappings":"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"}
|
package/dist/responses.cjs
CHANGED
|
@@ -428,6 +428,7 @@ function buildMessageOutputEvents(content, chunkSize, outputIndex) {
|
|
|
428
428
|
});
|
|
429
429
|
events.push({
|
|
430
430
|
type: "response.content_part.added",
|
|
431
|
+
item_id: msgId,
|
|
431
432
|
output_index: outputIndex,
|
|
432
433
|
content_index: 0,
|
|
433
434
|
part: {
|
|
@@ -445,12 +446,14 @@ function buildMessageOutputEvents(content, chunkSize, outputIndex) {
|
|
|
445
446
|
});
|
|
446
447
|
events.push({
|
|
447
448
|
type: "response.output_text.done",
|
|
449
|
+
item_id: msgId,
|
|
448
450
|
output_index: outputIndex,
|
|
449
451
|
content_index: 0,
|
|
450
452
|
text: content
|
|
451
453
|
});
|
|
452
454
|
events.push({
|
|
453
455
|
type: "response.content_part.done",
|
|
456
|
+
item_id: msgId,
|
|
454
457
|
output_index: outputIndex,
|
|
455
458
|
content_index: 0,
|
|
456
459
|
part: {
|
package/dist/responses.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"responses.cjs","names":["generateToolCallId","generateId","calculateDelay","delay","flattenHeaders","getTestId","matchFixture","applyChaos","proxyAndRecord","resolveResponse","isErrorResponse","isContentWithToolCallsResponse","extractOverrides","createInterruptionSignal","isTextResponse","isToolCallResponse"],"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 flattenHeaders,\n getTestId,\n resolveResponse,\n} from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse, delay, calculateDelay } from \"./sse-writer.js\";\nimport { createInterruptionSignal } from \"./interruption.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 [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 tools: responsesToolsToCompletionsTools(req.tools),\n tool_choice: req.tool_choice,\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 return {\n input_tokens: overrides.usage.input_tokens ?? 0,\n output_tokens: overrides.usage.output_tokens ?? 0,\n total_tokens:\n overrides.usage.total_tokens ??\n (overrides.usage.input_tokens ?? 0) + (overrides.usage.output_tokens ?? 0),\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 overrides?: ResponseOverrides,\n): ResponsesSSEEvent[] {\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\n // response.created\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\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 const outputItems: 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\n // output_item.added (function_call)\n events.push({\n type: \"response.output_item.added\",\n output_index: idx,\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: idx,\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: idx,\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: idx,\n item: doneItem,\n });\n\n outputItems.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: effectiveModel,\n status: responsesStatus(overrides?.finishReason, \"completed\"),\n output: outputItems,\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 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 output_index: outputIndex,\n content_index: 0,\n text: content,\n });\n events.push({\n type: \"response.content_part.done\",\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 overrides?: ResponseOverrides,\n): object {\n return buildResponseEnvelope(\n model,\n toolCalls.map((tc) => ({\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 overrides,\n );\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 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 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);\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 {\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: { message: \"Malformed JSON\", type: \"invalid_request_error\", code: \"invalid_json\" },\n }),\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = responsesToCompletionRequest(responsesReq);\n completionReq._endpointType = \"chat\";\n\n const testId = getTestId(req);\n const fixture = matchFixture(\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 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 !== \"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 const strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n if (defaults.strict) {\n defaults.logger.error(\n `STRICT: No fixture matched for ${req.method ?? \"POST\"} ${req.url ?? \"/v1/responses\"}`,\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: { status: strictStatus, fixture: null },\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\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\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, JSON.stringify(response));\n return;\n }\n\n // Combined content + tool calls response\n if (isContentWithToolCallsResponse(response)) {\n const overrides = extractOverrides(response);\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 response.reasoning,\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 response.reasoning,\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 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 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 response.reasoning,\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 response.reasoning,\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 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 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(response.toolCalls, completionReq.model, overrides);\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 overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeResponsesSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\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.cjs","names":["generateToolCallId","generateId","calculateDelay","delay","flattenHeaders","getTestId","matchFixture","applyChaos","proxyAndRecord","resolveResponse","isErrorResponse","isContentWithToolCallsResponse","extractOverrides","createInterruptionSignal","isTextResponse","isToolCallResponse"],"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 flattenHeaders,\n getTestId,\n resolveResponse,\n} from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse, delay, calculateDelay } from \"./sse-writer.js\";\nimport { createInterruptionSignal } from \"./interruption.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 [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 tools: responsesToolsToCompletionsTools(req.tools),\n tool_choice: req.tool_choice,\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 return {\n input_tokens: overrides.usage.input_tokens ?? 0,\n output_tokens: overrides.usage.output_tokens ?? 0,\n total_tokens:\n overrides.usage.total_tokens ??\n (overrides.usage.input_tokens ?? 0) + (overrides.usage.output_tokens ?? 0),\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 overrides?: ResponseOverrides,\n): ResponsesSSEEvent[] {\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\n // response.created\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\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 const outputItems: 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\n // output_item.added (function_call)\n events.push({\n type: \"response.output_item.added\",\n output_index: idx,\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: idx,\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: idx,\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: idx,\n item: doneItem,\n });\n\n outputItems.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: effectiveModel,\n status: responsesStatus(overrides?.finishReason, \"completed\"),\n output: outputItems,\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 overrides?: ResponseOverrides,\n): object {\n return buildResponseEnvelope(\n model,\n toolCalls.map((tc) => ({\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 overrides,\n );\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 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 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);\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 {\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: { message: \"Malformed JSON\", type: \"invalid_request_error\", code: \"invalid_json\" },\n }),\n );\n return;\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = responsesToCompletionRequest(responsesReq);\n completionReq._endpointType = \"chat\";\n\n const testId = getTestId(req);\n const fixture = matchFixture(\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 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 !== \"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 const strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n if (defaults.strict) {\n defaults.logger.error(\n `STRICT: No fixture matched for ${req.method ?? \"POST\"} ${req.url ?? \"/v1/responses\"}`,\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: { status: strictStatus, fixture: null },\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\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\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, JSON.stringify(response));\n return;\n }\n\n // Combined content + tool calls response\n if (isContentWithToolCallsResponse(response)) {\n const overrides = extractOverrides(response);\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 response.reasoning,\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 response.reasoning,\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 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 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 response.reasoning,\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 response.reasoning,\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 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 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(response.toolCalls, completionReq.model, overrides);\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 overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeResponsesSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\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/responses.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"responses.d.cts","names":[],"sources":["../src/responses.ts"],"sourcesContent":[],"mappings":";;;;;;UA6QiB,iBAAA;;;;iBAKD,qBAAA,4GAMF,oBACX;iBAgCa,yBAAA,YACH,0DAGC,oBACX;
|
|
1
|
+
{"version":3,"file":"responses.d.cts","names":[],"sources":["../src/responses.ts"],"sourcesContent":[],"mappings":";;;;;;UA6QiB,iBAAA;;;;iBAKD,qBAAA,4GAMF,oBACX;iBAgCa,yBAAA,YACH,0DAGC,oBACX;iBAgba,qCAAA,6BAEH,sGAKC,oBACX;iBAqJmB,eAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}
|
package/dist/responses.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"responses.d.ts","names":[],"sources":["../src/responses.ts"],"sourcesContent":[],"mappings":";;;;;;UA6QiB,iBAAA;;;;iBAKD,qBAAA,4GAMF,oBACX;iBAgCa,yBAAA,YACH,0DAGC,oBACX;
|
|
1
|
+
{"version":3,"file":"responses.d.ts","names":[],"sources":["../src/responses.ts"],"sourcesContent":[],"mappings":";;;;;;UA6QiB,iBAAA;;;;iBAKD,qBAAA,4GAMF,oBACX;iBAgCa,yBAAA,YACH,0DAGC,oBACX;iBAgba,qCAAA,6BAEH,sGAKC,oBACX;iBAqJmB,eAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}
|
package/dist/responses.js
CHANGED
|
@@ -428,6 +428,7 @@ function buildMessageOutputEvents(content, chunkSize, outputIndex) {
|
|
|
428
428
|
});
|
|
429
429
|
events.push({
|
|
430
430
|
type: "response.content_part.added",
|
|
431
|
+
item_id: msgId,
|
|
431
432
|
output_index: outputIndex,
|
|
432
433
|
content_index: 0,
|
|
433
434
|
part: {
|
|
@@ -445,12 +446,14 @@ function buildMessageOutputEvents(content, chunkSize, outputIndex) {
|
|
|
445
446
|
});
|
|
446
447
|
events.push({
|
|
447
448
|
type: "response.output_text.done",
|
|
449
|
+
item_id: msgId,
|
|
448
450
|
output_index: outputIndex,
|
|
449
451
|
content_index: 0,
|
|
450
452
|
text: content
|
|
451
453
|
});
|
|
452
454
|
events.push({
|
|
453
455
|
type: "response.content_part.done",
|
|
456
|
+
item_id: msgId,
|
|
454
457
|
output_index: outputIndex,
|
|
455
458
|
content_index: 0,
|
|
456
459
|
part: {
|