@copilotkit/aimock 1.19.4 → 1.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +35 -0
- package/README.md +1 -1
- package/dist/agui-recorder.cjs +4 -4
- package/dist/agui-recorder.cjs.map +1 -1
- package/dist/agui-recorder.js +4 -4
- package/dist/agui-recorder.js.map +1 -1
- package/dist/agui-types.d.ts.map +1 -1
- package/dist/bedrock.cjs +28 -3
- package/dist/bedrock.cjs.map +1 -1
- package/dist/bedrock.d.cts.map +1 -1
- package/dist/bedrock.d.ts.map +1 -1
- package/dist/bedrock.js +28 -3
- package/dist/bedrock.js.map +1 -1
- package/dist/cohere.cjs +59 -35
- package/dist/cohere.cjs.map +1 -1
- package/dist/cohere.d.cts +14 -2
- package/dist/cohere.d.cts.map +1 -1
- package/dist/cohere.d.ts +14 -2
- package/dist/cohere.d.ts.map +1 -1
- package/dist/cohere.js +59 -35
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/fixture-loader.cjs +7 -1
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.d.cts.map +1 -1
- package/dist/fixture-loader.d.ts.map +1 -1
- package/dist/fixture-loader.js +7 -1
- package/dist/fixture-loader.js.map +1 -1
- package/dist/gemini.cjs +4 -2
- package/dist/gemini.cjs.map +1 -1
- package/dist/gemini.d.cts.map +1 -1
- package/dist/gemini.d.ts.map +1 -1
- package/dist/gemini.js +5 -3
- package/dist/gemini.js.map +1 -1
- package/dist/messages.cjs +24 -4
- package/dist/messages.cjs.map +1 -1
- package/dist/messages.d.cts.map +1 -1
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +24 -4
- package/dist/messages.js.map +1 -1
- package/dist/moderation.cjs +6 -2
- package/dist/moderation.cjs.map +1 -1
- package/dist/moderation.d.cts.map +1 -1
- package/dist/moderation.d.ts.map +1 -1
- package/dist/moderation.js +6 -2
- package/dist/moderation.js.map +1 -1
- package/dist/ollama.cjs +25 -8
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.d.cts +7 -0
- package/dist/ollama.d.cts.map +1 -1
- package/dist/ollama.d.ts +7 -0
- package/dist/ollama.d.ts.map +1 -1
- package/dist/ollama.js +25 -8
- package/dist/ollama.js.map +1 -1
- package/dist/recorder.cjs +5 -2
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.js +5 -2
- package/dist/recorder.js.map +1 -1
- package/dist/rerank.cjs +4 -10
- package/dist/rerank.cjs.map +1 -1
- package/dist/rerank.js +4 -10
- package/dist/rerank.js.map +1 -1
- package/dist/responses.cjs +3 -1
- 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 -1
- package/dist/responses.js.map +1 -1
- package/dist/router.cjs +28 -0
- package/dist/router.cjs.map +1 -1
- package/dist/router.d.cts +0 -1
- package/dist/router.d.cts.map +1 -1
- package/dist/router.d.ts +0 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +28 -0
- package/dist/router.js.map +1 -1
- package/dist/search.cjs +7 -1
- package/dist/search.cjs.map +1 -1
- package/dist/search.js +7 -1
- package/dist/search.js.map +1 -1
- package/dist/server.cjs +12 -2
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +12 -2
- package/dist/server.js.map +1 -1
- package/dist/transcription.cjs +7 -6
- package/dist/transcription.cjs.map +1 -1
- package/dist/transcription.js +7 -6
- package/dist/transcription.js.map +1 -1
- package/dist/types.d.cts +11 -0
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-types.d.cts.map +1 -1
- package/dist/vector-types.d.ts.map +1 -1
- package/dist/ws-gemini-live.cjs +37 -29
- package/dist/ws-gemini-live.cjs.map +1 -1
- package/dist/ws-gemini-live.d.cts.map +1 -1
- package/dist/ws-gemini-live.d.ts.map +1 -1
- package/dist/ws-gemini-live.js +37 -29
- package/dist/ws-gemini-live.js.map +1 -1
- package/dist/ws-realtime.cjs +84 -15
- package/dist/ws-realtime.cjs.map +1 -1
- package/dist/ws-realtime.d.cts.map +1 -1
- package/dist/ws-realtime.d.ts.map +1 -1
- package/dist/ws-realtime.js +84 -16
- package/dist/ws-realtime.js.map +1 -1
- package/package.json +1 -1
- package/skills/write-fixtures/SKILL.md +2 -0
package/dist/cohere.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cohere.js","names":[],"sources":["../src/cohere.ts"],"sourcesContent":["/**\n * Cohere v2 Chat API endpoint support.\n *\n * Translates incoming /v2/chat requests into the ChatCompletionRequest\n * format used by the fixture router, and converts fixture responses back into\n * Cohere's typed SSE streaming (or non-streaming) format.\n *\n * Cohere uses typed SSE events (event: + data: lines), similar to the\n * Claude Messages handler in messages.ts.\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 generateMessageId,\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 type { Logger } from \"./logger.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n// ─── Cohere v2 Chat request types ───────────────────────────────────────────\n\ninterface CohereToolCallDef {\n id?: string;\n type: string;\n function: {\n name: string;\n arguments: string;\n };\n}\n\ninterface CohereMessage {\n role: \"user\" | \"assistant\" | \"system\" | \"tool\";\n content: string;\n tool_call_id?: string;\n tool_calls?: CohereToolCallDef[];\n}\n\ninterface CohereToolDef {\n type: string;\n function: {\n name: string;\n description?: string;\n parameters?: object;\n };\n}\n\ninterface CohereRequest {\n model: string;\n messages: CohereMessage[];\n stream?: boolean;\n tools?: CohereToolDef[];\n response_format?: { type: string; json_schema?: object };\n}\n\n// ─── Cohere SSE event types ─────────────────────────────────────────────────\n\ninterface CohereSSEEvent {\n type: string;\n [key: string]: unknown;\n}\n\n// ─── Zero-value usage block ─────────────────────────────────────────────────\n\nconst ZERO_USAGE = {\n billed_units: { input_tokens: 0, output_tokens: 0, search_units: 0, classifications: 0 },\n tokens: { input_tokens: 0, output_tokens: 0 },\n};\n\n// ─── Cohere finish reason / usage mapping ──────────────────────────────────\n\nfunction cohereFinishReason(\n overrideFinishReason: string | undefined,\n defaultReason: string,\n): string {\n if (!overrideFinishReason) return defaultReason;\n if (overrideFinishReason === \"stop\") return \"COMPLETE\";\n if (overrideFinishReason === \"tool_calls\") return \"TOOL_CALL\";\n if (overrideFinishReason === \"length\") return \"MAX_TOKENS\";\n return overrideFinishReason;\n}\n\nfunction cohereUsage(overrides?: ResponseOverrides): typeof ZERO_USAGE {\n if (!overrides?.usage) return ZERO_USAGE;\n const inputTokens = overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? 0;\n const outputTokens = overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? 0;\n return {\n billed_units: {\n input_tokens: inputTokens,\n output_tokens: outputTokens,\n search_units: 0,\n classifications: 0,\n },\n tokens: { input_tokens: inputTokens, output_tokens: outputTokens },\n };\n}\n\n// ─── Input conversion: Cohere → ChatCompletionRequest ───────────────────────\n\nexport function cohereToCompletionRequest(req: CohereRequest): ChatCompletionRequest {\n const messages: ChatMessage[] = [];\n\n for (const msg of req.messages) {\n if (msg.role === \"system\") {\n messages.push({ role: \"system\", content: msg.content });\n } else if (msg.role === \"user\") {\n messages.push({ role: \"user\", content: msg.content });\n } else if (msg.role === \"assistant\") {\n if (msg.tool_calls && msg.tool_calls.length > 0) {\n messages.push({\n role: \"assistant\",\n content: msg.content || null,\n tool_calls: msg.tool_calls.map((tc) => ({\n id: tc.id ?? generateToolCallId(),\n type: \"function\" as const,\n function: {\n name: tc.function.name,\n arguments: tc.function.arguments,\n },\n })),\n });\n } else {\n messages.push({ role: \"assistant\", content: msg.content });\n }\n } else if (msg.role === \"tool\") {\n messages.push({\n role: \"tool\",\n content: msg.content,\n tool_call_id: msg.tool_call_id,\n });\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,\n tools,\n ...(req.response_format && { response_format: req.response_format }),\n };\n}\n\n// ─── Response building: fixture → Cohere v2 Chat format ─────────────────────\n\n// Non-streaming text response\nfunction buildCohereTextResponse(\n content: string,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): object {\n const contentBlocks: { type: string; text: string }[] = [];\n if (reasoning) {\n contentBlocks.push({ type: \"text\", text: reasoning });\n }\n contentBlocks.push({ type: \"text\", text: content });\n\n return {\n id: overrides?.id ?? generateMessageId(),\n finish_reason: cohereFinishReason(overrides?.finishReason, \"COMPLETE\"),\n message: {\n role: \"assistant\",\n content: contentBlocks,\n tool_calls: [],\n tool_plan: \"\",\n citations: [],\n },\n usage: cohereUsage(overrides),\n };\n}\n\n// Non-streaming tool call response\nfunction buildCohereToolCallResponse(\n toolCalls: ToolCall[],\n logger: Logger,\n overrides?: ResponseOverrides,\n): object {\n const cohereCalls = toolCalls.map((tc) => {\n // Validate arguments JSON\n let argsJson: string;\n try {\n JSON.parse(tc.arguments || \"{}\");\n argsJson = tc.arguments || \"{}\";\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsJson = \"{}\";\n }\n return {\n id: tc.id || generateToolCallId(),\n type: \"function\",\n function: {\n name: tc.name,\n arguments: argsJson,\n },\n };\n });\n\n return {\n id: overrides?.id ?? generateMessageId(),\n finish_reason: cohereFinishReason(overrides?.finishReason, \"TOOL_CALL\"),\n message: {\n role: \"assistant\",\n content: [],\n tool_calls: cohereCalls,\n tool_plan: \"\",\n citations: [],\n },\n usage: cohereUsage(overrides),\n };\n}\n\n// Non-streaming content + tool calls response\nfunction buildCohereContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): object {\n const cohereCalls = toolCalls.map((tc) => {\n let argsJson: string;\n try {\n JSON.parse(tc.arguments || \"{}\");\n argsJson = tc.arguments || \"{}\";\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsJson = \"{}\";\n }\n return {\n id: tc.id || generateToolCallId(),\n type: \"function\",\n function: {\n name: tc.name,\n arguments: argsJson,\n },\n };\n });\n\n const contentBlocks: { type: string; text: string }[] = [];\n if (reasoning) {\n contentBlocks.push({ type: \"text\", text: reasoning });\n }\n contentBlocks.push({ type: \"text\", text: content });\n\n return {\n id: overrides?.id ?? generateMessageId(),\n finish_reason: cohereFinishReason(overrides?.finishReason, \"TOOL_CALL\"),\n message: {\n role: \"assistant\",\n content: contentBlocks,\n tool_calls: cohereCalls,\n tool_plan: \"\",\n citations: [],\n },\n usage: cohereUsage(overrides),\n };\n}\n\n// ─── Streaming event builders ───────────────────────────────────────────────\n\nfunction buildCohereTextStreamEvents(\n content: string,\n chunkSize: number,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): CohereSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const events: CohereSSEEvent[] = [];\n\n // message-start\n events.push({\n id: msgId,\n type: \"message-start\",\n delta: {\n message: {\n role: \"assistant\",\n content: [],\n tool_plan: \"\",\n tool_calls: [],\n citations: [],\n },\n },\n });\n\n let contentIndex = 0;\n\n // Reasoning as a text block before main content (Cohere has no native reasoning type)\n if (reasoning) {\n events.push({\n type: \"content-start\",\n index: contentIndex,\n delta: { message: { content: { type: \"text\" } } },\n });\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content-delta\",\n index: contentIndex,\n delta: { message: { content: { type: \"text\", text: slice } } },\n });\n }\n events.push({ type: \"content-end\", index: contentIndex });\n contentIndex++;\n }\n\n // content-start (type: \"text\" only, no text field)\n events.push({\n type: \"content-start\",\n index: contentIndex,\n delta: {\n message: {\n content: { type: \"text\" },\n },\n },\n });\n\n // content-delta — text chunks\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n type: \"content-delta\",\n index: contentIndex,\n delta: {\n message: {\n content: { type: \"text\", text: slice },\n },\n },\n });\n }\n\n // content-end\n events.push({\n type: \"content-end\",\n index: contentIndex,\n });\n\n // message-end\n events.push({\n type: \"message-end\",\n delta: {\n finish_reason: cohereFinishReason(overrides?.finishReason, \"COMPLETE\"),\n usage: cohereUsage(overrides),\n },\n });\n\n return events;\n}\n\nfunction buildCohereToolCallStreamEvents(\n toolCalls: ToolCall[],\n chunkSize: number,\n logger: Logger,\n overrides?: ResponseOverrides,\n): CohereSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const events: CohereSSEEvent[] = [];\n\n // message-start\n events.push({\n id: msgId,\n type: \"message-start\",\n delta: {\n message: {\n role: \"assistant\",\n content: [],\n tool_plan: \"\",\n tool_calls: [],\n citations: [],\n },\n },\n });\n\n // tool-plan-delta\n events.push({\n type: \"tool-plan-delta\",\n delta: {\n message: {\n tool_plan: \"I will use the requested tool.\",\n },\n },\n });\n\n for (let idx = 0; idx < toolCalls.length; idx++) {\n const tc = toolCalls[idx];\n const callId = tc.id || generateToolCallId();\n\n // Validate arguments JSON\n let argsJson: string;\n try {\n JSON.parse(tc.arguments || \"{}\");\n argsJson = tc.arguments || \"{}\";\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsJson = \"{}\";\n }\n\n // tool-call-start\n events.push({\n type: \"tool-call-start\",\n index: idx,\n delta: {\n message: {\n tool_calls: {\n id: callId,\n type: \"function\",\n function: {\n name: tc.name,\n arguments: \"\",\n },\n },\n },\n },\n });\n\n // tool-call-delta — chunked arguments\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"tool-call-delta\",\n index: idx,\n delta: {\n message: {\n tool_calls: {\n function: {\n arguments: slice,\n },\n },\n },\n },\n });\n }\n\n // tool-call-end\n events.push({\n type: \"tool-call-end\",\n index: idx,\n });\n }\n\n // message-end\n events.push({\n type: \"message-end\",\n delta: {\n finish_reason: cohereFinishReason(overrides?.finishReason, \"TOOL_CALL\"),\n usage: cohereUsage(overrides),\n },\n });\n\n return events;\n}\n\nfunction buildCohereContentWithToolCallsStreamEvents(\n content: string,\n toolCalls: ToolCall[],\n chunkSize: number,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): CohereSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const events: CohereSSEEvent[] = [];\n\n // message-start\n events.push({\n id: msgId,\n type: \"message-start\",\n delta: {\n message: {\n role: \"assistant\",\n content: [],\n tool_plan: \"\",\n tool_calls: [],\n citations: [],\n },\n },\n });\n\n let contentIndex = 0;\n\n // Reasoning as a text block before main content\n if (reasoning) {\n events.push({\n type: \"content-start\",\n index: contentIndex,\n delta: { message: { content: { type: \"text\" } } },\n });\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content-delta\",\n index: contentIndex,\n delta: { message: { content: { type: \"text\", text: slice } } },\n });\n }\n events.push({ type: \"content-end\", index: contentIndex });\n contentIndex++;\n }\n\n // content-start (type: \"text\" only, no text field)\n events.push({\n type: \"content-start\",\n index: contentIndex,\n delta: {\n message: {\n content: { type: \"text\" },\n },\n },\n });\n\n // content-delta — text chunks\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n type: \"content-delta\",\n index: contentIndex,\n delta: {\n message: {\n content: { type: \"text\", text: slice },\n },\n },\n });\n }\n\n // content-end\n events.push({\n type: \"content-end\",\n index: contentIndex,\n });\n\n // tool-plan-delta\n events.push({\n type: \"tool-plan-delta\",\n delta: {\n message: {\n tool_plan: \"I will use the requested tool.\",\n },\n },\n });\n\n // Tool call events\n for (let idx = 0; idx < toolCalls.length; idx++) {\n const tc = toolCalls[idx];\n const callId = tc.id || generateToolCallId();\n\n let argsJson: string;\n try {\n JSON.parse(tc.arguments || \"{}\");\n argsJson = tc.arguments || \"{}\";\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsJson = \"{}\";\n }\n\n // tool-call-start\n events.push({\n type: \"tool-call-start\",\n index: idx,\n delta: {\n message: {\n tool_calls: {\n id: callId,\n type: \"function\",\n function: {\n name: tc.name,\n arguments: \"\",\n },\n },\n },\n },\n });\n\n // tool-call-delta — chunked arguments\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"tool-call-delta\",\n index: idx,\n delta: {\n message: {\n tool_calls: {\n function: {\n arguments: slice,\n },\n },\n },\n },\n });\n }\n\n // tool-call-end\n events.push({\n type: \"tool-call-end\",\n index: idx,\n });\n }\n\n // message-end\n events.push({\n type: \"message-end\",\n delta: {\n finish_reason: cohereFinishReason(overrides?.finishReason, \"TOOL_CALL\"),\n usage: cohereUsage(overrides),\n },\n });\n\n return events;\n}\n\n// ─── SSE writer for Cohere typed events ─────────────────────────────────────\n\ninterface CohereStreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n}\n\nasync function writeCohereSSEStream(\n res: http.ServerResponse,\n events: CohereSSEEvent[],\n optionsOrLatency?: number | CohereStreamOptions,\n): Promise<boolean> {\n const opts: CohereStreamOptions =\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 handleCohere(\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 let cohereReq: CohereRequest;\n try {\n cohereReq = JSON.parse(raw) as CohereRequest;\n } catch {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\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 // Validate required model field\n if (!cohereReq.model) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\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: \"model is required\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n if (!cohereReq.messages || !Array.isArray(cohereReq.messages)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\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 = cohereToCompletionRequest(cohereReq);\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: req.url ?? \"/v2/chat\",\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 \"cohere\",\n req.url ?? \"/v2/chat\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\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(\n `STRICT: No fixture matched for ${req.method ?? \"POST\"} ${req.url ?? \"/v2/chat\"}`,\n );\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\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 // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\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 if (response.webSearches?.length) {\n logger.warn(\n \"webSearches in fixture response are not supported for Cohere v2 Chat API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (cohereReq.stream !== true) {\n const body = buildCohereContentWithToolCallsResponse(\n response.content,\n response.toolCalls,\n logger,\n response.reasoning,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildCohereContentWithToolCallsStreamEvents(\n response.content,\n response.toolCalls,\n chunkSize,\n logger,\n response.reasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeCohereSSEStream(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 if (response.webSearches?.length) {\n logger.warn(\n \"webSearches in fixture response are not supported for Cohere v2 Chat API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (cohereReq.stream !== true) {\n const body = buildCohereTextResponse(response.content, response.reasoning, overrides);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildCohereTextStreamEvents(\n response.content,\n chunkSize,\n response.reasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeCohereSSEStream(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 ?? \"/v2/chat\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (cohereReq.stream !== true) {\n const body = buildCohereToolCallResponse(response.toolCalls, logger, overrides);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildCohereToolCallStreamEvents(\n response.toolCalls,\n chunkSize,\n logger,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeCohereSSEStream(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 ?? \"/v2/chat\",\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":";;;;;;;;AAsFA,MAAM,aAAa;CACjB,cAAc;EAAE,cAAc;EAAG,eAAe;EAAG,cAAc;EAAG,iBAAiB;EAAG;CACxF,QAAQ;EAAE,cAAc;EAAG,eAAe;EAAG;CAC9C;AAID,SAAS,mBACP,sBACA,eACQ;AACR,KAAI,CAAC,qBAAsB,QAAO;AAClC,KAAI,yBAAyB,OAAQ,QAAO;AAC5C,KAAI,yBAAyB,aAAc,QAAO;AAClD,KAAI,yBAAyB,SAAU,QAAO;AAC9C,QAAO;;AAGT,SAAS,YAAY,WAAkD;AACrE,KAAI,CAAC,WAAW,MAAO,QAAO;CAC9B,MAAM,cAAc,UAAU,MAAM,gBAAgB,UAAU,MAAM,iBAAiB;CACrF,MAAM,eAAe,UAAU,MAAM,iBAAiB,UAAU,MAAM,qBAAqB;AAC3F,QAAO;EACL,cAAc;GACZ,cAAc;GACd,eAAe;GACf,cAAc;GACd,iBAAiB;GAClB;EACD,QAAQ;GAAE,cAAc;GAAa,eAAe;GAAc;EACnE;;AAKH,SAAgB,0BAA0B,KAA2C;CACnF,MAAM,WAA0B,EAAE;AAElC,MAAK,MAAM,OAAO,IAAI,SACpB,KAAI,IAAI,SAAS,SACf,UAAS,KAAK;EAAE,MAAM;EAAU,SAAS,IAAI;EAAS,CAAC;UAC9C,IAAI,SAAS,OACtB,UAAS,KAAK;EAAE,MAAM;EAAQ,SAAS,IAAI;EAAS,CAAC;UAC5C,IAAI,SAAS,YACtB,KAAI,IAAI,cAAc,IAAI,WAAW,SAAS,EAC5C,UAAS,KAAK;EACZ,MAAM;EACN,SAAS,IAAI,WAAW;EACxB,YAAY,IAAI,WAAW,KAAK,QAAQ;GACtC,IAAI,GAAG,MAAM,oBAAoB;GACjC,MAAM;GACN,UAAU;IACR,MAAM,GAAG,SAAS;IAClB,WAAW,GAAG,SAAS;IACxB;GACF,EAAE;EACJ,CAAC;KAEF,UAAS,KAAK;EAAE,MAAM;EAAa,SAAS,IAAI;EAAS,CAAC;UAEnD,IAAI,SAAS,OACtB,UAAS,KAAK;EACZ,MAAM;EACN,SAAS,IAAI;EACb,cAAc,IAAI;EACnB,CAAC;CAKN,IAAI;AACJ,KAAI,IAAI,SAAS,IAAI,MAAM,SAAS,EAClC,SAAQ,IAAI,MAAM,KAAK,OAAO;EAC5B,MAAM;EACN,UAAU;GACR,MAAM,EAAE,SAAS;GACjB,aAAa,EAAE,SAAS;GACxB,YAAY,EAAE,SAAS;GACxB;EACF,EAAE;AAGL,QAAO;EACL,OAAO,IAAI;EACX;EACA,QAAQ,IAAI;EACZ;EACA,GAAI,IAAI,mBAAmB,EAAE,iBAAiB,IAAI,iBAAiB;EACpE;;AAMH,SAAS,wBACP,SACA,WACA,WACQ;CACR,MAAM,gBAAkD,EAAE;AAC1D,KAAI,UACF,eAAc,KAAK;EAAE,MAAM;EAAQ,MAAM;EAAW,CAAC;AAEvD,eAAc,KAAK;EAAE,MAAM;EAAQ,MAAM;EAAS,CAAC;AAEnD,QAAO;EACL,IAAI,WAAW,MAAM,mBAAmB;EACxC,eAAe,mBAAmB,WAAW,cAAc,WAAW;EACtE,SAAS;GACP,MAAM;GACN,SAAS;GACT,YAAY,EAAE;GACd,WAAW;GACX,WAAW,EAAE;GACd;EACD,OAAO,YAAY,UAAU;EAC9B;;AAIH,SAAS,4BACP,WACA,QACA,WACQ;CACR,MAAM,cAAc,UAAU,KAAK,OAAO;EAExC,IAAI;AACJ,MAAI;AACF,QAAK,MAAM,GAAG,aAAa,KAAK;AAChC,cAAW,GAAG,aAAa;UACrB;AACN,UAAO,KACL,sDAAsD,GAAG,KAAK,KAAK,GAAG,YACvE;AACD,cAAW;;AAEb,SAAO;GACL,IAAI,GAAG,MAAM,oBAAoB;GACjC,MAAM;GACN,UAAU;IACR,MAAM,GAAG;IACT,WAAW;IACZ;GACF;GACD;AAEF,QAAO;EACL,IAAI,WAAW,MAAM,mBAAmB;EACxC,eAAe,mBAAmB,WAAW,cAAc,YAAY;EACvE,SAAS;GACP,MAAM;GACN,SAAS,EAAE;GACX,YAAY;GACZ,WAAW;GACX,WAAW,EAAE;GACd;EACD,OAAO,YAAY,UAAU;EAC9B;;AAIH,SAAS,wCACP,SACA,WACA,QACA,WACA,WACQ;CACR,MAAM,cAAc,UAAU,KAAK,OAAO;EACxC,IAAI;AACJ,MAAI;AACF,QAAK,MAAM,GAAG,aAAa,KAAK;AAChC,cAAW,GAAG,aAAa;UACrB;AACN,UAAO,KACL,sDAAsD,GAAG,KAAK,KAAK,GAAG,YACvE;AACD,cAAW;;AAEb,SAAO;GACL,IAAI,GAAG,MAAM,oBAAoB;GACjC,MAAM;GACN,UAAU;IACR,MAAM,GAAG;IACT,WAAW;IACZ;GACF;GACD;CAEF,MAAM,gBAAkD,EAAE;AAC1D,KAAI,UACF,eAAc,KAAK;EAAE,MAAM;EAAQ,MAAM;EAAW,CAAC;AAEvD,eAAc,KAAK;EAAE,MAAM;EAAQ,MAAM;EAAS,CAAC;AAEnD,QAAO;EACL,IAAI,WAAW,MAAM,mBAAmB;EACxC,eAAe,mBAAmB,WAAW,cAAc,YAAY;EACvE,SAAS;GACP,MAAM;GACN,SAAS;GACT,YAAY;GACZ,WAAW;GACX,WAAW,EAAE;GACd;EACD,OAAO,YAAY,UAAU;EAC9B;;AAKH,SAAS,4BACP,SACA,WACA,WACA,WACkB;CAClB,MAAM,QAAQ,WAAW,MAAM,mBAAmB;CAClD,MAAM,SAA2B,EAAE;AAGnC,QAAO,KAAK;EACV,IAAI;EACJ,MAAM;EACN,OAAO,EACL,SAAS;GACP,MAAM;GACN,SAAS,EAAE;GACX,WAAW;GACX,YAAY,EAAE;GACd,WAAW,EAAE;GACd,EACF;EACF,CAAC;CAEF,IAAI,eAAe;AAGnB,KAAI,WAAW;AACb,SAAO,KAAK;GACV,MAAM;GACN,OAAO;GACP,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,QAAQ,EAAE,EAAE;GAClD,CAAC;AACF,OAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK,WAAW;GACpD,MAAM,QAAQ,UAAU,MAAM,GAAG,IAAI,UAAU;AAC/C,UAAO,KAAK;IACV,MAAM;IACN,OAAO;IACP,OAAO,EAAE,SAAS,EAAE,SAAS;KAAE,MAAM;KAAQ,MAAM;KAAO,EAAE,EAAE;IAC/D,CAAC;;AAEJ,SAAO,KAAK;GAAE,MAAM;GAAe,OAAO;GAAc,CAAC;AACzD;;AAIF,QAAO,KAAK;EACV,MAAM;EACN,OAAO;EACP,OAAO,EACL,SAAS,EACP,SAAS,EAAE,MAAM,QAAQ,EAC1B,EACF;EACF,CAAC;AAGF,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,WAAW;EAClD,MAAM,QAAQ,QAAQ,MAAM,GAAG,IAAI,UAAU;AAC7C,SAAO,KAAK;GACV,MAAM;GACN,OAAO;GACP,OAAO,EACL,SAAS,EACP,SAAS;IAAE,MAAM;IAAQ,MAAM;IAAO,EACvC,EACF;GACF,CAAC;;AAIJ,QAAO,KAAK;EACV,MAAM;EACN,OAAO;EACR,CAAC;AAGF,QAAO,KAAK;EACV,MAAM;EACN,OAAO;GACL,eAAe,mBAAmB,WAAW,cAAc,WAAW;GACtE,OAAO,YAAY,UAAU;GAC9B;EACF,CAAC;AAEF,QAAO;;AAGT,SAAS,gCACP,WACA,WACA,QACA,WACkB;CAClB,MAAM,QAAQ,WAAW,MAAM,mBAAmB;CAClD,MAAM,SAA2B,EAAE;AAGnC,QAAO,KAAK;EACV,IAAI;EACJ,MAAM;EACN,OAAO,EACL,SAAS;GACP,MAAM;GACN,SAAS,EAAE;GACX,WAAW;GACX,YAAY,EAAE;GACd,WAAW,EAAE;GACd,EACF;EACF,CAAC;AAGF,QAAO,KAAK;EACV,MAAM;EACN,OAAO,EACL,SAAS,EACP,WAAW,kCACZ,EACF;EACF,CAAC;AAEF,MAAK,IAAI,MAAM,GAAG,MAAM,UAAU,QAAQ,OAAO;EAC/C,MAAM,KAAK,UAAU;EACrB,MAAM,SAAS,GAAG,MAAM,oBAAoB;EAG5C,IAAI;AACJ,MAAI;AACF,QAAK,MAAM,GAAG,aAAa,KAAK;AAChC,cAAW,GAAG,aAAa;UACrB;AACN,UAAO,KACL,sDAAsD,GAAG,KAAK,KAAK,GAAG,YACvE;AACD,cAAW;;AAIb,SAAO,KAAK;GACV,MAAM;GACN,OAAO;GACP,OAAO,EACL,SAAS,EACP,YAAY;IACV,IAAI;IACJ,MAAM;IACN,UAAU;KACR,MAAM,GAAG;KACT,WAAW;KACZ;IACF,EACF,EACF;GACF,CAAC;AAGF,OAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,WAAW;GACnD,MAAM,QAAQ,SAAS,MAAM,GAAG,IAAI,UAAU;AAC9C,UAAO,KAAK;IACV,MAAM;IACN,OAAO;IACP,OAAO,EACL,SAAS,EACP,YAAY,EACV,UAAU,EACR,WAAW,OACZ,EACF,EACF,EACF;IACF,CAAC;;AAIJ,SAAO,KAAK;GACV,MAAM;GACN,OAAO;GACR,CAAC;;AAIJ,QAAO,KAAK;EACV,MAAM;EACN,OAAO;GACL,eAAe,mBAAmB,WAAW,cAAc,YAAY;GACvE,OAAO,YAAY,UAAU;GAC9B;EACF,CAAC;AAEF,QAAO;;AAGT,SAAS,4CACP,SACA,WACA,WACA,QACA,WACA,WACkB;CAClB,MAAM,QAAQ,WAAW,MAAM,mBAAmB;CAClD,MAAM,SAA2B,EAAE;AAGnC,QAAO,KAAK;EACV,IAAI;EACJ,MAAM;EACN,OAAO,EACL,SAAS;GACP,MAAM;GACN,SAAS,EAAE;GACX,WAAW;GACX,YAAY,EAAE;GACd,WAAW,EAAE;GACd,EACF;EACF,CAAC;CAEF,IAAI,eAAe;AAGnB,KAAI,WAAW;AACb,SAAO,KAAK;GACV,MAAM;GACN,OAAO;GACP,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,QAAQ,EAAE,EAAE;GAClD,CAAC;AACF,OAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK,WAAW;GACpD,MAAM,QAAQ,UAAU,MAAM,GAAG,IAAI,UAAU;AAC/C,UAAO,KAAK;IACV,MAAM;IACN,OAAO;IACP,OAAO,EAAE,SAAS,EAAE,SAAS;KAAE,MAAM;KAAQ,MAAM;KAAO,EAAE,EAAE;IAC/D,CAAC;;AAEJ,SAAO,KAAK;GAAE,MAAM;GAAe,OAAO;GAAc,CAAC;AACzD;;AAIF,QAAO,KAAK;EACV,MAAM;EACN,OAAO;EACP,OAAO,EACL,SAAS,EACP,SAAS,EAAE,MAAM,QAAQ,EAC1B,EACF;EACF,CAAC;AAGF,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,WAAW;EAClD,MAAM,QAAQ,QAAQ,MAAM,GAAG,IAAI,UAAU;AAC7C,SAAO,KAAK;GACV,MAAM;GACN,OAAO;GACP,OAAO,EACL,SAAS,EACP,SAAS;IAAE,MAAM;IAAQ,MAAM;IAAO,EACvC,EACF;GACF,CAAC;;AAIJ,QAAO,KAAK;EACV,MAAM;EACN,OAAO;EACR,CAAC;AAGF,QAAO,KAAK;EACV,MAAM;EACN,OAAO,EACL,SAAS,EACP,WAAW,kCACZ,EACF;EACF,CAAC;AAGF,MAAK,IAAI,MAAM,GAAG,MAAM,UAAU,QAAQ,OAAO;EAC/C,MAAM,KAAK,UAAU;EACrB,MAAM,SAAS,GAAG,MAAM,oBAAoB;EAE5C,IAAI;AACJ,MAAI;AACF,QAAK,MAAM,GAAG,aAAa,KAAK;AAChC,cAAW,GAAG,aAAa;UACrB;AACN,UAAO,KACL,sDAAsD,GAAG,KAAK,KAAK,GAAG,YACvE;AACD,cAAW;;AAIb,SAAO,KAAK;GACV,MAAM;GACN,OAAO;GACP,OAAO,EACL,SAAS,EACP,YAAY;IACV,IAAI;IACJ,MAAM;IACN,UAAU;KACR,MAAM,GAAG;KACT,WAAW;KACZ;IACF,EACF,EACF;GACF,CAAC;AAGF,OAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,WAAW;GACnD,MAAM,QAAQ,SAAS,MAAM,GAAG,IAAI,UAAU;AAC9C,UAAO,KAAK;IACV,MAAM;IACN,OAAO;IACP,OAAO,EACL,SAAS,EACP,YAAY,EACV,UAAU,EACR,WAAW,OACZ,EACF,EACF,EACF;IACF,CAAC;;AAIJ,SAAO,KAAK;GACV,MAAM;GACN,OAAO;GACR,CAAC;;AAIJ,QAAO,KAAK;EACV,MAAM;EACN,OAAO;GACL,eAAe,mBAAmB,WAAW,cAAc,YAAY;GACvE,OAAO,YAAY,UAAU;GAC9B;EACF,CAAC;AAEF,QAAO;;AAYT,eAAe,qBACb,KACA,QACA,kBACkB;CAClB,MAAM,OACJ,OAAO,qBAAqB,WAAW,EAAE,SAAS,kBAAkB,GAAI,oBAAoB,EAAE;CAChG,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,UAAU,KAAK;CACrB,MAAM,SAAS,KAAK;CACpB,MAAM,cAAc,KAAK;AAEzB,KAAI,IAAI,cAAe,QAAO;AAC9B,KAAI,UAAU,gBAAgB,oBAAoB;AAClD,KAAI,UAAU,iBAAiB,WAAW;AAC1C,KAAI,UAAU,cAAc,aAAa;CAEzC,IAAI,aAAa;AACjB,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,aAAa,eAAe,YAAY,SAAS,QAAQ;AAC/D,MAAI,aAAa,EAAG,OAAM,MAAM,YAAY,OAAO;AACnD,MAAI,QAAQ,QAAS,QAAO;AAC5B,MAAI,IAAI,cAAe,QAAO;AAC9B,MAAI,MAAM,UAAU,MAAM,KAAK,UAAU,KAAK,UAAU,MAAM,CAAC,MAAM;AACrE,iBAAe;AACf,MAAI,QAAQ,QAAS,QAAO;AAC5B;;AAGF,KAAI,CAAC,IAAI,cACP,KAAI,KAAK;AAEX,QAAO;;AAKT,eAAsB,aACpB,KACA,KACA,KACA,UACA,SACA,UACA,gBACe;CACf,MAAM,EAAE,WAAW;AACnB,gBAAe,IAAI;CAEnB,IAAI;AACJ,KAAI;AACF,cAAY,KAAK,MAAM,IAAI;SACrB;AACN,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,qBACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACP,EACF,CAAC,CACH;AACD;;AAIF,KAAI,CAAC,UAAU,OAAO;AACpB,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,qBACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACP,EACF,CAAC,CACH;AACD;;AAGF,KAAI,CAAC,UAAU,YAAY,CAAC,MAAM,QAAQ,UAAU,SAAS,EAAE;AAC7D,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,qBACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACP,EACF,CAAC,CACH;AACD;;CAIF,MAAM,gBAAgB,0BAA0B,UAAU;AAC1D,eAAc,gBAAgB;CAE9B,MAAM,SAAS,UAAU,IAAI;CAC7B,MAAM,UAAU,aACd,UACA,eACA,QAAQ,6BAA6B,OAAO,EAC5C,SAAS,iBACV;AAED,KAAI,SAAS;AACX,UAAQ,2BAA2B,SAAS,UAAU,OAAO;AAC7D,SAAO,MAAM,oBAAoB,KAAK,UAAU,QAAQ,MAAM,CAAC,MAAM,GAAG,IAAI,GAAG;OAE/E,QAAO,MAAM,iCAAiC;AAGhD,KACE,WACE,KACA,SACA,SAAS,OACT,IAAI,SACJ,SACA;EACE,QAAQ,IAAI,UAAU;EACtB,MAAM,IAAI,OAAO;EACjB,SAAS,eAAe,IAAI,QAAQ;EACpC,MAAM;EACP,EACD,UAAU,YAAY,SACtB,SAAS,UACT,SAAS,OACV,CAED;AAEF,KAAI,CAAC,SAAS;AACZ,MAAI,SAAS,QAWX;OAVgB,MAAM,eACpB,KACA,KACA,eACA,UACA,IAAI,OAAO,YACX,UACA,UACA,IACD,KACe,kBAAkB;AAChC,YAAQ,IAAI;KACV,QAAQ,IAAI,UAAU;KACtB,MAAM,IAAI,OAAO;KACjB,SAAS,eAAe,IAAI,QAAQ;KACpC,MAAM;KACN,UAAU;MAAE,QAAQ,IAAI,cAAc;MAAK,SAAS;MAAM,QAAQ;MAAS;KAC5E,CAAC;AACF;;;EAGJ,MAAM,eAAe,SAAS,SAAS,MAAM;EAC7C,MAAM,gBAAgB,SAAS,SAC3B,oCACA;AACJ,MAAI,SAAS,OACX,QAAO,MACL,kCAAkC,IAAI,UAAU,OAAO,GAAG,IAAI,OAAO,aACtE;AAEH,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAc,SAAS;IAAM;GAClD,CAAC;AACF,qBACE,KACA,cACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACP,EACF,CAAC,CACH;AACD;;CAGF,MAAM,WAAW,MAAM,gBAAgB,SAAS,cAAc;CAC9D,MAAM,UAAU,QAAQ,WAAW,SAAS;CAC5C,MAAM,YAAY,KAAK,IAAI,GAAG,QAAQ,aAAa,SAAS,UAAU;AAGtE,KAAI,gBAAgB,SAAS,EAAE;EAC7B,MAAM,SAAS,SAAS,UAAU;AAClC,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE;IAAQ;IAAS;GAC9B,CAAC;AACF,qBAAmB,KAAK,QAAQ,KAAK,UAAU,SAAS,CAAC;AACzD;;AAIF,KAAI,+BAA+B,SAAS,EAAE;AAC5C,MAAI,SAAS,aAAa,OACxB,QAAO,KACL,sFACD;EAEH,MAAM,YAAY,iBAAiB,SAAS;EAC5C,MAAM,eAAe,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,MAAI,UAAU,WAAW,MAAM;GAC7B,MAAM,OAAO,wCACX,SAAS,SACT,SAAS,WACT,QACA,SAAS,WACT,UACD;AACD,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,KAAK,CAAC;SACxB;GACL,MAAM,SAAS,4CACb,SAAS,SACT,SAAS,WACT,WACA,QACA,SAAS,WACT,UACD;GACD,MAAM,eAAe,yBAAyB,QAAQ;AAOtD,OAAI,CANc,MAAM,qBAAqB,KAAK,QAAQ;IACxD;IACA,kBAAkB,QAAQ;IAC1B,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC5B,CAAC,EACc;AACd,QAAI,CAAC,IAAI,cAAe,KAAI,SAAS;AACrC,iBAAa,SAAS,cAAc;AACpC,iBAAa,SAAS,kBAAkB,cAAc,QAAQ;;AAEhE,iBAAc,SAAS;;AAEzB;;AAIF,KAAI,eAAe,SAAS,EAAE;AAC5B,MAAI,SAAS,aAAa,OACxB,QAAO,KACL,sFACD;EAEH,MAAM,YAAY,iBAAiB,SAAS;EAC5C,MAAM,eAAe,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,MAAI,UAAU,WAAW,MAAM;GAC7B,MAAM,OAAO,wBAAwB,SAAS,SAAS,SAAS,WAAW,UAAU;AACrF,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,KAAK,CAAC;SACxB;GACL,MAAM,SAAS,4BACb,SAAS,SACT,WACA,SAAS,WACT,UACD;GACD,MAAM,eAAe,yBAAyB,QAAQ;AAOtD,OAAI,CANc,MAAM,qBAAqB,KAAK,QAAQ;IACxD;IACA,kBAAkB,QAAQ;IAC1B,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC5B,CAAC,EACc;AACd,QAAI,CAAC,IAAI,cAAe,KAAI,SAAS;AACrC,iBAAa,SAAS,cAAc;AACpC,iBAAa,SAAS,kBAAkB,cAAc,QAAQ;;AAEhE,iBAAc,SAAS;;AAEzB;;AAIF,KAAI,mBAAmB,SAAS,EAAE;EAChC,MAAM,YAAY,iBAAiB,SAAS;EAC5C,MAAM,eAAe,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,MAAI,UAAU,WAAW,MAAM;GAC7B,MAAM,OAAO,4BAA4B,SAAS,WAAW,QAAQ,UAAU;AAC/E,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,KAAK,CAAC;SACxB;GACL,MAAM,SAAS,gCACb,SAAS,WACT,WACA,QACA,UACD;GACD,MAAM,eAAe,yBAAyB,QAAQ;AAOtD,OAAI,CANc,MAAM,qBAAqB,KAAK,QAAQ;IACxD;IACA,kBAAkB,QAAQ;IAC1B,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC5B,CAAC,EACc;AACd,QAAI,CAAC,IAAI,cAAe,KAAI,SAAS;AACrC,iBAAa,SAAS,cAAc;AACpC,iBAAa,SAAS,kBAAkB,cAAc,QAAQ;;AAEhE,iBAAc,SAAS;;AAEzB;;AAIF,SAAQ,IAAI;EACV,QAAQ,IAAI,UAAU;EACtB,MAAM,IAAI,OAAO;EACjB,SAAS,eAAe,IAAI,QAAQ;EACpC,MAAM;EACN,UAAU;GAAE,QAAQ;GAAK;GAAS;EACnC,CAAC;AACF,oBACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;EACL,SAAS;EACT,MAAM;EACP,EACF,CAAC,CACH"}
|
|
1
|
+
{"version":3,"file":"cohere.js","names":[],"sources":["../src/cohere.ts"],"sourcesContent":["/**\n * Cohere v2 Chat API endpoint support.\n *\n * Translates incoming /v2/chat requests into the ChatCompletionRequest\n * format used by the fixture router, and converts fixture responses back into\n * Cohere's typed SSE streaming (or non-streaming) format.\n *\n * Cohere uses typed SSE events (event: + data: lines), similar to the\n * Claude Messages handler in messages.ts.\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 generateMessageId,\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 type { Logger } from \"./logger.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n// ─── Cohere v2 Chat request types ───────────────────────────────────────────\n\ninterface CohereToolCallDef {\n id?: string;\n type: string;\n function: {\n name: string;\n arguments: string;\n };\n}\n\ninterface CohereContentPart {\n type: string;\n text?: string;\n}\n\ninterface CohereMessage {\n role: \"user\" | \"assistant\" | \"system\" | \"tool\";\n content: string | CohereContentPart[];\n tool_call_id?: string;\n tool_calls?: CohereToolCallDef[];\n}\n\n// OpenAI-style tool definition (wrapped in { type: \"function\", function: { ... } })\ninterface CohereToolDefOpenAI {\n type: string;\n function: {\n name: string;\n description?: string;\n parameters?: object;\n };\n}\n\n// Cohere v2 native tool definition (flat: { name, description, parameter_definitions })\ninterface CohereToolDefNative {\n name: string;\n description?: string;\n parameter_definitions?: object;\n}\n\ntype CohereToolDef = CohereToolDefOpenAI | CohereToolDefNative;\n\ninterface CohereRequest {\n model: string;\n messages: CohereMessage[];\n stream?: boolean;\n tools?: CohereToolDef[];\n response_format?: { type: string; json_schema?: object };\n temperature?: number;\n max_tokens?: number;\n}\n\n// ─── Cohere SSE event types ─────────────────────────────────────────────────\n\ninterface CohereSSEEvent {\n type: string;\n [key: string]: unknown;\n}\n\n// ─── Zero-value usage block ─────────────────────────────────────────────────\n\nconst ZERO_USAGE = {\n billed_units: { input_tokens: 0, output_tokens: 0, search_units: 0, classifications: 0 },\n tokens: { input_tokens: 0, output_tokens: 0 },\n};\n\n// ─── Cohere finish reason / usage mapping ──────────────────────────────────\n\nfunction cohereFinishReason(\n overrideFinishReason: string | undefined,\n defaultReason: string,\n): string {\n if (!overrideFinishReason) return defaultReason;\n if (overrideFinishReason === \"stop\") return \"COMPLETE\";\n if (overrideFinishReason === \"tool_calls\") return \"TOOL_CALL\";\n if (overrideFinishReason === \"length\") return \"MAX_TOKENS\";\n return overrideFinishReason;\n}\n\nfunction cohereUsage(overrides?: ResponseOverrides): typeof ZERO_USAGE {\n if (!overrides?.usage) return ZERO_USAGE;\n const inputTokens = overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? 0;\n const outputTokens = overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? 0;\n return {\n billed_units: {\n input_tokens: inputTokens,\n output_tokens: outputTokens,\n search_units: 0,\n classifications: 0,\n },\n tokens: { input_tokens: inputTokens, output_tokens: outputTokens },\n };\n}\n\n// ─── Input conversion: Cohere → ChatCompletionRequest ───────────────────────\n\n/** Extract plain text from structured content (array of { type, text } parts) or passthrough string. */\nfunction extractTextContent(content: string | CohereContentPart[]): string {\n if (typeof content === \"string\") return content;\n return content\n .filter((part) => part.type === \"text\" && part.text !== undefined)\n .map((part) => part.text!)\n .join(\"\");\n}\n\n/** Type guard: is this an OpenAI-style tool definition (has `function` key)? */\nfunction isOpenAIToolDef(t: CohereToolDef): t is CohereToolDefOpenAI {\n return \"function\" in t && typeof (t as CohereToolDefOpenAI).function === \"object\";\n}\n\nexport function cohereToCompletionRequest(req: CohereRequest): ChatCompletionRequest {\n const messages: ChatMessage[] = [];\n\n for (const msg of req.messages) {\n const textContent = extractTextContent(msg.content);\n if (msg.role === \"system\") {\n messages.push({ role: \"system\", content: textContent });\n } else if (msg.role === \"user\") {\n messages.push({ role: \"user\", content: textContent });\n } else if (msg.role === \"assistant\") {\n if (msg.tool_calls && msg.tool_calls.length > 0) {\n messages.push({\n role: \"assistant\",\n content: textContent || null,\n tool_calls: msg.tool_calls.map((tc) => ({\n id: tc.id ?? generateToolCallId(),\n type: \"function\" as const,\n function: {\n name: tc.function.name,\n arguments: tc.function.arguments,\n },\n })),\n });\n } else {\n messages.push({ role: \"assistant\", content: textContent });\n }\n } else if (msg.role === \"tool\") {\n messages.push({\n role: \"tool\",\n content: textContent,\n tool_call_id: msg.tool_call_id,\n });\n }\n }\n\n // Convert tools — accept both OpenAI format and Cohere v2 native format\n let tools: ToolDefinition[] | undefined;\n if (req.tools && req.tools.length > 0) {\n tools = req.tools.map((t) => {\n if (isOpenAIToolDef(t)) {\n return {\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 // Cohere v2 native format: { name, description, parameter_definitions }\n return {\n type: \"function\" as const,\n function: {\n name: t.name,\n description: t.description,\n parameters: t.parameter_definitions,\n },\n };\n });\n }\n\n return {\n model: req.model,\n messages,\n stream: req.stream,\n tools,\n ...(req.response_format && { response_format: req.response_format }),\n ...(req.temperature !== undefined && { temperature: req.temperature }),\n ...(req.max_tokens !== undefined && { max_tokens: req.max_tokens }),\n };\n}\n\n// ─── Response building: fixture → Cohere v2 Chat format ─────────────────────\n\n// Non-streaming text response\nfunction buildCohereTextResponse(\n content: string,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): object {\n const contentBlocks: { type: string; text: string }[] = [];\n if (reasoning) {\n contentBlocks.push({ type: \"text\", text: reasoning });\n }\n contentBlocks.push({ type: \"text\", text: content });\n\n return {\n id: overrides?.id ?? generateMessageId(),\n finish_reason: cohereFinishReason(overrides?.finishReason, \"COMPLETE\"),\n message: {\n role: \"assistant\",\n content: contentBlocks,\n tool_calls: [],\n tool_plan: \"\",\n citations: [],\n },\n usage: cohereUsage(overrides),\n };\n}\n\n// Non-streaming tool call response\nfunction buildCohereToolCallResponse(\n toolCalls: ToolCall[],\n logger: Logger,\n overrides?: ResponseOverrides,\n): object {\n const cohereCalls = toolCalls.map((tc) => {\n // Validate arguments JSON\n let argsJson: string;\n try {\n JSON.parse(tc.arguments || \"{}\");\n argsJson = tc.arguments || \"{}\";\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsJson = \"{}\";\n }\n return {\n id: tc.id || generateToolCallId(),\n type: \"function\",\n function: {\n name: tc.name,\n arguments: argsJson,\n },\n };\n });\n\n return {\n id: overrides?.id ?? generateMessageId(),\n finish_reason: cohereFinishReason(overrides?.finishReason, \"TOOL_CALL\"),\n message: {\n role: \"assistant\",\n content: [],\n tool_calls: cohereCalls,\n tool_plan: \"\",\n citations: [],\n },\n usage: cohereUsage(overrides),\n };\n}\n\n// Non-streaming content + tool calls response\nfunction buildCohereContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): object {\n const cohereCalls = toolCalls.map((tc) => {\n let argsJson: string;\n try {\n JSON.parse(tc.arguments || \"{}\");\n argsJson = tc.arguments || \"{}\";\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsJson = \"{}\";\n }\n return {\n id: tc.id || generateToolCallId(),\n type: \"function\",\n function: {\n name: tc.name,\n arguments: argsJson,\n },\n };\n });\n\n const contentBlocks: { type: string; text: string }[] = [];\n if (reasoning) {\n contentBlocks.push({ type: \"text\", text: reasoning });\n }\n contentBlocks.push({ type: \"text\", text: content });\n\n return {\n id: overrides?.id ?? generateMessageId(),\n finish_reason: cohereFinishReason(overrides?.finishReason, \"TOOL_CALL\"),\n message: {\n role: \"assistant\",\n content: contentBlocks,\n tool_calls: cohereCalls,\n tool_plan: \"\",\n citations: [],\n },\n usage: cohereUsage(overrides),\n };\n}\n\n// ─── Streaming event builders ───────────────────────────────────────────────\n\nfunction buildCohereTextStreamEvents(\n content: string,\n chunkSize: number,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): CohereSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const events: CohereSSEEvent[] = [];\n\n // message-start\n events.push({\n id: msgId,\n type: \"message-start\",\n delta: {\n message: {\n role: \"assistant\",\n content: [],\n tool_plan: \"\",\n tool_calls: [],\n citations: [],\n },\n },\n });\n\n let contentIndex = 0;\n\n // Reasoning as a text block before main content (Cohere has no native reasoning type)\n if (reasoning) {\n events.push({\n type: \"content-start\",\n index: contentIndex,\n delta: { message: { content: { type: \"text\" } } },\n });\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content-delta\",\n index: contentIndex,\n delta: { message: { content: { type: \"text\", text: slice } } },\n });\n }\n events.push({ type: \"content-end\", index: contentIndex });\n contentIndex++;\n }\n\n // content-start (type: \"text\" only, no text field)\n events.push({\n type: \"content-start\",\n index: contentIndex,\n delta: {\n message: {\n content: { type: \"text\" },\n },\n },\n });\n\n // content-delta — text chunks\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n type: \"content-delta\",\n index: contentIndex,\n delta: {\n message: {\n content: { type: \"text\", text: slice },\n },\n },\n });\n }\n\n // content-end\n events.push({\n type: \"content-end\",\n index: contentIndex,\n });\n\n // message-end\n events.push({\n type: \"message-end\",\n delta: {\n finish_reason: cohereFinishReason(overrides?.finishReason, \"COMPLETE\"),\n usage: cohereUsage(overrides),\n },\n });\n\n return events;\n}\n\nfunction buildCohereToolCallStreamEvents(\n toolCalls: ToolCall[],\n chunkSize: number,\n logger: Logger,\n overrides?: ResponseOverrides,\n): CohereSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const events: CohereSSEEvent[] = [];\n\n // message-start\n events.push({\n id: msgId,\n type: \"message-start\",\n delta: {\n message: {\n role: \"assistant\",\n content: [],\n tool_plan: \"\",\n tool_calls: [],\n citations: [],\n },\n },\n });\n\n // tool-plan-delta\n events.push({\n type: \"tool-plan-delta\",\n delta: {\n message: {\n tool_plan: \"I will use the requested tool.\",\n },\n },\n });\n\n for (let idx = 0; idx < toolCalls.length; idx++) {\n const tc = toolCalls[idx];\n const callId = tc.id || generateToolCallId();\n\n // Validate arguments JSON\n let argsJson: string;\n try {\n JSON.parse(tc.arguments || \"{}\");\n argsJson = tc.arguments || \"{}\";\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsJson = \"{}\";\n }\n\n // tool-call-start\n events.push({\n type: \"tool-call-start\",\n index: idx,\n delta: {\n message: {\n tool_calls: {\n id: callId,\n type: \"function\",\n function: {\n name: tc.name,\n arguments: \"\",\n },\n },\n },\n },\n });\n\n // tool-call-delta — chunked arguments\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"tool-call-delta\",\n index: idx,\n delta: {\n message: {\n tool_calls: {\n function: {\n arguments: slice,\n },\n },\n },\n },\n });\n }\n\n // tool-call-end\n events.push({\n type: \"tool-call-end\",\n index: idx,\n });\n }\n\n // message-end\n events.push({\n type: \"message-end\",\n delta: {\n finish_reason: cohereFinishReason(overrides?.finishReason, \"TOOL_CALL\"),\n usage: cohereUsage(overrides),\n },\n });\n\n return events;\n}\n\nfunction buildCohereContentWithToolCallsStreamEvents(\n content: string,\n toolCalls: ToolCall[],\n chunkSize: number,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n): CohereSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const events: CohereSSEEvent[] = [];\n\n // message-start\n events.push({\n id: msgId,\n type: \"message-start\",\n delta: {\n message: {\n role: \"assistant\",\n content: [],\n tool_plan: \"\",\n tool_calls: [],\n citations: [],\n },\n },\n });\n\n let contentIndex = 0;\n\n // Reasoning as a text block before main content\n if (reasoning) {\n events.push({\n type: \"content-start\",\n index: contentIndex,\n delta: { message: { content: { type: \"text\" } } },\n });\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content-delta\",\n index: contentIndex,\n delta: { message: { content: { type: \"text\", text: slice } } },\n });\n }\n events.push({ type: \"content-end\", index: contentIndex });\n contentIndex++;\n }\n\n // content-start (type: \"text\" only, no text field)\n events.push({\n type: \"content-start\",\n index: contentIndex,\n delta: {\n message: {\n content: { type: \"text\" },\n },\n },\n });\n\n // content-delta — text chunks\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n type: \"content-delta\",\n index: contentIndex,\n delta: {\n message: {\n content: { type: \"text\", text: slice },\n },\n },\n });\n }\n\n // content-end\n events.push({\n type: \"content-end\",\n index: contentIndex,\n });\n\n // tool-plan-delta\n events.push({\n type: \"tool-plan-delta\",\n delta: {\n message: {\n tool_plan: \"I will use the requested tool.\",\n },\n },\n });\n\n // Tool call events\n for (let idx = 0; idx < toolCalls.length; idx++) {\n const tc = toolCalls[idx];\n const callId = tc.id || generateToolCallId();\n\n let argsJson: string;\n try {\n JSON.parse(tc.arguments || \"{}\");\n argsJson = tc.arguments || \"{}\";\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsJson = \"{}\";\n }\n\n // tool-call-start\n events.push({\n type: \"tool-call-start\",\n index: idx,\n delta: {\n message: {\n tool_calls: {\n id: callId,\n type: \"function\",\n function: {\n name: tc.name,\n arguments: \"\",\n },\n },\n },\n },\n });\n\n // tool-call-delta — chunked arguments\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"tool-call-delta\",\n index: idx,\n delta: {\n message: {\n tool_calls: {\n function: {\n arguments: slice,\n },\n },\n },\n },\n });\n }\n\n // tool-call-end\n events.push({\n type: \"tool-call-end\",\n index: idx,\n });\n }\n\n // message-end\n events.push({\n type: \"message-end\",\n delta: {\n finish_reason: cohereFinishReason(overrides?.finishReason, \"TOOL_CALL\"),\n usage: cohereUsage(overrides),\n },\n });\n\n return events;\n}\n\n// ─── SSE writer for Cohere typed events ─────────────────────────────────────\n\ninterface CohereStreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n}\n\nasync function writeCohereSSEStream(\n res: http.ServerResponse,\n events: CohereSSEEvent[],\n optionsOrLatency?: number | CohereStreamOptions,\n): Promise<boolean> {\n const opts: CohereStreamOptions =\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 handleCohere(\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 let cohereReq: CohereRequest;\n try {\n cohereReq = JSON.parse(raw) as CohereRequest;\n } catch {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\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 // Validate required model field\n if (!cohereReq.model) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\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: \"model is required\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n if (!cohereReq.messages || !Array.isArray(cohereReq.messages)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\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 = cohereToCompletionRequest(cohereReq);\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: req.url ?? \"/v2/chat\",\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 \"cohere\",\n req.url ?? \"/v2/chat\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\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(\n `STRICT: No fixture matched for ${req.method ?? \"POST\"} ${req.url ?? \"/v2/chat\"}`,\n );\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\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 // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\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 if (response.webSearches?.length) {\n logger.warn(\n \"webSearches in fixture response are not supported for Cohere v2 Chat API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (cohereReq.stream !== true) {\n const body = buildCohereContentWithToolCallsResponse(\n response.content,\n response.toolCalls,\n logger,\n response.reasoning,\n overrides,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildCohereContentWithToolCallsStreamEvents(\n response.content,\n response.toolCalls,\n chunkSize,\n logger,\n response.reasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeCohereSSEStream(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 if (response.webSearches?.length) {\n logger.warn(\n \"webSearches in fixture response are not supported for Cohere v2 Chat API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (cohereReq.stream !== true) {\n const body = buildCohereTextResponse(response.content, response.reasoning, overrides);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildCohereTextStreamEvents(\n response.content,\n chunkSize,\n response.reasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeCohereSSEStream(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 ?? \"/v2/chat\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (cohereReq.stream !== true) {\n const body = buildCohereToolCallResponse(response.toolCalls, logger, overrides);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildCohereToolCallStreamEvents(\n response.toolCalls,\n chunkSize,\n logger,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeCohereSSEStream(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 ?? \"/v2/chat\",\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.d.ts","names":[],"sources":["../src/config-loader.ts"],"sourcesContent":[],"mappings":";;;;;;;;UAciB,aAAA,SAAsB;;AAAvC;AAIiB,UAAA,iBAAA,CAAiB;EASjB,GAAA,EAAA,MAAA;EAAgB,IAAA,EAAA,MAAA;UAEnB,CAAA,EAAA,MAAA;aAF2B,CAAA,EAAA,MAAA;EAAmB,IAAA,CAAA,EAAA,MAAA;EAM3C,IAAA,CAAA,EAAA,MAAS;;AAGhB,UATO,eAAA,SAAwB,mBAS/B,CAAA;QACI,CAAA,EAAA;IACF,QAAA,EATE,KASF,CAAA;MAAe,IAAA,EAAA,MAAA;MAGV,OAAA,EAAA;QAAgB,IAAA,EAAA,MAAA;QAEvB,IAAA,EAAA,MAAA;MACI,CAAA;IACH,CAAA,CAAA;EAAc,CAAA;AAIzB;AAAgC,UAhBf,SAAA,CAgBe;MACnB,CAAA,EAAA,MAAA;YACH,CAAA,EAAA;IACS,IAAA,EAAA,MAAA;IAHqB,OAAA,EAAA,MAAA;EAAkB,CAAA;EAMzC,KAAA,CAAA,EAnBP,aAmBgB,
|
|
1
|
+
{"version":3,"file":"config-loader.d.ts","names":[],"sources":["../src/config-loader.ts"],"sourcesContent":[],"mappings":";;;;;;;;UAciB,aAAA,SAAsB;;AAAvC;AAIiB,UAAA,iBAAA,CAAiB;EASjB,GAAA,EAAA,MAAA;EAAgB,IAAA,EAAA,MAAA;UAEnB,CAAA,EAAA,MAAA;aAF2B,CAAA,EAAA,MAAA;EAAmB,IAAA,CAAA,EAAA,MAAA;EAM3C,IAAA,CAAA,EAAA,MAAS;;AAGhB,UATO,eAAA,SAAwB,mBAS/B,CAAA;QACI,CAAA,EAAA;IACF,QAAA,EATE,KASF,CAAA;MAAe,IAAA,EAAA,MAAA;MAGV,OAAA,EAAA;QAAgB,IAAA,EAAA,MAAA;QAEvB,IAAA,EAAA,MAAA;MACI,CAAA;IACH,CAAA,CAAA;EAAc,CAAA;AAIzB;AAAgC,UAhBf,SAAA,CAgBe;MACnB,CAAA,EAAA,MAAA;YACH,CAAA,EAAA;IACS,IAAA,EAAA,MAAA;IAHqB,OAAA,EAAA,MAAA;EAAkB,CAAA;EAMzC,KAAA,CAAA,EAnBP,aAmBgB,EAEf;EAGM,SAAA,CAAA,EAvBH,iBAuBoB,EAGvB;EAIM,OAAA,CAAA,EA7BL,eA+BC,EAAA;AAGb;AAAuC,UA/BtB,gBAAA,CA+BsB;SAMxB,EAAA,MAAA;OAHH,CAAA,EAhCF,OAgCE,EAAA;WAKK,CAAA,EApCH,WAoCG,EAAA;EAAW,MAAA,CAAA,EAnCjB,cAmCiB,EAAA;EAGX,OAAA,CAAA,EAAA,MAAY;AAK7B;AAA6B,UAvCZ,cAAA,SAAuB,kBAuCX,CAAA;UAGjB,CAAA,EAzCC,gBAyCD,EAAA;OACC,CAAA,EAzCH,gBAyCG,EAAA;gBAEL,CAAA,EA1CW,gBA0CX,EAAA;;AAEC,UAzCQ,SAAA,CAyCR;MACE,CAAA,EAAA,MAAA;EAAY,MAAA,CAAA,EAxCZ,cAwCY,EAAA;AAQvB;AAKsB,UAlDL,iBAAA,CAkDoB;EAAA,KAAA,EAAA;IAC3B,OAAA,CAAA,EAAA,MAAA;IAEW,QAAA,CAAA,EAAA,MAAA;IAAlB,QAAA,CAAA,EAAA,MAAA;EAAO,CAAA;;WAlDC;;;UAIM,UAAA;;aAEJ;;UAGI,sBAAA;;;YAGL;;;eAGG;;iBAEE;;UAGA,YAAA;;gBAED;;UAGC,YAAA;;;YAGL;aACC;;QAEL;QACA;SACC;WACE;;;;;;;;;;;iBAQK,UAAA,sBAAgC;iBAK1B,eAAA,SACZ;;;IAEP;UAAkB"}
|
package/dist/fixture-loader.cjs
CHANGED
|
@@ -25,6 +25,7 @@ function entryToFixture(entry) {
|
|
|
25
25
|
return {
|
|
26
26
|
match: {
|
|
27
27
|
userMessage: entry.match.userMessage,
|
|
28
|
+
systemMessage: entry.match.systemMessage,
|
|
28
29
|
inputText: entry.match.inputText,
|
|
29
30
|
toolCallId: entry.match.toolCallId,
|
|
30
31
|
toolName: entry.match.toolName,
|
|
@@ -399,6 +400,11 @@ function validateFixtures(fixtures) {
|
|
|
399
400
|
fixtureIndex: i,
|
|
400
401
|
message: `match.hasToolResult must be a boolean, got ${typeof f.match.hasToolResult}`
|
|
401
402
|
});
|
|
403
|
+
if (f.match.systemMessage !== void 0 && typeof f.match.systemMessage !== "string") results.push({
|
|
404
|
+
severity: "error",
|
|
405
|
+
fixtureIndex: i,
|
|
406
|
+
message: `match.systemMessage must be a string, got ${typeof f.match.systemMessage}`
|
|
407
|
+
});
|
|
402
408
|
const um = f.match.userMessage;
|
|
403
409
|
if (typeof um === "string" && um) {
|
|
404
410
|
const dedupKey = `${um}|${f.match.turnIndex}|${f.match.hasToolResult}|${f.match.sequenceIndex}`;
|
|
@@ -411,7 +417,7 @@ function validateFixtures(fixtures) {
|
|
|
411
417
|
else seenUserMessages.set(dedupKey, i);
|
|
412
418
|
}
|
|
413
419
|
const match = f.match;
|
|
414
|
-
if (!(match.endpoint !== void 0 || match.userMessage !== void 0 || match.inputText !== void 0 || match.responseFormat !== void 0 || match.toolCallId !== void 0 || match.toolName !== void 0 || match.model !== void 0 || match.predicate !== void 0 || match.turnIndex !== void 0 || match.hasToolResult !== void 0) && i < fixtures.length - 1) results.push({
|
|
420
|
+
if (!(match.endpoint !== void 0 || match.userMessage !== void 0 || match.systemMessage !== void 0 || match.inputText !== void 0 || match.responseFormat !== void 0 || match.toolCallId !== void 0 || match.toolName !== void 0 || match.model !== void 0 || match.predicate !== void 0 || match.turnIndex !== void 0 || match.hasToolResult !== void 0) && i < fixtures.length - 1) results.push({
|
|
415
421
|
severity: "warning",
|
|
416
422
|
fixtureIndex: i,
|
|
417
423
|
message: `empty match acts as catch-all but is not the last fixture — shadows fixtures ${i + 1}+`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fixture-loader.cjs","names":["isContentWithToolCallsResponse","isTextResponse","isToolCallResponse","isErrorResponse","isEmbeddingResponse","isImageResponse","isAudioResponse","isTranscriptionResponse","isVideoResponse","isJSONResponse"],"sources":["../src/fixture-loader.ts"],"sourcesContent":["import { readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type {\n Fixture,\n FixtureFile,\n FixtureFileEntry,\n FixtureFileResponse,\n FixtureResponse,\n ResponseOverrides,\n} from \"./types.js\";\nimport {\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n isEmbeddingResponse,\n isImageResponse,\n isAudioResponse,\n isTranscriptionResponse,\n isVideoResponse,\n isJSONResponse,\n} from \"./helpers.js\";\nimport type { Logger } from \"./logger.js\";\n\n/**\n * Auto-stringify object-valued `content` and `toolCalls[].arguments` fields.\n * This lets fixture authors write plain JSON objects instead of escaped strings.\n * All other fields (including ResponseOverrides) pass through unmodified.\n */\nexport function normalizeResponse(raw: FixtureFileResponse): FixtureResponse {\n // Shallow-clone so we don't mutate the parsed JSON input.\n const response = { ...raw } as Record<string, unknown>;\n\n // Auto-stringify object content (e.g. structured output)\n if (typeof response.content === \"object\" && response.content !== null) {\n response.content = JSON.stringify(response.content);\n }\n\n // Auto-stringify object arguments in toolCalls\n if (Array.isArray(response.toolCalls)) {\n response.toolCalls = (response.toolCalls as Array<Record<string, unknown>>).map((tc) => {\n if (typeof tc.arguments === \"object\" && tc.arguments !== null) {\n return { ...tc, arguments: JSON.stringify(tc.arguments) };\n }\n return tc;\n });\n }\n\n return response as unknown as FixtureResponse;\n}\n\nexport function entryToFixture(entry: FixtureFileEntry): Fixture {\n return {\n match: {\n userMessage: entry.match.userMessage,\n inputText: entry.match.inputText,\n toolCallId: entry.match.toolCallId,\n toolName: entry.match.toolName,\n model: entry.match.model,\n responseFormat: entry.match.responseFormat,\n endpoint: entry.match.endpoint,\n ...(entry.match.sequenceIndex !== undefined && { sequenceIndex: entry.match.sequenceIndex }),\n ...(entry.match.turnIndex !== undefined && {\n turnIndex: entry.match.turnIndex,\n }),\n ...(entry.match.hasToolResult !== undefined && {\n hasToolResult: entry.match.hasToolResult,\n }),\n },\n response: normalizeResponse(entry.response),\n ...(entry.latency !== undefined && { latency: entry.latency }),\n ...(entry.chunkSize !== undefined && { chunkSize: entry.chunkSize }),\n ...(entry.truncateAfterChunks !== undefined && {\n truncateAfterChunks: entry.truncateAfterChunks,\n }),\n ...(entry.disconnectAfterMs !== undefined && { disconnectAfterMs: entry.disconnectAfterMs }),\n ...(entry.streamingProfile !== undefined && { streamingProfile: entry.streamingProfile }),\n ...(entry.chaos !== undefined && { chaos: entry.chaos }),\n };\n}\n\n// Logging helper — uses logger if provided, falls back to console.warn.\nfunction warn(logger: Logger | undefined, msg: string, ...rest: unknown[]): void {\n if (logger) {\n logger.warn(msg, ...rest);\n } else {\n console.warn(`[fixture-loader] ${msg}`, ...rest);\n }\n}\n\nexport function loadFixtureFile(filePath: string, logger?: Logger): Fixture[] {\n let raw: string;\n try {\n raw = readFileSync(filePath, \"utf-8\");\n } catch (err) {\n warn(logger, `Could not read file ${filePath}:`, err);\n return [];\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n warn(logger, `Invalid JSON in ${filePath}:`, err);\n return [];\n }\n\n if (\n typeof parsed !== \"object\" ||\n parsed === null ||\n !Array.isArray((parsed as FixtureFile).fixtures)\n ) {\n warn(logger, `Missing or invalid \"fixtures\" array in ${filePath}`);\n return [];\n }\n\n return (parsed as FixtureFile).fixtures.map(entryToFixture);\n}\n\nexport function loadFixturesFromDir(dirPath: string, logger?: Logger): Fixture[] {\n let entries: string[];\n try {\n entries = readdirSync(dirPath);\n } catch (err) {\n warn(logger, `Could not read directory ${dirPath}:`, err);\n return [];\n }\n\n const jsonFiles: string[] = [];\n const subdirs: string[] = [];\n for (const name of entries) {\n const fullPath = join(dirPath, name);\n try {\n if (statSync(fullPath).isDirectory()) {\n subdirs.push(name);\n continue;\n }\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") {\n warn(logger, `Could not stat ${fullPath}:`, err);\n }\n continue;\n }\n if (name.endsWith(\".json\")) {\n jsonFiles.push(name);\n }\n }\n jsonFiles.sort();\n\n const fixtures: Fixture[] = [];\n for (const name of jsonFiles) {\n const filePath = join(dirPath, name);\n fixtures.push(...loadFixtureFile(filePath, logger));\n }\n\n // Recurse one level into subdirectories to support snapshot-style layouts\n // where the recorder writes to <fixturePath>/<testId>/<provider>.json.\n subdirs.sort();\n for (const sub of subdirs) {\n const subPath = join(dirPath, sub);\n let subEntries: string[];\n try {\n subEntries = readdirSync(subPath);\n } catch (err) {\n warn(logger, `Could not read subdirectory ${subPath}:`, err);\n continue;\n }\n const subJsonFiles: string[] = [];\n for (const subName of subEntries) {\n const subFullPath = join(subPath, subName);\n try {\n if (statSync(subFullPath).isDirectory()) {\n // Only one level of recursion — skip deeper nesting\n continue;\n }\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") {\n warn(logger, `Could not stat ${subFullPath}:`, err);\n }\n continue;\n }\n if (subName.endsWith(\".json\")) {\n subJsonFiles.push(subName);\n }\n }\n subJsonFiles.sort();\n for (const subName of subJsonFiles) {\n const filePath = join(subPath, subName);\n fixtures.push(...loadFixtureFile(filePath, logger));\n }\n }\n\n return fixtures;\n}\n\n// ---------------------------------------------------------------------------\n// Fixture validation\n// ---------------------------------------------------------------------------\n\nexport interface ValidationResult {\n severity: \"error\" | \"warning\";\n fixtureIndex: number;\n message: string;\n}\n\nfunction validateReasoning(\n response: { reasoning?: unknown },\n fixtureIndex: number,\n results: ValidationResult[],\n): void {\n if (response.reasoning !== undefined) {\n if (typeof response.reasoning !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex,\n message: \"reasoning must be a string\",\n });\n } else if (response.reasoning === \"\") {\n results.push({\n severity: \"warning\",\n fixtureIndex,\n message: \"reasoning is empty string — no reasoning events will be emitted\",\n });\n }\n }\n}\n\nfunction validateWebSearches(\n response: { webSearches?: unknown },\n fixtureIndex: number,\n results: ValidationResult[],\n): void {\n if (response.webSearches !== undefined) {\n if (!Array.isArray(response.webSearches)) {\n results.push({\n severity: \"error\",\n fixtureIndex,\n message: \"webSearches must be an array of strings\",\n });\n } else if (response.webSearches.length === 0) {\n results.push({\n severity: \"warning\",\n fixtureIndex,\n message: \"webSearches is empty array — no web search events will be emitted\",\n });\n } else {\n for (let j = 0; j < response.webSearches.length; j++) {\n if (typeof response.webSearches[j] !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex,\n message: `webSearches[${j}] is not a string`,\n });\n break;\n }\n if (response.webSearches[j] === \"\") {\n results.push({\n severity: \"warning\",\n fixtureIndex,\n message: `webSearches[${j}] is empty string`,\n });\n }\n }\n }\n }\n}\n\nexport function validateFixtures(fixtures: Fixture[]): ValidationResult[] {\n const results: ValidationResult[] = [];\n\n const seenUserMessages = new Map<string, number>();\n\n for (let i = 0; i < fixtures.length; i++) {\n const f = fixtures[i];\n const response = f.response;\n\n // Skip response-shape validation for function responses — they are\n // evaluated at runtime so we cannot statically inspect them.\n if (typeof response === \"function\") {\n // Still validate match fields and numeric options below.\n } else {\n // --- Error checks ---\n\n // Response type recognition\n // Note: isContentWithToolCallsResponse must be checked before isTextResponse\n // and isToolCallResponse since it is a structural superset of both.\n if (\n !isContentWithToolCallsResponse(response) &&\n !isTextResponse(response) &&\n !isToolCallResponse(response) &&\n !isErrorResponse(response) &&\n !isEmbeddingResponse(response) &&\n !isImageResponse(response) &&\n !isAudioResponse(response) &&\n !isTranscriptionResponse(response) &&\n !isVideoResponse(response) &&\n !isJSONResponse(response)\n ) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message:\n \"response is not a recognized type (must have content, toolCalls, error, embedding, image, audio, transcription, video, or json)\",\n });\n }\n\n // Text response checks\n if (isTextResponse(response)) {\n if (response.content === \"\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"content is empty string\",\n });\n }\n validateReasoning(response, i, results);\n validateWebSearches(response, i, results);\n }\n\n // ContentWithToolCalls response checks\n if (isContentWithToolCallsResponse(response)) {\n if (response.content === \"\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"content is empty string\",\n });\n }\n if (response.toolCalls.length === 0) {\n results.push({\n severity: \"warning\",\n fixtureIndex: i,\n message: \"toolCalls array is empty — fixture will never produce tool calls\",\n });\n }\n for (let j = 0; j < response.toolCalls.length; j++) {\n const tc = response.toolCalls[j];\n if (!tc.name) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `toolCalls[${j}].name is empty`,\n });\n }\n try {\n JSON.parse(tc.arguments);\n } catch {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `toolCalls[${j}].arguments is not valid JSON: ${tc.arguments}`,\n });\n }\n }\n validateReasoning(response, i, results);\n validateWebSearches(response, i, results);\n }\n\n // Tool call response checks\n if (isToolCallResponse(response)) {\n if (response.toolCalls.length === 0) {\n results.push({\n severity: \"warning\",\n fixtureIndex: i,\n message: \"toolCalls array is empty — fixture will never produce tool calls\",\n });\n }\n for (let j = 0; j < response.toolCalls.length; j++) {\n const tc = response.toolCalls[j];\n if (!tc.name) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `toolCalls[${j}].name is empty`,\n });\n }\n try {\n JSON.parse(tc.arguments);\n } catch {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `toolCalls[${j}].arguments is not valid JSON: ${tc.arguments}`,\n });\n }\n }\n }\n\n // Error response checks\n if (isErrorResponse(response)) {\n if (!response.error.message) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"error.message is empty\",\n });\n }\n if (response.status !== undefined && (response.status < 100 || response.status > 599)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `error status ${response.status} is not a valid HTTP status code`,\n });\n }\n }\n\n // Embedding response checks\n if (isEmbeddingResponse(response)) {\n if (response.embedding.length === 0) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"embedding array is empty\",\n });\n }\n for (let j = 0; j < response.embedding.length; j++) {\n if (typeof response.embedding[j] !== \"number\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `embedding[${j}] is not a number`,\n });\n break; // one error is enough\n }\n }\n }\n\n // Audio response checks — validate object-form audio\n if (isAudioResponse(response) && typeof response.audio === \"object\") {\n const audioObj = response.audio;\n if (typeof audioObj.b64Json !== \"string\" || audioObj.b64Json === \"\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"audio.b64Json must be a non-empty string\",\n });\n }\n if (audioObj.contentType !== undefined && typeof audioObj.contentType !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `audio.contentType must be a string, got ${typeof audioObj.contentType}`,\n });\n }\n }\n\n // Validate ResponseOverrides fields\n if (\n isTextResponse(response) ||\n isToolCallResponse(response) ||\n isContentWithToolCallsResponse(response)\n ) {\n const r = response as ResponseOverrides;\n if (r.id !== undefined && typeof r.id !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"id\" must be a string, got ${typeof r.id}`,\n });\n }\n if (r.created !== undefined && (typeof r.created !== \"number\" || r.created < 0)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"created\" must be a non-negative number`,\n });\n }\n if (r.model !== undefined && typeof r.model !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"model\" must be a string, got ${typeof r.model}`,\n });\n }\n if (r.finishReason !== undefined && typeof r.finishReason !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"finishReason\" must be a string, got ${typeof r.finishReason}`,\n });\n }\n if (r.role !== undefined && typeof r.role !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"role\" must be a string, got ${typeof r.role}`,\n });\n }\n if (r.systemFingerprint !== undefined && typeof r.systemFingerprint !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"systemFingerprint\" must be a string, got ${typeof r.systemFingerprint}`,\n });\n }\n if (r.usage !== undefined) {\n if (typeof r.usage !== \"object\" || r.usage === null || Array.isArray(r.usage)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"usage\" must be an object`,\n });\n } else {\n // Check all known usage fields are numbers if present\n for (const key of Object.keys(r.usage)) {\n const val = (r.usage as Record<string, unknown>)[key];\n if (val !== undefined && typeof val !== \"number\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"usage.${key}\" must be a number, got ${typeof val}`,\n });\n }\n }\n }\n }\n }\n } // end: skip response-shape validation for function responses\n\n // Numeric sanity checks\n if (f.latency !== undefined && f.latency < 0) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"latency must be >= 0\",\n });\n }\n if (f.chunkSize !== undefined && f.chunkSize < 1) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"chunkSize must be >= 1\",\n });\n }\n if (f.truncateAfterChunks !== undefined && f.truncateAfterChunks < 1) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"truncateAfterChunks must be >= 1\",\n });\n }\n if (f.disconnectAfterMs !== undefined && f.disconnectAfterMs < 0) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"disconnectAfterMs must be >= 0\",\n });\n }\n if (f.streamingProfile !== undefined) {\n const sp = f.streamingProfile;\n if (sp.ttft !== undefined && sp.ttft < 0) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"streamingProfile.ttft must be >= 0\",\n });\n }\n if (sp.tps !== undefined && sp.tps <= 0) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"streamingProfile.tps must be > 0\",\n });\n }\n if (sp.jitter !== undefined && (sp.jitter < 0 || sp.jitter > 1)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"streamingProfile.jitter must be between 0 and 1\",\n });\n }\n }\n if (f.chaos !== undefined) {\n const ch = f.chaos;\n if (ch.dropRate !== undefined && (ch.dropRate < 0 || ch.dropRate > 1)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"chaos.dropRate must be between 0 and 1\",\n });\n }\n if (ch.malformedRate !== undefined && (ch.malformedRate < 0 || ch.malformedRate > 1)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"chaos.malformedRate must be between 0 and 1\",\n });\n }\n if (ch.disconnectRate !== undefined && (ch.disconnectRate < 0 || ch.disconnectRate > 1)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"chaos.disconnectRate must be between 0 and 1\",\n });\n }\n }\n\n // Match field type checks\n if (f.match.turnIndex !== undefined) {\n if (\n typeof f.match.turnIndex !== \"number\" ||\n f.match.turnIndex < 0 ||\n !Number.isInteger(f.match.turnIndex)\n ) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"match.turnIndex must be a non-negative integer\",\n });\n }\n }\n if (f.match.hasToolResult !== undefined && typeof f.match.hasToolResult !== \"boolean\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `match.hasToolResult must be a boolean, got ${typeof f.match.hasToolResult}`,\n });\n }\n\n // --- Warning checks ---\n\n // Duplicate userMessage shadowing — include turnIndex, hasToolResult, and\n // sequenceIndex in the dedup key so that fixtures which share a userMessage\n // but differ on those fields are NOT considered duplicates.\n const um = f.match.userMessage;\n if (typeof um === \"string\" && um) {\n const dedupKey = `${um}|${f.match.turnIndex}|${f.match.hasToolResult}|${f.match.sequenceIndex}`;\n const prev = seenUserMessages.get(dedupKey);\n if (prev !== undefined) {\n results.push({\n severity: \"warning\",\n fixtureIndex: i,\n message: `duplicate userMessage '${um}' — shadows fixture ${prev}`,\n });\n } else {\n seenUserMessages.set(dedupKey, i);\n }\n }\n\n // Catch-all not in last position\n const match = f.match;\n const hasDiscriminator =\n match.endpoint !== undefined ||\n match.userMessage !== undefined ||\n match.inputText !== undefined ||\n match.responseFormat !== undefined ||\n match.toolCallId !== undefined ||\n match.toolName !== undefined ||\n match.model !== undefined ||\n match.predicate !== undefined ||\n match.turnIndex !== undefined ||\n match.hasToolResult !== undefined;\n\n if (!hasDiscriminator && i < fixtures.length - 1) {\n results.push({\n severity: \"warning\",\n fixtureIndex: i,\n message: `empty match acts as catch-all but is not the last fixture — shadows fixtures ${i + 1}+`,\n });\n }\n }\n\n return results;\n}\n"],"mappings":";;;;;;;;;;;AA6BA,SAAgB,kBAAkB,KAA2C;CAE3E,MAAM,WAAW,EAAE,GAAG,KAAK;AAG3B,KAAI,OAAO,SAAS,YAAY,YAAY,SAAS,YAAY,KAC/D,UAAS,UAAU,KAAK,UAAU,SAAS,QAAQ;AAIrD,KAAI,MAAM,QAAQ,SAAS,UAAU,CACnC,UAAS,YAAa,SAAS,UAA6C,KAAK,OAAO;AACtF,MAAI,OAAO,GAAG,cAAc,YAAY,GAAG,cAAc,KACvD,QAAO;GAAE,GAAG;GAAI,WAAW,KAAK,UAAU,GAAG,UAAU;GAAE;AAE3D,SAAO;GACP;AAGJ,QAAO;;AAGT,SAAgB,eAAe,OAAkC;AAC/D,QAAO;EACL,OAAO;GACL,aAAa,MAAM,MAAM;GACzB,WAAW,MAAM,MAAM;GACvB,YAAY,MAAM,MAAM;GACxB,UAAU,MAAM,MAAM;GACtB,OAAO,MAAM,MAAM;GACnB,gBAAgB,MAAM,MAAM;GAC5B,UAAU,MAAM,MAAM;GACtB,GAAI,MAAM,MAAM,kBAAkB,UAAa,EAAE,eAAe,MAAM,MAAM,eAAe;GAC3F,GAAI,MAAM,MAAM,cAAc,UAAa,EACzC,WAAW,MAAM,MAAM,WACxB;GACD,GAAI,MAAM,MAAM,kBAAkB,UAAa,EAC7C,eAAe,MAAM,MAAM,eAC5B;GACF;EACD,UAAU,kBAAkB,MAAM,SAAS;EAC3C,GAAI,MAAM,YAAY,UAAa,EAAE,SAAS,MAAM,SAAS;EAC7D,GAAI,MAAM,cAAc,UAAa,EAAE,WAAW,MAAM,WAAW;EACnE,GAAI,MAAM,wBAAwB,UAAa,EAC7C,qBAAqB,MAAM,qBAC5B;EACD,GAAI,MAAM,sBAAsB,UAAa,EAAE,mBAAmB,MAAM,mBAAmB;EAC3F,GAAI,MAAM,qBAAqB,UAAa,EAAE,kBAAkB,MAAM,kBAAkB;EACxF,GAAI,MAAM,UAAU,UAAa,EAAE,OAAO,MAAM,OAAO;EACxD;;AAIH,SAAS,KAAK,QAA4B,KAAa,GAAG,MAAuB;AAC/E,KAAI,OACF,QAAO,KAAK,KAAK,GAAG,KAAK;KAEzB,SAAQ,KAAK,oBAAoB,OAAO,GAAG,KAAK;;AAIpD,SAAgB,gBAAgB,UAAkB,QAA4B;CAC5E,IAAI;AACJ,KAAI;AACF,kCAAmB,UAAU,QAAQ;UAC9B,KAAK;AACZ,OAAK,QAAQ,uBAAuB,SAAS,IAAI,IAAI;AACrD,SAAO,EAAE;;CAGX,IAAI;AACJ,KAAI;AACF,WAAS,KAAK,MAAM,IAAI;UACjB,KAAK;AACZ,OAAK,QAAQ,mBAAmB,SAAS,IAAI,IAAI;AACjD,SAAO,EAAE;;AAGX,KACE,OAAO,WAAW,YAClB,WAAW,QACX,CAAC,MAAM,QAAS,OAAuB,SAAS,EAChD;AACA,OAAK,QAAQ,0CAA0C,WAAW;AAClE,SAAO,EAAE;;AAGX,QAAQ,OAAuB,SAAS,IAAI,eAAe;;AAG7D,SAAgB,oBAAoB,SAAiB,QAA4B;CAC/E,IAAI;AACJ,KAAI;AACF,qCAAsB,QAAQ;UACvB,KAAK;AACZ,OAAK,QAAQ,4BAA4B,QAAQ,IAAI,IAAI;AACzD,SAAO,EAAE;;CAGX,MAAM,YAAsB,EAAE;CAC9B,MAAM,UAAoB,EAAE;AAC5B,MAAK,MAAM,QAAQ,SAAS;EAC1B,MAAM,+BAAgB,SAAS,KAAK;AACpC,MAAI;AACF,6BAAa,SAAS,CAAC,aAAa,EAAE;AACpC,YAAQ,KAAK,KAAK;AAClB;;WAEK,KAAK;AAEZ,OADc,IAA8B,SAC/B,SACX,MAAK,QAAQ,kBAAkB,SAAS,IAAI,IAAI;AAElD;;AAEF,MAAI,KAAK,SAAS,QAAQ,CACxB,WAAU,KAAK,KAAK;;AAGxB,WAAU,MAAM;CAEhB,MAAM,WAAsB,EAAE;AAC9B,MAAK,MAAM,QAAQ,WAAW;EAC5B,MAAM,+BAAgB,SAAS,KAAK;AACpC,WAAS,KAAK,GAAG,gBAAgB,UAAU,OAAO,CAAC;;AAKrD,SAAQ,MAAM;AACd,MAAK,MAAM,OAAO,SAAS;EACzB,MAAM,8BAAe,SAAS,IAAI;EAClC,IAAI;AACJ,MAAI;AACF,yCAAyB,QAAQ;WAC1B,KAAK;AACZ,QAAK,QAAQ,+BAA+B,QAAQ,IAAI,IAAI;AAC5D;;EAEF,MAAM,eAAyB,EAAE;AACjC,OAAK,MAAM,WAAW,YAAY;GAChC,MAAM,kCAAmB,SAAS,QAAQ;AAC1C,OAAI;AACF,8BAAa,YAAY,CAAC,aAAa,CAErC;YAEK,KAAK;AAEZ,QADc,IAA8B,SAC/B,SACX,MAAK,QAAQ,kBAAkB,YAAY,IAAI,IAAI;AAErD;;AAEF,OAAI,QAAQ,SAAS,QAAQ,CAC3B,cAAa,KAAK,QAAQ;;AAG9B,eAAa,MAAM;AACnB,OAAK,MAAM,WAAW,cAAc;GAClC,MAAM,+BAAgB,SAAS,QAAQ;AACvC,YAAS,KAAK,GAAG,gBAAgB,UAAU,OAAO,CAAC;;;AAIvD,QAAO;;AAaT,SAAS,kBACP,UACA,cACA,SACM;AACN,KAAI,SAAS,cAAc,QACzB;MAAI,OAAO,SAAS,cAAc,SAChC,SAAQ,KAAK;GACX,UAAU;GACV;GACA,SAAS;GACV,CAAC;WACO,SAAS,cAAc,GAChC,SAAQ,KAAK;GACX,UAAU;GACV;GACA,SAAS;GACV,CAAC;;;AAKR,SAAS,oBACP,UACA,cACA,SACM;AACN,KAAI,SAAS,gBAAgB,OAC3B,KAAI,CAAC,MAAM,QAAQ,SAAS,YAAY,CACtC,SAAQ,KAAK;EACX,UAAU;EACV;EACA,SAAS;EACV,CAAC;UACO,SAAS,YAAY,WAAW,EACzC,SAAQ,KAAK;EACX,UAAU;EACV;EACA,SAAS;EACV,CAAC;KAEF,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,YAAY,QAAQ,KAAK;AACpD,MAAI,OAAO,SAAS,YAAY,OAAO,UAAU;AAC/C,WAAQ,KAAK;IACX,UAAU;IACV;IACA,SAAS,eAAe,EAAE;IAC3B,CAAC;AACF;;AAEF,MAAI,SAAS,YAAY,OAAO,GAC9B,SAAQ,KAAK;GACX,UAAU;GACV;GACA,SAAS,eAAe,EAAE;GAC3B,CAAC;;;AAOZ,SAAgB,iBAAiB,UAAyC;CACxE,MAAM,UAA8B,EAAE;CAEtC,MAAM,mCAAmB,IAAI,KAAqB;AAElD,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;EACxC,MAAM,IAAI,SAAS;EACnB,MAAM,WAAW,EAAE;AAInB,MAAI,OAAO,aAAa,YAAY,QAE7B;AAML,OACE,CAACA,+CAA+B,SAAS,IACzC,CAACC,+BAAe,SAAS,IACzB,CAACC,mCAAmB,SAAS,IAC7B,CAACC,gCAAgB,SAAS,IAC1B,CAACC,oCAAoB,SAAS,IAC9B,CAACC,gCAAgB,SAAS,IAC1B,CAACC,gCAAgB,SAAS,IAC1B,CAACC,wCAAwB,SAAS,IAClC,CAACC,gCAAgB,SAAS,IAC1B,CAACC,+BAAe,SAAS,CAEzB,SAAQ,KAAK;IACX,UAAU;IACV,cAAc;IACd,SACE;IACH,CAAC;AAIJ,OAAIR,+BAAe,SAAS,EAAE;AAC5B,QAAI,SAAS,YAAY,GACvB,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS;KACV,CAAC;AAEJ,sBAAkB,UAAU,GAAG,QAAQ;AACvC,wBAAoB,UAAU,GAAG,QAAQ;;AAI3C,OAAID,+CAA+B,SAAS,EAAE;AAC5C,QAAI,SAAS,YAAY,GACvB,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS;KACV,CAAC;AAEJ,QAAI,SAAS,UAAU,WAAW,EAChC,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS;KACV,CAAC;AAEJ,SAAK,IAAI,IAAI,GAAG,IAAI,SAAS,UAAU,QAAQ,KAAK;KAClD,MAAM,KAAK,SAAS,UAAU;AAC9B,SAAI,CAAC,GAAG,KACN,SAAQ,KAAK;MACX,UAAU;MACV,cAAc;MACd,SAAS,aAAa,EAAE;MACzB,CAAC;AAEJ,SAAI;AACF,WAAK,MAAM,GAAG,UAAU;aAClB;AACN,cAAQ,KAAK;OACX,UAAU;OACV,cAAc;OACd,SAAS,aAAa,EAAE,iCAAiC,GAAG;OAC7D,CAAC;;;AAGN,sBAAkB,UAAU,GAAG,QAAQ;AACvC,wBAAoB,UAAU,GAAG,QAAQ;;AAI3C,OAAIE,mCAAmB,SAAS,EAAE;AAChC,QAAI,SAAS,UAAU,WAAW,EAChC,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS;KACV,CAAC;AAEJ,SAAK,IAAI,IAAI,GAAG,IAAI,SAAS,UAAU,QAAQ,KAAK;KAClD,MAAM,KAAK,SAAS,UAAU;AAC9B,SAAI,CAAC,GAAG,KACN,SAAQ,KAAK;MACX,UAAU;MACV,cAAc;MACd,SAAS,aAAa,EAAE;MACzB,CAAC;AAEJ,SAAI;AACF,WAAK,MAAM,GAAG,UAAU;aAClB;AACN,cAAQ,KAAK;OACX,UAAU;OACV,cAAc;OACd,SAAS,aAAa,EAAE,iCAAiC,GAAG;OAC7D,CAAC;;;;AAMR,OAAIC,gCAAgB,SAAS,EAAE;AAC7B,QAAI,CAAC,SAAS,MAAM,QAClB,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS;KACV,CAAC;AAEJ,QAAI,SAAS,WAAW,WAAc,SAAS,SAAS,OAAO,SAAS,SAAS,KAC/E,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS,gBAAgB,SAAS,OAAO;KAC1C,CAAC;;AAKN,OAAIC,oCAAoB,SAAS,EAAE;AACjC,QAAI,SAAS,UAAU,WAAW,EAChC,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS;KACV,CAAC;AAEJ,SAAK,IAAI,IAAI,GAAG,IAAI,SAAS,UAAU,QAAQ,IAC7C,KAAI,OAAO,SAAS,UAAU,OAAO,UAAU;AAC7C,aAAQ,KAAK;MACX,UAAU;MACV,cAAc;MACd,SAAS,aAAa,EAAE;MACzB,CAAC;AACF;;;AAMN,OAAIE,gCAAgB,SAAS,IAAI,OAAO,SAAS,UAAU,UAAU;IACnE,MAAM,WAAW,SAAS;AAC1B,QAAI,OAAO,SAAS,YAAY,YAAY,SAAS,YAAY,GAC/D,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS;KACV,CAAC;AAEJ,QAAI,SAAS,gBAAgB,UAAa,OAAO,SAAS,gBAAgB,SACxE,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS,2CAA2C,OAAO,SAAS;KACrE,CAAC;;AAKN,OACEL,+BAAe,SAAS,IACxBC,mCAAmB,SAAS,IAC5BF,+CAA+B,SAAS,EACxC;IACA,MAAM,IAAI;AACV,QAAI,EAAE,OAAO,UAAa,OAAO,EAAE,OAAO,SACxC,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS,uCAAuC,OAAO,EAAE;KAC1D,CAAC;AAEJ,QAAI,EAAE,YAAY,WAAc,OAAO,EAAE,YAAY,YAAY,EAAE,UAAU,GAC3E,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS;KACV,CAAC;AAEJ,QAAI,EAAE,UAAU,UAAa,OAAO,EAAE,UAAU,SAC9C,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS,0CAA0C,OAAO,EAAE;KAC7D,CAAC;AAEJ,QAAI,EAAE,iBAAiB,UAAa,OAAO,EAAE,iBAAiB,SAC5D,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS,iDAAiD,OAAO,EAAE;KACpE,CAAC;AAEJ,QAAI,EAAE,SAAS,UAAa,OAAO,EAAE,SAAS,SAC5C,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS,yCAAyC,OAAO,EAAE;KAC5D,CAAC;AAEJ,QAAI,EAAE,sBAAsB,UAAa,OAAO,EAAE,sBAAsB,SACtE,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS,sDAAsD,OAAO,EAAE;KACzE,CAAC;AAEJ,QAAI,EAAE,UAAU,OACd,KAAI,OAAO,EAAE,UAAU,YAAY,EAAE,UAAU,QAAQ,MAAM,QAAQ,EAAE,MAAM,CAC3E,SAAQ,KAAK;KACX,UAAU;KACV,cAAc;KACd,SAAS;KACV,CAAC;QAGF,MAAK,MAAM,OAAO,OAAO,KAAK,EAAE,MAAM,EAAE;KACtC,MAAM,MAAO,EAAE,MAAkC;AACjD,SAAI,QAAQ,UAAa,OAAO,QAAQ,SACtC,SAAQ,KAAK;MACX,UAAU;MACV,cAAc;MACd,SAAS,mBAAmB,IAAI,0BAA0B,OAAO;MAClE,CAAC;;;;AASd,MAAI,EAAE,YAAY,UAAa,EAAE,UAAU,EACzC,SAAQ,KAAK;GACX,UAAU;GACV,cAAc;GACd,SAAS;GACV,CAAC;AAEJ,MAAI,EAAE,cAAc,UAAa,EAAE,YAAY,EAC7C,SAAQ,KAAK;GACX,UAAU;GACV,cAAc;GACd,SAAS;GACV,CAAC;AAEJ,MAAI,EAAE,wBAAwB,UAAa,EAAE,sBAAsB,EACjE,SAAQ,KAAK;GACX,UAAU;GACV,cAAc;GACd,SAAS;GACV,CAAC;AAEJ,MAAI,EAAE,sBAAsB,UAAa,EAAE,oBAAoB,EAC7D,SAAQ,KAAK;GACX,UAAU;GACV,cAAc;GACd,SAAS;GACV,CAAC;AAEJ,MAAI,EAAE,qBAAqB,QAAW;GACpC,MAAM,KAAK,EAAE;AACb,OAAI,GAAG,SAAS,UAAa,GAAG,OAAO,EACrC,SAAQ,KAAK;IACX,UAAU;IACV,cAAc;IACd,SAAS;IACV,CAAC;AAEJ,OAAI,GAAG,QAAQ,UAAa,GAAG,OAAO,EACpC,SAAQ,KAAK;IACX,UAAU;IACV,cAAc;IACd,SAAS;IACV,CAAC;AAEJ,OAAI,GAAG,WAAW,WAAc,GAAG,SAAS,KAAK,GAAG,SAAS,GAC3D,SAAQ,KAAK;IACX,UAAU;IACV,cAAc;IACd,SAAS;IACV,CAAC;;AAGN,MAAI,EAAE,UAAU,QAAW;GACzB,MAAM,KAAK,EAAE;AACb,OAAI,GAAG,aAAa,WAAc,GAAG,WAAW,KAAK,GAAG,WAAW,GACjE,SAAQ,KAAK;IACX,UAAU;IACV,cAAc;IACd,SAAS;IACV,CAAC;AAEJ,OAAI,GAAG,kBAAkB,WAAc,GAAG,gBAAgB,KAAK,GAAG,gBAAgB,GAChF,SAAQ,KAAK;IACX,UAAU;IACV,cAAc;IACd,SAAS;IACV,CAAC;AAEJ,OAAI,GAAG,mBAAmB,WAAc,GAAG,iBAAiB,KAAK,GAAG,iBAAiB,GACnF,SAAQ,KAAK;IACX,UAAU;IACV,cAAc;IACd,SAAS;IACV,CAAC;;AAKN,MAAI,EAAE,MAAM,cAAc,QACxB;OACE,OAAO,EAAE,MAAM,cAAc,YAC7B,EAAE,MAAM,YAAY,KACpB,CAAC,OAAO,UAAU,EAAE,MAAM,UAAU,CAEpC,SAAQ,KAAK;IACX,UAAU;IACV,cAAc;IACd,SAAS;IACV,CAAC;;AAGN,MAAI,EAAE,MAAM,kBAAkB,UAAa,OAAO,EAAE,MAAM,kBAAkB,UAC1E,SAAQ,KAAK;GACX,UAAU;GACV,cAAc;GACd,SAAS,8CAA8C,OAAO,EAAE,MAAM;GACvE,CAAC;EAQJ,MAAM,KAAK,EAAE,MAAM;AACnB,MAAI,OAAO,OAAO,YAAY,IAAI;GAChC,MAAM,WAAW,GAAG,GAAG,GAAG,EAAE,MAAM,UAAU,GAAG,EAAE,MAAM,cAAc,GAAG,EAAE,MAAM;GAChF,MAAM,OAAO,iBAAiB,IAAI,SAAS;AAC3C,OAAI,SAAS,OACX,SAAQ,KAAK;IACX,UAAU;IACV,cAAc;IACd,SAAS,0BAA0B,GAAG,sBAAsB;IAC7D,CAAC;OAEF,kBAAiB,IAAI,UAAU,EAAE;;EAKrC,MAAM,QAAQ,EAAE;AAahB,MAAI,EAXF,MAAM,aAAa,UACnB,MAAM,gBAAgB,UACtB,MAAM,cAAc,UACpB,MAAM,mBAAmB,UACzB,MAAM,eAAe,UACrB,MAAM,aAAa,UACnB,MAAM,UAAU,UAChB,MAAM,cAAc,UACpB,MAAM,cAAc,UACpB,MAAM,kBAAkB,WAED,IAAI,SAAS,SAAS,EAC7C,SAAQ,KAAK;GACX,UAAU;GACV,cAAc;GACd,SAAS,gFAAgF,IAAI,EAAE;GAChG,CAAC;;AAIN,QAAO"}
|
|
1
|
+
{"version":3,"file":"fixture-loader.cjs","names":["isContentWithToolCallsResponse","isTextResponse","isToolCallResponse","isErrorResponse","isEmbeddingResponse","isImageResponse","isAudioResponse","isTranscriptionResponse","isVideoResponse","isJSONResponse"],"sources":["../src/fixture-loader.ts"],"sourcesContent":["import { readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type {\n Fixture,\n FixtureFile,\n FixtureFileEntry,\n FixtureFileResponse,\n FixtureResponse,\n ResponseOverrides,\n} from \"./types.js\";\nimport {\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n isEmbeddingResponse,\n isImageResponse,\n isAudioResponse,\n isTranscriptionResponse,\n isVideoResponse,\n isJSONResponse,\n} from \"./helpers.js\";\nimport type { Logger } from \"./logger.js\";\n\n/**\n * Auto-stringify object-valued `content` and `toolCalls[].arguments` fields.\n * This lets fixture authors write plain JSON objects instead of escaped strings.\n * All other fields (including ResponseOverrides) pass through unmodified.\n */\nexport function normalizeResponse(raw: FixtureFileResponse): FixtureResponse {\n // Shallow-clone so we don't mutate the parsed JSON input.\n const response = { ...raw } as Record<string, unknown>;\n\n // Auto-stringify object content (e.g. structured output)\n if (typeof response.content === \"object\" && response.content !== null) {\n response.content = JSON.stringify(response.content);\n }\n\n // Auto-stringify object arguments in toolCalls\n if (Array.isArray(response.toolCalls)) {\n response.toolCalls = (response.toolCalls as Array<Record<string, unknown>>).map((tc) => {\n if (typeof tc.arguments === \"object\" && tc.arguments !== null) {\n return { ...tc, arguments: JSON.stringify(tc.arguments) };\n }\n return tc;\n });\n }\n\n return response as unknown as FixtureResponse;\n}\n\nexport function entryToFixture(entry: FixtureFileEntry): Fixture {\n return {\n match: {\n userMessage: entry.match.userMessage,\n systemMessage: entry.match.systemMessage,\n inputText: entry.match.inputText,\n toolCallId: entry.match.toolCallId,\n toolName: entry.match.toolName,\n model: entry.match.model,\n responseFormat: entry.match.responseFormat,\n endpoint: entry.match.endpoint,\n ...(entry.match.sequenceIndex !== undefined && { sequenceIndex: entry.match.sequenceIndex }),\n ...(entry.match.turnIndex !== undefined && {\n turnIndex: entry.match.turnIndex,\n }),\n ...(entry.match.hasToolResult !== undefined && {\n hasToolResult: entry.match.hasToolResult,\n }),\n },\n response: normalizeResponse(entry.response),\n ...(entry.latency !== undefined && { latency: entry.latency }),\n ...(entry.chunkSize !== undefined && { chunkSize: entry.chunkSize }),\n ...(entry.truncateAfterChunks !== undefined && {\n truncateAfterChunks: entry.truncateAfterChunks,\n }),\n ...(entry.disconnectAfterMs !== undefined && { disconnectAfterMs: entry.disconnectAfterMs }),\n ...(entry.streamingProfile !== undefined && { streamingProfile: entry.streamingProfile }),\n ...(entry.chaos !== undefined && { chaos: entry.chaos }),\n };\n}\n\n// Logging helper — uses logger if provided, falls back to console.warn.\nfunction warn(logger: Logger | undefined, msg: string, ...rest: unknown[]): void {\n if (logger) {\n logger.warn(msg, ...rest);\n } else {\n console.warn(`[fixture-loader] ${msg}`, ...rest);\n }\n}\n\nexport function loadFixtureFile(filePath: string, logger?: Logger): Fixture[] {\n let raw: string;\n try {\n raw = readFileSync(filePath, \"utf-8\");\n } catch (err) {\n warn(logger, `Could not read file ${filePath}:`, err);\n return [];\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n warn(logger, `Invalid JSON in ${filePath}:`, err);\n return [];\n }\n\n if (\n typeof parsed !== \"object\" ||\n parsed === null ||\n !Array.isArray((parsed as FixtureFile).fixtures)\n ) {\n warn(logger, `Missing or invalid \"fixtures\" array in ${filePath}`);\n return [];\n }\n\n return (parsed as FixtureFile).fixtures.map(entryToFixture);\n}\n\nexport function loadFixturesFromDir(dirPath: string, logger?: Logger): Fixture[] {\n let entries: string[];\n try {\n entries = readdirSync(dirPath);\n } catch (err) {\n warn(logger, `Could not read directory ${dirPath}:`, err);\n return [];\n }\n\n const jsonFiles: string[] = [];\n const subdirs: string[] = [];\n for (const name of entries) {\n const fullPath = join(dirPath, name);\n try {\n if (statSync(fullPath).isDirectory()) {\n subdirs.push(name);\n continue;\n }\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") {\n warn(logger, `Could not stat ${fullPath}:`, err);\n }\n continue;\n }\n if (name.endsWith(\".json\")) {\n jsonFiles.push(name);\n }\n }\n jsonFiles.sort();\n\n const fixtures: Fixture[] = [];\n for (const name of jsonFiles) {\n const filePath = join(dirPath, name);\n fixtures.push(...loadFixtureFile(filePath, logger));\n }\n\n // Recurse one level into subdirectories to support snapshot-style layouts\n // where the recorder writes to <fixturePath>/<testId>/<provider>.json.\n subdirs.sort();\n for (const sub of subdirs) {\n const subPath = join(dirPath, sub);\n let subEntries: string[];\n try {\n subEntries = readdirSync(subPath);\n } catch (err) {\n warn(logger, `Could not read subdirectory ${subPath}:`, err);\n continue;\n }\n const subJsonFiles: string[] = [];\n for (const subName of subEntries) {\n const subFullPath = join(subPath, subName);\n try {\n if (statSync(subFullPath).isDirectory()) {\n // Only one level of recursion — skip deeper nesting\n continue;\n }\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") {\n warn(logger, `Could not stat ${subFullPath}:`, err);\n }\n continue;\n }\n if (subName.endsWith(\".json\")) {\n subJsonFiles.push(subName);\n }\n }\n subJsonFiles.sort();\n for (const subName of subJsonFiles) {\n const filePath = join(subPath, subName);\n fixtures.push(...loadFixtureFile(filePath, logger));\n }\n }\n\n return fixtures;\n}\n\n// ---------------------------------------------------------------------------\n// Fixture validation\n// ---------------------------------------------------------------------------\n\nexport interface ValidationResult {\n severity: \"error\" | \"warning\";\n fixtureIndex: number;\n message: string;\n}\n\nfunction validateReasoning(\n response: { reasoning?: unknown },\n fixtureIndex: number,\n results: ValidationResult[],\n): void {\n if (response.reasoning !== undefined) {\n if (typeof response.reasoning !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex,\n message: \"reasoning must be a string\",\n });\n } else if (response.reasoning === \"\") {\n results.push({\n severity: \"warning\",\n fixtureIndex,\n message: \"reasoning is empty string — no reasoning events will be emitted\",\n });\n }\n }\n}\n\nfunction validateWebSearches(\n response: { webSearches?: unknown },\n fixtureIndex: number,\n results: ValidationResult[],\n): void {\n if (response.webSearches !== undefined) {\n if (!Array.isArray(response.webSearches)) {\n results.push({\n severity: \"error\",\n fixtureIndex,\n message: \"webSearches must be an array of strings\",\n });\n } else if (response.webSearches.length === 0) {\n results.push({\n severity: \"warning\",\n fixtureIndex,\n message: \"webSearches is empty array — no web search events will be emitted\",\n });\n } else {\n for (let j = 0; j < response.webSearches.length; j++) {\n if (typeof response.webSearches[j] !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex,\n message: `webSearches[${j}] is not a string`,\n });\n break;\n }\n if (response.webSearches[j] === \"\") {\n results.push({\n severity: \"warning\",\n fixtureIndex,\n message: `webSearches[${j}] is empty string`,\n });\n }\n }\n }\n }\n}\n\nexport function validateFixtures(fixtures: Fixture[]): ValidationResult[] {\n const results: ValidationResult[] = [];\n\n const seenUserMessages = new Map<string, number>();\n\n for (let i = 0; i < fixtures.length; i++) {\n const f = fixtures[i];\n const response = f.response;\n\n // Skip response-shape validation for function responses — they are\n // evaluated at runtime so we cannot statically inspect them.\n if (typeof response === \"function\") {\n // Still validate match fields and numeric options below.\n } else {\n // --- Error checks ---\n\n // Response type recognition\n // Note: isContentWithToolCallsResponse must be checked before isTextResponse\n // and isToolCallResponse since it is a structural superset of both.\n if (\n !isContentWithToolCallsResponse(response) &&\n !isTextResponse(response) &&\n !isToolCallResponse(response) &&\n !isErrorResponse(response) &&\n !isEmbeddingResponse(response) &&\n !isImageResponse(response) &&\n !isAudioResponse(response) &&\n !isTranscriptionResponse(response) &&\n !isVideoResponse(response) &&\n !isJSONResponse(response)\n ) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message:\n \"response is not a recognized type (must have content, toolCalls, error, embedding, image, audio, transcription, video, or json)\",\n });\n }\n\n // Text response checks\n if (isTextResponse(response)) {\n if (response.content === \"\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"content is empty string\",\n });\n }\n validateReasoning(response, i, results);\n validateWebSearches(response, i, results);\n }\n\n // ContentWithToolCalls response checks\n if (isContentWithToolCallsResponse(response)) {\n if (response.content === \"\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"content is empty string\",\n });\n }\n if (response.toolCalls.length === 0) {\n results.push({\n severity: \"warning\",\n fixtureIndex: i,\n message: \"toolCalls array is empty — fixture will never produce tool calls\",\n });\n }\n for (let j = 0; j < response.toolCalls.length; j++) {\n const tc = response.toolCalls[j];\n if (!tc.name) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `toolCalls[${j}].name is empty`,\n });\n }\n try {\n JSON.parse(tc.arguments);\n } catch {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `toolCalls[${j}].arguments is not valid JSON: ${tc.arguments}`,\n });\n }\n }\n validateReasoning(response, i, results);\n validateWebSearches(response, i, results);\n }\n\n // Tool call response checks\n if (isToolCallResponse(response)) {\n if (response.toolCalls.length === 0) {\n results.push({\n severity: \"warning\",\n fixtureIndex: i,\n message: \"toolCalls array is empty — fixture will never produce tool calls\",\n });\n }\n for (let j = 0; j < response.toolCalls.length; j++) {\n const tc = response.toolCalls[j];\n if (!tc.name) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `toolCalls[${j}].name is empty`,\n });\n }\n try {\n JSON.parse(tc.arguments);\n } catch {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `toolCalls[${j}].arguments is not valid JSON: ${tc.arguments}`,\n });\n }\n }\n }\n\n // Error response checks\n if (isErrorResponse(response)) {\n if (!response.error.message) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"error.message is empty\",\n });\n }\n if (response.status !== undefined && (response.status < 100 || response.status > 599)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `error status ${response.status} is not a valid HTTP status code`,\n });\n }\n }\n\n // Embedding response checks\n if (isEmbeddingResponse(response)) {\n if (response.embedding.length === 0) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"embedding array is empty\",\n });\n }\n for (let j = 0; j < response.embedding.length; j++) {\n if (typeof response.embedding[j] !== \"number\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `embedding[${j}] is not a number`,\n });\n break; // one error is enough\n }\n }\n }\n\n // Audio response checks — validate object-form audio\n if (isAudioResponse(response) && typeof response.audio === \"object\") {\n const audioObj = response.audio;\n if (typeof audioObj.b64Json !== \"string\" || audioObj.b64Json === \"\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"audio.b64Json must be a non-empty string\",\n });\n }\n if (audioObj.contentType !== undefined && typeof audioObj.contentType !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `audio.contentType must be a string, got ${typeof audioObj.contentType}`,\n });\n }\n }\n\n // Validate ResponseOverrides fields\n if (\n isTextResponse(response) ||\n isToolCallResponse(response) ||\n isContentWithToolCallsResponse(response)\n ) {\n const r = response as ResponseOverrides;\n if (r.id !== undefined && typeof r.id !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"id\" must be a string, got ${typeof r.id}`,\n });\n }\n if (r.created !== undefined && (typeof r.created !== \"number\" || r.created < 0)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"created\" must be a non-negative number`,\n });\n }\n if (r.model !== undefined && typeof r.model !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"model\" must be a string, got ${typeof r.model}`,\n });\n }\n if (r.finishReason !== undefined && typeof r.finishReason !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"finishReason\" must be a string, got ${typeof r.finishReason}`,\n });\n }\n if (r.role !== undefined && typeof r.role !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"role\" must be a string, got ${typeof r.role}`,\n });\n }\n if (r.systemFingerprint !== undefined && typeof r.systemFingerprint !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"systemFingerprint\" must be a string, got ${typeof r.systemFingerprint}`,\n });\n }\n if (r.usage !== undefined) {\n if (typeof r.usage !== \"object\" || r.usage === null || Array.isArray(r.usage)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"usage\" must be an object`,\n });\n } else {\n // Check all known usage fields are numbers if present\n for (const key of Object.keys(r.usage)) {\n const val = (r.usage as Record<string, unknown>)[key];\n if (val !== undefined && typeof val !== \"number\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `override \"usage.${key}\" must be a number, got ${typeof val}`,\n });\n }\n }\n }\n }\n }\n } // end: skip response-shape validation for function responses\n\n // Numeric sanity checks\n if (f.latency !== undefined && f.latency < 0) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"latency must be >= 0\",\n });\n }\n if (f.chunkSize !== undefined && f.chunkSize < 1) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"chunkSize must be >= 1\",\n });\n }\n if (f.truncateAfterChunks !== undefined && f.truncateAfterChunks < 1) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"truncateAfterChunks must be >= 1\",\n });\n }\n if (f.disconnectAfterMs !== undefined && f.disconnectAfterMs < 0) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"disconnectAfterMs must be >= 0\",\n });\n }\n if (f.streamingProfile !== undefined) {\n const sp = f.streamingProfile;\n if (sp.ttft !== undefined && sp.ttft < 0) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"streamingProfile.ttft must be >= 0\",\n });\n }\n if (sp.tps !== undefined && sp.tps <= 0) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"streamingProfile.tps must be > 0\",\n });\n }\n if (sp.jitter !== undefined && (sp.jitter < 0 || sp.jitter > 1)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"streamingProfile.jitter must be between 0 and 1\",\n });\n }\n }\n if (f.chaos !== undefined) {\n const ch = f.chaos;\n if (ch.dropRate !== undefined && (ch.dropRate < 0 || ch.dropRate > 1)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"chaos.dropRate must be between 0 and 1\",\n });\n }\n if (ch.malformedRate !== undefined && (ch.malformedRate < 0 || ch.malformedRate > 1)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"chaos.malformedRate must be between 0 and 1\",\n });\n }\n if (ch.disconnectRate !== undefined && (ch.disconnectRate < 0 || ch.disconnectRate > 1)) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"chaos.disconnectRate must be between 0 and 1\",\n });\n }\n }\n\n // Match field type checks\n if (f.match.turnIndex !== undefined) {\n if (\n typeof f.match.turnIndex !== \"number\" ||\n f.match.turnIndex < 0 ||\n !Number.isInteger(f.match.turnIndex)\n ) {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: \"match.turnIndex must be a non-negative integer\",\n });\n }\n }\n if (f.match.hasToolResult !== undefined && typeof f.match.hasToolResult !== \"boolean\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `match.hasToolResult must be a boolean, got ${typeof f.match.hasToolResult}`,\n });\n }\n if (f.match.systemMessage !== undefined && typeof f.match.systemMessage !== \"string\") {\n results.push({\n severity: \"error\",\n fixtureIndex: i,\n message: `match.systemMessage must be a string, got ${typeof f.match.systemMessage}`,\n });\n }\n\n // --- Warning checks ---\n\n // Duplicate userMessage shadowing — include turnIndex, hasToolResult, and\n // sequenceIndex in the dedup key so that fixtures which share a userMessage\n // but differ on those fields are NOT considered duplicates.\n const um = f.match.userMessage;\n if (typeof um === \"string\" && um) {\n const dedupKey = `${um}|${f.match.turnIndex}|${f.match.hasToolResult}|${f.match.sequenceIndex}`;\n const prev = seenUserMessages.get(dedupKey);\n if (prev !== undefined) {\n results.push({\n severity: \"warning\",\n fixtureIndex: i,\n message: `duplicate userMessage '${um}' — shadows fixture ${prev}`,\n });\n } else {\n seenUserMessages.set(dedupKey, i);\n }\n }\n\n // Catch-all not in last position\n const match = f.match;\n const hasDiscriminator =\n match.endpoint !== undefined ||\n match.userMessage !== undefined ||\n match.systemMessage !== undefined ||\n match.inputText !== undefined ||\n match.responseFormat !== undefined ||\n match.toolCallId !== undefined ||\n match.toolName !== undefined ||\n match.model !== undefined ||\n match.predicate !== undefined ||\n match.turnIndex !== undefined ||\n match.hasToolResult !== undefined;\n\n if (!hasDiscriminator && i < fixtures.length - 1) {\n results.push({\n severity: \"warning\",\n fixtureIndex: i,\n message: `empty match acts as catch-all but is not the last fixture — shadows fixtures ${i + 1}+`,\n });\n }\n }\n\n return results;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fixture-loader.d.cts","names":[],"sources":["../src/fixture-loader.ts"],"sourcesContent":[],"mappings":";;;;;;;AA6BA;;;AAA6D,iBAA7C,iBAAA,CAA6C,GAAA,EAAtB,mBAAsB,CAAA,EAAA,eAAA;
|
|
1
|
+
{"version":3,"file":"fixture-loader.d.cts","names":[],"sources":["../src/fixture-loader.ts"],"sourcesContent":[],"mappings":";;;;;;;AA6BA;;;AAA6D,iBAA7C,iBAAA,CAA6C,GAAA,EAAtB,mBAAsB,CAAA,EAAA,eAAA;AA8D7C,iBAAA,eAAA,CAAe,QAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAA4B,MAA5B,CAAA,EAAqC,OAArC,EAAA;AAAA,iBA6Bf,mBAAA,CA7Be,OAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EA6B+B,MA7B/B,CAAA,EA6BwC,OA7BxC,EAAA;AAA4B,UA+G1C,gBAAA,CA/G0C;UAAS,EAAA,OAAA,GAAA,SAAA;EAAO,YAAA,EAAA,MAAA;EA6B3D,OAAA,EAAA,MAAA;;AAA8C,iBAsJ9C,gBAAA,CAtJ8C,QAAA,EAsJnB,OAtJmB,EAAA,CAAA,EAsJP,gBAtJO,EAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fixture-loader.d.ts","names":[],"sources":["../src/fixture-loader.ts"],"sourcesContent":[],"mappings":";;;;;;;AA6BA;;;AAA6D,iBAA7C,iBAAA,CAA6C,GAAA,EAAtB,mBAAsB,CAAA,EAAA,eAAA;
|
|
1
|
+
{"version":3,"file":"fixture-loader.d.ts","names":[],"sources":["../src/fixture-loader.ts"],"sourcesContent":[],"mappings":";;;;;;;AA6BA;;;AAA6D,iBAA7C,iBAAA,CAA6C,GAAA,EAAtB,mBAAsB,CAAA,EAAA,eAAA;AA8D7C,iBAAA,eAAA,CAAe,QAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAA4B,MAA5B,CAAA,EAAqC,OAArC,EAAA;AAAA,iBA6Bf,mBAAA,CA7Be,OAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EA6B+B,MA7B/B,CAAA,EA6BwC,OA7BxC,EAAA;AAA4B,UA+G1C,gBAAA,CA/G0C;UAAS,EAAA,OAAA,GAAA,SAAA;EAAO,YAAA,EAAA,MAAA;EA6B3D,OAAA,EAAA,MAAA;;AAA8C,iBAsJ9C,gBAAA,CAtJ8C,QAAA,EAsJnB,OAtJmB,EAAA,CAAA,EAsJP,gBAtJO,EAAA"}
|
package/dist/fixture-loader.js
CHANGED
|
@@ -24,6 +24,7 @@ function entryToFixture(entry) {
|
|
|
24
24
|
return {
|
|
25
25
|
match: {
|
|
26
26
|
userMessage: entry.match.userMessage,
|
|
27
|
+
systemMessage: entry.match.systemMessage,
|
|
27
28
|
inputText: entry.match.inputText,
|
|
28
29
|
toolCallId: entry.match.toolCallId,
|
|
29
30
|
toolName: entry.match.toolName,
|
|
@@ -398,6 +399,11 @@ function validateFixtures(fixtures) {
|
|
|
398
399
|
fixtureIndex: i,
|
|
399
400
|
message: `match.hasToolResult must be a boolean, got ${typeof f.match.hasToolResult}`
|
|
400
401
|
});
|
|
402
|
+
if (f.match.systemMessage !== void 0 && typeof f.match.systemMessage !== "string") results.push({
|
|
403
|
+
severity: "error",
|
|
404
|
+
fixtureIndex: i,
|
|
405
|
+
message: `match.systemMessage must be a string, got ${typeof f.match.systemMessage}`
|
|
406
|
+
});
|
|
401
407
|
const um = f.match.userMessage;
|
|
402
408
|
if (typeof um === "string" && um) {
|
|
403
409
|
const dedupKey = `${um}|${f.match.turnIndex}|${f.match.hasToolResult}|${f.match.sequenceIndex}`;
|
|
@@ -410,7 +416,7 @@ function validateFixtures(fixtures) {
|
|
|
410
416
|
else seenUserMessages.set(dedupKey, i);
|
|
411
417
|
}
|
|
412
418
|
const match = f.match;
|
|
413
|
-
if (!(match.endpoint !== void 0 || match.userMessage !== void 0 || match.inputText !== void 0 || match.responseFormat !== void 0 || match.toolCallId !== void 0 || match.toolName !== void 0 || match.model !== void 0 || match.predicate !== void 0 || match.turnIndex !== void 0 || match.hasToolResult !== void 0) && i < fixtures.length - 1) results.push({
|
|
419
|
+
if (!(match.endpoint !== void 0 || match.userMessage !== void 0 || match.systemMessage !== void 0 || match.inputText !== void 0 || match.responseFormat !== void 0 || match.toolCallId !== void 0 || match.toolName !== void 0 || match.model !== void 0 || match.predicate !== void 0 || match.turnIndex !== void 0 || match.hasToolResult !== void 0) && i < fixtures.length - 1) results.push({
|
|
414
420
|
severity: "warning",
|
|
415
421
|
fixtureIndex: i,
|
|
416
422
|
message: `empty match acts as catch-all but is not the last fixture — shadows fixtures ${i + 1}+`
|