@copilotkit/aimock 1.44.0 → 1.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +31 -0
  4. package/README.md +6 -0
  5. package/dist/agui-types.d.ts.map +1 -1
  6. package/dist/aimock-cli.cjs +31 -5
  7. package/dist/aimock-cli.cjs.map +1 -1
  8. package/dist/aimock-cli.d.cts.map +1 -1
  9. package/dist/aimock-cli.d.ts.map +1 -1
  10. package/dist/aimock-cli.js +31 -5
  11. package/dist/aimock-cli.js.map +1 -1
  12. package/dist/bedrock-converse.cjs +312 -39
  13. package/dist/bedrock-converse.cjs.map +1 -1
  14. package/dist/bedrock-converse.d.cts.map +1 -1
  15. package/dist/bedrock-converse.d.ts.map +1 -1
  16. package/dist/bedrock-converse.js +313 -40
  17. package/dist/bedrock-converse.js.map +1 -1
  18. package/dist/bedrock.cjs +195 -42
  19. package/dist/bedrock.cjs.map +1 -1
  20. package/dist/bedrock.d.cts.map +1 -1
  21. package/dist/bedrock.d.ts.map +1 -1
  22. package/dist/bedrock.js +196 -43
  23. package/dist/bedrock.js.map +1 -1
  24. package/dist/chaos.cjs +1 -0
  25. package/dist/chaos.js +1 -1
  26. package/dist/cli.cjs +152 -5
  27. package/dist/cli.cjs.map +1 -1
  28. package/dist/cli.js +155 -8
  29. package/dist/cli.js.map +1 -1
  30. package/dist/cohere.cjs +132 -71
  31. package/dist/cohere.cjs.map +1 -1
  32. package/dist/cohere.d.cts.map +1 -1
  33. package/dist/cohere.d.ts.map +1 -1
  34. package/dist/cohere.js +133 -72
  35. package/dist/cohere.js.map +1 -1
  36. package/dist/config-loader.cjs +62 -4
  37. package/dist/config-loader.cjs.map +1 -1
  38. package/dist/config-loader.d.cts +37 -4
  39. package/dist/config-loader.d.cts.map +1 -1
  40. package/dist/config-loader.d.ts +37 -4
  41. package/dist/config-loader.d.ts.map +1 -1
  42. package/dist/config-loader.js +62 -4
  43. package/dist/config-loader.js.map +1 -1
  44. package/dist/fakes-plugin.cjs +131 -0
  45. package/dist/fakes-plugin.cjs.map +1 -0
  46. package/dist/fakes-plugin.d.cts +23 -0
  47. package/dist/fakes-plugin.d.cts.map +1 -0
  48. package/dist/fakes-plugin.d.ts +23 -0
  49. package/dist/fakes-plugin.d.ts.map +1 -0
  50. package/dist/fakes-plugin.js +127 -0
  51. package/dist/fakes-plugin.js.map +1 -0
  52. package/dist/fixture-loader-services.cjs +1 -1
  53. package/dist/fixture-loader-services.cjs.map +1 -1
  54. package/dist/fixture-loader-services.js +1 -1
  55. package/dist/fixture-loader-services.js.map +1 -1
  56. package/dist/fixture-loader.cjs +389 -27
  57. package/dist/fixture-loader.cjs.map +1 -1
  58. package/dist/fixture-loader.d.cts +47 -3
  59. package/dist/fixture-loader.d.cts.map +1 -1
  60. package/dist/fixture-loader.d.ts +47 -3
  61. package/dist/fixture-loader.d.ts.map +1 -1
  62. package/dist/fixture-loader.js +384 -29
  63. package/dist/fixture-loader.js.map +1 -1
  64. package/dist/gemini-interactions.cjs +250 -52
  65. package/dist/gemini-interactions.cjs.map +1 -1
  66. package/dist/gemini-interactions.d.cts.map +1 -1
  67. package/dist/gemini-interactions.d.ts.map +1 -1
  68. package/dist/gemini-interactions.js +251 -53
  69. package/dist/gemini-interactions.js.map +1 -1
  70. package/dist/gemini.cjs +226 -37
  71. package/dist/gemini.cjs.map +1 -1
  72. package/dist/gemini.d.cts.map +1 -1
  73. package/dist/gemini.d.ts.map +1 -1
  74. package/dist/gemini.js +227 -38
  75. package/dist/gemini.js.map +1 -1
  76. package/dist/helpers.cjs +881 -7
  77. package/dist/helpers.cjs.map +1 -1
  78. package/dist/helpers.d.cts +85 -4
  79. package/dist/helpers.d.cts.map +1 -1
  80. package/dist/helpers.d.ts +85 -4
  81. package/dist/helpers.d.ts.map +1 -1
  82. package/dist/helpers.js +839 -8
  83. package/dist/helpers.js.map +1 -1
  84. package/dist/index.cjs +9 -0
  85. package/dist/index.d.cts +7 -5
  86. package/dist/index.d.ts +7 -5
  87. package/dist/index.js +4 -3
  88. package/dist/jest.cjs +31 -7
  89. package/dist/jest.cjs.map +1 -1
  90. package/dist/jest.d.cts +43 -3
  91. package/dist/jest.d.cts.map +1 -1
  92. package/dist/jest.d.ts +43 -3
  93. package/dist/jest.d.ts.map +1 -1
  94. package/dist/jest.js +33 -9
  95. package/dist/jest.js.map +1 -1
  96. package/dist/journal.cjs +135 -13
  97. package/dist/journal.cjs.map +1 -1
  98. package/dist/journal.d.cts +38 -4
  99. package/dist/journal.d.cts.map +1 -1
  100. package/dist/journal.d.ts +38 -4
  101. package/dist/journal.d.ts.map +1 -1
  102. package/dist/journal.js +135 -13
  103. package/dist/journal.js.map +1 -1
  104. package/dist/live-sanitize.cjs +4 -32
  105. package/dist/live-sanitize.cjs.map +1 -1
  106. package/dist/live-sanitize.js +4 -32
  107. package/dist/live-sanitize.js.map +1 -1
  108. package/dist/llmock.cjs +123 -30
  109. package/dist/llmock.cjs.map +1 -1
  110. package/dist/llmock.d.cts +16 -1
  111. package/dist/llmock.d.cts.map +1 -1
  112. package/dist/llmock.d.ts +16 -1
  113. package/dist/llmock.d.ts.map +1 -1
  114. package/dist/llmock.js +125 -32
  115. package/dist/llmock.js.map +1 -1
  116. package/dist/mcp-fakes-mount.cjs +1 -0
  117. package/dist/mcp-fakes-mount.cjs.map +1 -1
  118. package/dist/mcp-fakes-mount.js +1 -0
  119. package/dist/mcp-fakes-mount.js.map +1 -1
  120. package/dist/mcp-fakes-report.cjs +111 -0
  121. package/dist/mcp-fakes-report.cjs.map +1 -0
  122. package/dist/mcp-fakes-report.d.cts +40 -0
  123. package/dist/mcp-fakes-report.d.cts.map +1 -0
  124. package/dist/mcp-fakes-report.d.ts +40 -0
  125. package/dist/mcp-fakes-report.d.ts.map +1 -0
  126. package/dist/mcp-fakes-report.js +107 -0
  127. package/dist/mcp-fakes-report.js.map +1 -0
  128. package/dist/mcp-fakes.cjs +331 -8
  129. package/dist/mcp-fakes.cjs.map +1 -1
  130. package/dist/mcp-fakes.d.cts +406 -3
  131. package/dist/mcp-fakes.d.cts.map +1 -1
  132. package/dist/mcp-fakes.d.ts +406 -3
  133. package/dist/mcp-fakes.d.ts.map +1 -1
  134. package/dist/mcp-fakes.js +331 -8
  135. package/dist/mcp-fakes.js.map +1 -1
  136. package/dist/mcp-handler.cjs +209 -16
  137. package/dist/mcp-handler.cjs.map +1 -1
  138. package/dist/mcp-handler.d.cts +49 -0
  139. package/dist/mcp-handler.d.cts.map +1 -0
  140. package/dist/mcp-handler.d.ts +49 -0
  141. package/dist/mcp-handler.d.ts.map +1 -0
  142. package/dist/mcp-handler.js +207 -17
  143. package/dist/mcp-handler.js.map +1 -1
  144. package/dist/mcp-mock.cjs +112 -1
  145. package/dist/mcp-mock.cjs.map +1 -1
  146. package/dist/mcp-mock.d.cts +33 -2
  147. package/dist/mcp-mock.d.cts.map +1 -1
  148. package/dist/mcp-mock.d.ts +33 -2
  149. package/dist/mcp-mock.d.ts.map +1 -1
  150. package/dist/mcp-mock.js +112 -1
  151. package/dist/mcp-mock.js.map +1 -1
  152. package/dist/mcp-recorder.cjs +1224 -0
  153. package/dist/mcp-recorder.cjs.map +1 -0
  154. package/dist/mcp-recorder.d.cts +108 -0
  155. package/dist/mcp-recorder.d.cts.map +1 -0
  156. package/dist/mcp-recorder.d.ts +108 -0
  157. package/dist/mcp-recorder.d.ts.map +1 -0
  158. package/dist/mcp-recorder.js +1215 -0
  159. package/dist/mcp-recorder.js.map +1 -0
  160. package/dist/messages.cjs +362 -56
  161. package/dist/messages.cjs.map +1 -1
  162. package/dist/messages.d.cts.map +1 -1
  163. package/dist/messages.d.ts.map +1 -1
  164. package/dist/messages.js +363 -58
  165. package/dist/messages.js.map +1 -1
  166. package/dist/misbehavior.cjs +1523 -0
  167. package/dist/misbehavior.cjs.map +1 -0
  168. package/dist/misbehavior.d.cts +43 -0
  169. package/dist/misbehavior.d.cts.map +1 -0
  170. package/dist/misbehavior.d.ts +43 -0
  171. package/dist/misbehavior.d.ts.map +1 -0
  172. package/dist/misbehavior.js +1511 -0
  173. package/dist/misbehavior.js.map +1 -0
  174. package/dist/ollama.cjs +310 -112
  175. package/dist/ollama.cjs.map +1 -1
  176. package/dist/ollama.d.cts.map +1 -1
  177. package/dist/ollama.d.ts.map +1 -1
  178. package/dist/ollama.js +311 -113
  179. package/dist/ollama.js.map +1 -1
  180. package/dist/record-sanitize.cjs +231 -0
  181. package/dist/record-sanitize.cjs.map +1 -0
  182. package/dist/record-sanitize.js +224 -0
  183. package/dist/record-sanitize.js.map +1 -0
  184. package/dist/recorder.cjs +106 -5
  185. package/dist/recorder.cjs.map +1 -1
  186. package/dist/recorder.d.cts +2 -1
  187. package/dist/recorder.d.cts.map +1 -1
  188. package/dist/recorder.d.ts +2 -1
  189. package/dist/recorder.d.ts.map +1 -1
  190. package/dist/recorder.js +107 -7
  191. package/dist/recorder.js.map +1 -1
  192. package/dist/responses.cjs +667 -171
  193. package/dist/responses.cjs.map +1 -1
  194. package/dist/responses.d.cts +5 -13
  195. package/dist/responses.d.cts.map +1 -1
  196. package/dist/responses.d.ts +5 -13
  197. package/dist/responses.d.ts.map +1 -1
  198. package/dist/responses.js +665 -174
  199. package/dist/responses.js.map +1 -1
  200. package/dist/router.cjs +24 -2
  201. package/dist/router.cjs.map +1 -1
  202. package/dist/router.d.cts.map +1 -1
  203. package/dist/router.d.ts.map +1 -1
  204. package/dist/router.js +25 -4
  205. package/dist/router.js.map +1 -1
  206. package/dist/server.cjs +572 -76
  207. package/dist/server.cjs.map +1 -1
  208. package/dist/server.d.cts.map +1 -1
  209. package/dist/server.d.ts.map +1 -1
  210. package/dist/server.js +574 -78
  211. package/dist/server.js.map +1 -1
  212. package/dist/stream-collapse.cjs +236 -34
  213. package/dist/stream-collapse.cjs.map +1 -1
  214. package/dist/stream-collapse.d.cts +39 -4
  215. package/dist/stream-collapse.d.cts.map +1 -1
  216. package/dist/stream-collapse.d.ts +39 -4
  217. package/dist/stream-collapse.d.ts.map +1 -1
  218. package/dist/stream-collapse.js +235 -35
  219. package/dist/stream-collapse.js.map +1 -1
  220. package/dist/types.cjs.map +1 -1
  221. package/dist/types.d.cts +315 -4
  222. package/dist/types.d.cts.map +1 -1
  223. package/dist/types.d.ts +315 -4
  224. package/dist/types.d.ts.map +1 -1
  225. package/dist/types.js.map +1 -1
  226. package/dist/validate-cli.cjs +36 -4
  227. package/dist/validate-cli.cjs.map +1 -1
  228. package/dist/validate-cli.js +37 -5
  229. package/dist/validate-cli.js.map +1 -1
  230. package/dist/vector-types.d.ts.map +1 -1
  231. package/dist/version.cjs +45 -0
  232. package/dist/version.cjs.map +1 -0
  233. package/dist/version.js +44 -0
  234. package/dist/version.js.map +1 -0
  235. package/dist/vitest.cjs +66 -10
  236. package/dist/vitest.cjs.map +1 -1
  237. package/dist/vitest.d.cts +35 -4
  238. package/dist/vitest.d.cts.map +1 -1
  239. package/dist/vitest.d.ts +35 -4
  240. package/dist/vitest.d.ts.map +1 -1
  241. package/dist/vitest.js +67 -11
  242. package/dist/vitest.js.map +1 -1
  243. package/dist/watcher.cjs +6 -2
  244. package/dist/watcher.cjs.map +1 -1
  245. package/dist/watcher.js +6 -2
  246. package/dist/watcher.js.map +1 -1
  247. package/dist/ws-gemini-live.cjs +210 -101
  248. package/dist/ws-gemini-live.cjs.map +1 -1
  249. package/dist/ws-gemini-live.d.cts +9 -3
  250. package/dist/ws-gemini-live.d.cts.map +1 -1
  251. package/dist/ws-gemini-live.d.ts +9 -3
  252. package/dist/ws-gemini-live.d.ts.map +1 -1
  253. package/dist/ws-gemini-live.js +211 -102
  254. package/dist/ws-gemini-live.js.map +1 -1
  255. package/dist/ws-realtime.cjs +175 -62
  256. package/dist/ws-realtime.cjs.map +1 -1
  257. package/dist/ws-realtime.d.cts +8 -3
  258. package/dist/ws-realtime.d.cts.map +1 -1
  259. package/dist/ws-realtime.d.ts +8 -3
  260. package/dist/ws-realtime.d.ts.map +1 -1
  261. package/dist/ws-realtime.js +176 -63
  262. package/dist/ws-realtime.js.map +1 -1
  263. package/dist/ws-responses.cjs +109 -16
  264. package/dist/ws-responses.cjs.map +1 -1
  265. package/dist/ws-responses.d.cts +8 -12
  266. package/dist/ws-responses.d.cts.map +1 -1
  267. package/dist/ws-responses.d.ts +8 -12
  268. package/dist/ws-responses.d.ts.map +1 -1
  269. package/dist/ws-responses.js +111 -18
  270. package/dist/ws-responses.js.map +1 -1
  271. package/package.json +10 -2
  272. package/skills/write-fixtures/SKILL.md +179 -21
@@ -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 FixtureBlock,\n HandlerDefaults,\n RecordedTimings,\n ResponseOverrides,\n StreamingProfile,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n generateMessageId,\n generateToolCallId,\n generateDeterministicEmbedding,\n extractOverrides,\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isEmbeddingResponse,\n isErrorResponse,\n serializeErrorResponse,\n validateChatMessages,\n validateToolsField,\n flattenHeaders,\n isJsonObject,\n getTestId,\n resolveFixtureBlockOutcome,\n resolveResponse,\n resolveStrictMode,\n resolveReasoningForModel,\n strictOverrideField,\n getContext,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic, recordMatchOptions } from \"./router.js\";\nimport { writeErrorResponse, delay, calculateDelay } from \"./sse-writer.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { Logger } from \"./logger.js\";\nimport { applyChaosAsync } 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[] | null | undefined): string {\n if (content === null || content === undefined) return \"\";\n if (typeof content === \"string\") return content;\n return content\n .filter(\n (part) =>\n part !== null && part !== undefined && part.type === \"text\" && part.text !== undefined,\n )\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 reasoning?: string,\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 // Reasoning as a leading text block (Cohere has no native reasoning type)\n const contentBlocks: { type: string; text: string }[] = [];\n if (reasoning) {\n contentBlocks.push({ type: \"text\", text: reasoning });\n }\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// Non-streaming content + tool calls response\nfunction buildCohereContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n blocks?: FixtureBlock[],\n): object {\n // Cohere's non-streaming response keeps text in `message.content[]` and tool\n // calls in the SEPARATE `message.tool_calls[]` field, so the relative ORDER\n // of a text vs. toolCall block is NOT observable on the wire (unlike the\n // ordered streaming events, or Anthropic/Gemini's single ordered array).\n // When `blocks` is present we therefore derive both fields FROM the blocks\n // (so a blocks-only fixture still produces correct output) but make no\n // ordering guarantee between the two fields. Legacy fixtures use the\n // `content` + `toolCalls` inputs unchanged.\n // Resolve the blocks exactly once (pure: validate + copy, no id-gen) and\n // reuse the single result for BOTH the tool-call and text derivation below.\n const outcome = blocks && blocks.length > 0 ? resolveFixtureBlockOutcome(blocks) : undefined;\n const resolvedBlocks = outcome?.ordered;\n\n const effectiveToolCalls: ToolCall[] = resolvedBlocks\n ? resolvedBlocks\n .filter((b): b is Extract<FixtureBlock, { type: \"toolCall\" }> => b.type === \"toolCall\")\n .map((b) => ({ name: b.name, arguments: b.arguments, id: b.id }))\n : toolCalls;\n\n const cohereCalls = effectiveToolCalls.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 // For the blocks path, derive text only from actual text blocks. A tool-only\n // blocks fixture has no text block, so it must NOT emit a spurious empty\n // `{ type: \"text\", text: \"\" }` entry (real Cohere wouldn't). The legacy\n // (no-blocks) path is unchanged: it always emits the `content` text entry.\n const textBlocks = resolvedBlocks?.filter(\n (b): b is Extract<FixtureBlock, { type: \"text\" }> => b.type === \"text\",\n );\n const hasTextEntry = resolvedBlocks ? (textBlocks?.length ?? 0) > 0 : true;\n const effectiveContent: string = resolvedBlocks\n ? (textBlocks ?? []).map((b) => b.text).join(\"\")\n : content;\n\n const contentBlocks: { type: string; text: string }[] = [];\n if (reasoning) {\n contentBlocks.push({ type: \"text\", text: reasoning });\n }\n if (hasTextEntry) {\n contentBlocks.push({ type: \"text\", text: effectiveContent });\n }\n\n return {\n id: overrides?.id ?? generateMessageId(),\n finish_reason: cohereFinishReason(\n overrides?.finishReason,\n outcome && !outcome.hasToolCalls ? \"COMPLETE\" : \"TOOL_CALL\",\n ),\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 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 // Reasoning as a text block before the tool plan (Cohere has no native reasoning type)\n if (reasoning) {\n events.push({\n type: \"content-start\",\n index: 0,\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: 0,\n delta: { message: { content: { type: \"text\", text: slice } } },\n });\n }\n events.push({ type: \"content-end\", index: 0 });\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 blocks?: FixtureBlock[],\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 if (blocks && blocks.length > 0) {\n // NEW path (#274): emit Cohere SSE events in the blocks' ARRAY ORDER so a\n // tool-first / interleaved fixture streams its tool call before its text.\n // Cohere v2 events are ordered, so tool-first is wire-expressible. The\n // tool-plan-delta is emitted once before the first toolCall block (Cohere\n // requires it preceding tool calls). Legacy fixtures (no blocks) skip this.\n const outcome = resolveFixtureBlockOutcome(blocks);\n const resolved = outcome.ordered;\n let toolPlanEmitted = false;\n let toolIdx = 0;\n resolved.forEach((block) => {\n if (block.type === \"toolCall\") {\n if (!toolPlanEmitted) {\n events.push({\n type: \"tool-plan-delta\",\n delta: { message: { tool_plan: \"I will use the requested tool.\" } },\n });\n toolPlanEmitted = true;\n }\n const callId = block.id || generateToolCallId();\n let argsJson: string;\n try {\n JSON.parse(block.arguments || \"{}\");\n argsJson = block.arguments || \"{}\";\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${block.name}\": ${block.arguments}`,\n );\n argsJson = \"{}\";\n }\n events.push({\n type: \"tool-call-start\",\n index: toolIdx,\n delta: {\n message: {\n tool_calls: {\n id: callId,\n type: \"function\",\n function: { name: block.name, arguments: \"\" },\n },\n },\n },\n });\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n events.push({\n type: \"tool-call-delta\",\n index: toolIdx,\n delta: {\n message: {\n tool_calls: { function: { arguments: argsJson.slice(i, i + chunkSize) } },\n },\n },\n });\n }\n events.push({ type: \"tool-call-end\", index: toolIdx });\n toolIdx++;\n } else {\n events.push({\n type: \"content-start\",\n index: contentIndex,\n delta: { message: { content: { type: \"text\" } } },\n });\n for (let i = 0; i < block.text.length; i += chunkSize) {\n events.push({\n type: \"content-delta\",\n index: contentIndex,\n delta: {\n message: { content: { type: \"text\", text: block.text.slice(i, i + chunkSize) } },\n },\n });\n }\n events.push({ type: \"content-end\", index: contentIndex });\n contentIndex++;\n }\n });\n events.push({\n type: \"message-end\",\n delta: {\n finish_reason: cohereFinishReason(\n overrides?.finishReason,\n outcome.hasToolCalls ? \"TOOL_CALL\" : \"COMPLETE\",\n ),\n usage: cohereUsage(overrides),\n },\n });\n return events;\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 recordedTimings?: RecordedTimings;\n replaySpeed?: number;\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 { recordedTimings, replaySpeed } = opts;\n const signal = opts.signal;\n const onChunkSent = opts.onChunkSent;\n\n if (res.writableEnded) return true;\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n let chunkIndex = 0;\n for (const event of events) {\n const chunkDelay = calculateDelay(chunkIndex, profile, latency, recordedTimings, replaySpeed);\n if (chunkDelay > 0) await delay(chunkDelay, signal);\n if (signal?.aborted) return false;\n if (res.writableEnded) return true;\n res.write(`event: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`);\n onChunkSent?.();\n if (signal?.aborted) return false;\n chunkIndex++;\n }\n\n if (!res.writableEnded) {\n res.end();\n }\n return true;\n}\n\n// ─── Request handler ────────────────────────────────────────────────────────\n\nexport async function 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 (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\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 body: ${detail}`,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Reject non-object bodies (e.g. `null`) before touching fields —\n // otherwise `cohereReq.model` throws a TypeError that surfaces as a 500\n // instead of a 400.\n if (!isJsonObject(cohereReq)) {\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: \"Request body must be a JSON object\",\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 // Reject wrong-typed message/tool fields before the converter dereferences\n // them — otherwise the TypeError surfaces as a 500 instead of a 400.\n let shapeError = validateChatMessages(cohereReq.messages) ?? validateToolsField(cohereReq.tools);\n if (!shapeError && Array.isArray(cohereReq.tools)) {\n const nullFunctionIndex = cohereReq.tools.findIndex(\n (tool) => \"function\" in tool && tool.function === null,\n );\n if (nullFunctionIndex !== -1) {\n shapeError = `tools[${nullFunctionIndex}].function must be an object`;\n }\n }\n if (shapeError) {\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: ${shapeError}`,\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 completionReq._context = getContext(req);\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n // Record mode proxies on a miss to capture a fresh turn (see record gate\n // below), so keep turnIndex strict to prevent an earlier-turn fixture from\n // shadowing a longer request and skipping the new turn's recording.\n recordMatchOptions(!!defaults.record, defaults.logger),\n );\n\n if (fixture) {\n 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 await applyChaosAsync(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\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 const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictStatus = 503;\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n logger.error(\n strictNoMatchLogLine(req.method ?? \"POST\", req.url ?? \"/v2/chat\", skippedBySequenceOrTurn),\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: {\n status: strictStatus,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\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 === \"handled_by_hook\") return;\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 journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n },\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, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\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 effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n cohereReq.model,\n effectiveStrict,\n logger,\n );\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 effReasoning,\n overrides,\n response.blocks,\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 effReasoning,\n overrides,\n response.blocks,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeCohereSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\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 effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n cohereReq.model,\n effectiveStrict,\n logger,\n );\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, effReasoning, 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 effReasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeCohereSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\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 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 effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n cohereReq.model,\n effectiveStrict,\n logger,\n );\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, effReasoning, 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 effReasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeCohereSSEStream(res, events, {\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\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\n// ─── Cohere v2 Embed API types ────────────────────────────────────────────\n\ninterface CohereEmbedRequest {\n texts: string[];\n model: string;\n input_type?: string;\n embedding_types?: string[];\n truncate?: string;\n}\n\ninterface CohereEmbedResponse {\n id: string;\n texts: string[];\n embeddings: Record<string, number[][]>;\n meta: { api_version: { version: string } };\n}\n\n// ─── Cohere Embed handler ─────────────────────────────────────────────────\n\nexport async function handleCohereEmbed(\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 embedReq: CohereEmbedRequest;\n try {\n embedReq = JSON.parse(raw) as CohereEmbedRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\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 body: ${detail}`,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Reject non-object bodies (e.g. `null`) before touching fields —\n // otherwise `embedReq.model` throws a TypeError that surfaces as a 500\n // instead of a 400.\n if (!isJsonObject(embedReq)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\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: \"Request body must be a JSON object\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Validate required fields\n if (!embedReq.model) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\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 (!embedReq.texts || !Array.isArray(embedReq.texts)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\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: texts array is required\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Every text must be a string — a number reaches createHash().update() in\n // the no-fixture fallback and throws a TypeError (500) instead of a 400.\n if (!embedReq.texts.every((text) => typeof text === \"string\")) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\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: texts must be an array of strings\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Concatenate all texts for fixture matching\n const combinedInput = embedReq.texts.join(\" \");\n\n // Build a synthetic ChatCompletionRequest for the fixture router\n const syntheticReq: ChatCompletionRequest = {\n model: embedReq.model,\n messages: [],\n embeddingInput: combinedInput,\n _endpointType: \"embedding\",\n _context: getContext(req),\n };\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n // Record mode proxies on a miss to capture a fresh turn (see record gate\n // below), so keep turnIndex strict to prevent an earlier-turn fixture from\n // shadowing a longer request and skipping the new turn's recording.\n recordMatchOptions(!!defaults.record, defaults.logger),\n );\n\n if (fixture) {\n 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 await applyChaosAsync(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n {\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n // Determine requested embedding types (default to float)\n const embeddingTypes =\n embedReq.embedding_types && embedReq.embedding_types.length > 0\n ? embedReq.embedding_types\n : [\"float\"];\n\n function rejectInvalidEmbeddingTypes(): boolean {\n if (embedReq.embedding_types == null) return false;\n const isArray = Array.isArray(embedReq.embedding_types);\n if (isArray && embedReq.embedding_types.every((type) => typeof type === \"string\")) return false;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 400, fixture: fixture ?? null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: isArray\n ? \"Invalid request: embedding_types must be an array of strings\"\n : \"Invalid request: embedding_types must be an array\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return true;\n }\n\n if (fixture) {\n const response = await resolveResponse(fixture, syntheticReq);\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/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n // Embedding response — use the fixture's embedding for each input text\n if (isEmbeddingResponse(response)) {\n if (rejectInvalidEmbeddingTypes()) return;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n const vectors = embedReq.texts.map(() => [...response.embedding]);\n const embeddings: Record<string, number[][]> = {};\n for (const t of embeddingTypes) {\n embeddings[t] = vectors;\n }\n const body: CohereEmbedResponse = {\n id: generateMessageId(),\n texts: embedReq.texts,\n embeddings,\n meta: { api_version: { version: \"2\" } },\n };\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n return;\n }\n\n // Fixture matched but response type is not compatible with embeddings\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message:\n \"Fixture response did not match any known embedding type (must have embedding or error)\",\n type: \"server_error\",\n },\n }),\n );\n return;\n }\n\n // No fixture match — check strict mode\n if (resolveStrictMode(defaults.strict, req.headers)) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n logger.error(\n strictNoMatchLogLine(req.method ?? \"POST\", req.url ?? \"/v2/embed\", skippedBySequenceOrTurn),\n );\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Try record-and-replay proxy\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"cohere\",\n req.url ?? \"/v2/embed\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n if (rejectInvalidEmbeddingTypes()) return;\n\n // No fixture match — generate deterministic embeddings from input texts\n logger.warn(\n `No embedding fixture matched for \"${combinedInput.slice(0, 80)}\" — returning deterministic fallback`,\n );\n const dimensions = 1024; // Cohere embed-v4.0 default\n const vectors = embedReq.texts.map((text) => generateDeterministicEmbedding(text, dimensions));\n const embeddings: Record<string, number[][]> = {};\n for (const t of embeddingTypes) {\n embeddings[t] = vectors;\n }\n\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture: null },\n });\n\n const body: CohereEmbedResponse = {\n id: generateMessageId(),\n texts: embedReq.texts,\n embeddings,\n meta: { api_version: { version: \"2\" } },\n };\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n}\n"],"mappings":"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"}
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 FixtureBlock,\n HandlerDefaults,\n RecordedTimings,\n ResponseOverrides,\n StreamingProfile,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n prepareOpenAIChatMisbehavior,\n resolveOpenAIChatMisbehaviorUsage,\n generateMessageId,\n generateToolCallId,\n generateDeterministicEmbedding,\n extractOverrides,\n requireEmittedFunctionToolCalls,\n isTextResponse,\n isToolCallResponse,\n isCombinedFixtureResponse,\n isEmbeddingResponse,\n isErrorResponse,\n serializeErrorResponse,\n validateChatMessages,\n validateToolsField,\n flattenHeaders,\n isJsonObject,\n getTestId,\n resolveFixtureBlockOutcome,\n resolveResponse,\n resolveStrictMode,\n resolveReasoningForModel,\n strictOverrideField,\n getContext,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n servedToolArgs,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic, recordMatchOptions } from \"./router.js\";\nimport { writeErrorResponse, delay, calculateDelay } from \"./sse-writer.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { Logger } from \"./logger.js\";\nimport { applyChaosAsync } from \"./chaos.js\";\nimport {\n normalizeDirectToolSchema,\n planMisbehavior,\n recordMisbehaviorOutcome,\n} from \"./misbehavior.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[] | null | undefined): string {\n if (content === null || content === undefined) return \"\";\n if (typeof content === \"string\") return content;\n return content\n .filter(\n (part) =>\n part !== null && part !== undefined && part.type === \"text\" && part.text !== undefined,\n )\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 // Preserve the native map identity before adapting to canonical JSON Schema.\n const schema = normalizeDirectToolSchema({ tools: [t] }, t.name);\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: schema\n ? { type: \"object\", properties: schema.properties, required: [...schema.required] }\n : undefined,\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 reasoning?: string,\n overrides?: ResponseOverrides,\n): object {\n const cohereCalls = toolCalls.map((tc) => {\n // Validate arguments JSON\n const args = servedToolArgs(tc, \"string\", logger);\n const argsJson = args.raw;\n return {\n id: tc.id || generateToolCallId(),\n type: \"function\",\n function: {\n name: tc.name,\n arguments: argsJson,\n },\n };\n });\n\n // Reasoning as a leading text block (Cohere has no native reasoning type)\n const contentBlocks: { type: string; text: string }[] = [];\n if (reasoning) {\n contentBlocks.push({ type: \"text\", text: reasoning });\n }\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// Non-streaming content + tool calls response\nfunction buildCohereContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n blocks?: FixtureBlock[],\n): object {\n // Cohere's non-streaming response keeps text in `message.content[]` and tool\n // calls in the SEPARATE `message.tool_calls[]` field, so the relative ORDER\n // of a text vs. toolCall block is NOT observable on the wire (unlike the\n // ordered streaming events, or Anthropic/Gemini's single ordered array).\n // When `blocks` is present we therefore derive both fields FROM the blocks\n // (so a blocks-only fixture still produces correct output) but make no\n // ordering guarantee between the two fields. Legacy fixtures use the\n // `content` + `toolCalls` inputs unchanged.\n // Resolve the blocks exactly once (pure: validate + copy, no id-gen) and\n // reuse the single result for BOTH the tool-call and text derivation below.\n const outcome = blocks && blocks.length > 0 ? resolveFixtureBlockOutcome(blocks) : undefined;\n const resolvedBlocks = outcome?.ordered;\n\n const effectiveToolCalls: ToolCall[] = resolvedBlocks\n ? resolvedBlocks\n .filter((b): b is Extract<FixtureBlock, { type: \"toolCall\" }> => b.type === \"toolCall\")\n .map((b) => ({ name: b.name, arguments: b.arguments, id: b.id }))\n : toolCalls;\n\n const cohereCalls = effectiveToolCalls.map((tc) => {\n const args = servedToolArgs(tc, \"string\", logger);\n const argsJson = args.raw;\n return {\n id: tc.id || generateToolCallId(),\n type: \"function\",\n function: {\n name: tc.name,\n arguments: argsJson,\n },\n };\n });\n\n // For the blocks path, derive text only from actual text blocks. A tool-only\n // blocks fixture has no text block, so it must NOT emit a spurious empty\n // `{ type: \"text\", text: \"\" }` entry (real Cohere wouldn't). The legacy\n // (no-blocks) path is unchanged: it always emits the `content` text entry.\n const textBlocks = resolvedBlocks?.filter(\n (b): b is Extract<FixtureBlock, { type: \"text\" }> => b.type === \"text\",\n );\n const hasTextEntry = resolvedBlocks ? (textBlocks?.length ?? 0) > 0 : true;\n const effectiveContent: string = resolvedBlocks\n ? (textBlocks ?? []).map((b) => b.text).join(\"\")\n : content;\n\n const contentBlocks: { type: string; text: string }[] = [];\n if (reasoning) {\n contentBlocks.push({ type: \"text\", text: reasoning });\n }\n if (hasTextEntry) {\n contentBlocks.push({ type: \"text\", text: effectiveContent });\n }\n\n return {\n id: overrides?.id ?? generateMessageId(),\n finish_reason: cohereFinishReason(\n overrides?.finishReason,\n outcome && !outcome.hasToolCalls ? \"COMPLETE\" : \"TOOL_CALL\",\n ),\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 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 // Reasoning as a text block before the tool plan (Cohere has no native reasoning type)\n if (reasoning) {\n events.push({\n type: \"content-start\",\n index: 0,\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: 0,\n delta: { message: { content: { type: \"text\", text: slice } } },\n });\n }\n events.push({ type: \"content-end\", index: 0 });\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 const args = servedToolArgs(tc, \"string\", logger);\n const argsJson = args.raw;\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 blocks?: FixtureBlock[],\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 if (blocks && blocks.length > 0) {\n // NEW path (#274): emit Cohere SSE events in the blocks' ARRAY ORDER so a\n // tool-first / interleaved fixture streams its tool call before its text.\n // Cohere v2 events are ordered, so tool-first is wire-expressible. The\n // tool-plan-delta is emitted once before the first toolCall block (Cohere\n // requires it preceding tool calls). Legacy fixtures (no blocks) skip this.\n const outcome = resolveFixtureBlockOutcome(blocks);\n const resolved = outcome.ordered;\n let toolPlanEmitted = false;\n let toolIdx = 0;\n resolved.forEach((block) => {\n if (block.type === \"toolCall\") {\n if (!toolPlanEmitted) {\n events.push({\n type: \"tool-plan-delta\",\n delta: { message: { tool_plan: \"I will use the requested tool.\" } },\n });\n toolPlanEmitted = true;\n }\n const callId = block.id || generateToolCallId();\n const args = servedToolArgs(block, \"string\", logger);\n const argsJson = args.raw;\n events.push({\n type: \"tool-call-start\",\n index: toolIdx,\n delta: {\n message: {\n tool_calls: {\n id: callId,\n type: \"function\",\n function: { name: block.name, arguments: \"\" },\n },\n },\n },\n });\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n events.push({\n type: \"tool-call-delta\",\n index: toolIdx,\n delta: {\n message: {\n tool_calls: { function: { arguments: argsJson.slice(i, i + chunkSize) } },\n },\n },\n });\n }\n events.push({ type: \"tool-call-end\", index: toolIdx });\n toolIdx++;\n } else {\n events.push({\n type: \"content-start\",\n index: contentIndex,\n delta: { message: { content: { type: \"text\" } } },\n });\n for (let i = 0; i < block.text.length; i += chunkSize) {\n events.push({\n type: \"content-delta\",\n index: contentIndex,\n delta: {\n message: { content: { type: \"text\", text: block.text.slice(i, i + chunkSize) } },\n },\n });\n }\n events.push({ type: \"content-end\", index: contentIndex });\n contentIndex++;\n }\n });\n events.push({\n type: \"message-end\",\n delta: {\n finish_reason: cohereFinishReason(\n overrides?.finishReason,\n outcome.hasToolCalls ? \"TOOL_CALL\" : \"COMPLETE\",\n ),\n usage: cohereUsage(overrides),\n },\n });\n return events;\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 const args = servedToolArgs(tc, \"string\", logger);\n const argsJson = args.raw;\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 terminalSentinel?: boolean;\n latency?: number;\n streamingProfile?: StreamingProfile;\n recordedTimings?: RecordedTimings;\n replaySpeed?: number;\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 { recordedTimings, replaySpeed } = opts;\n const signal = opts.signal;\n const onChunkSent = opts.onChunkSent;\n\n if (res.writableEnded) return true;\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n let chunkIndex = 0;\n for (const event of events) {\n const chunkDelay = calculateDelay(chunkIndex, profile, latency, recordedTimings, replaySpeed);\n if (chunkDelay > 0) await delay(chunkDelay, signal);\n if (signal?.aborted) return false;\n if (res.writableEnded) return true;\n res.write(`event: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`);\n onChunkSent?.();\n if (signal?.aborted) return false;\n chunkIndex++;\n }\n\n if (!res.writableEnded) {\n if (opts.terminalSentinel && !signal?.aborted) res.write(\"data: [DONE]\\n\\n\");\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 (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\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 body: ${detail}`,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Reject non-object bodies (e.g. `null`) before touching fields —\n // otherwise `cohereReq.model` throws a TypeError that surfaces as a 500\n // instead of a 400.\n if (!isJsonObject(cohereReq)) {\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: \"Request body must be a JSON object\",\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 // Reject wrong-typed message/tool fields before the converter dereferences\n // them — otherwise the TypeError surfaces as a 500 instead of a 400.\n let shapeError = validateChatMessages(cohereReq.messages) ?? validateToolsField(cohereReq.tools);\n if (!shapeError && Array.isArray(cohereReq.tools)) {\n const nullFunctionIndex = cohereReq.tools.findIndex(\n (tool) => \"function\" in tool && tool.function === null,\n );\n if (nullFunctionIndex !== -1) {\n shapeError = `tools[${nullFunctionIndex}].function must be an object`;\n }\n }\n if (shapeError) {\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: ${shapeError}`,\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 completionReq._context = getContext(req);\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n // Record mode proxies on a miss to capture a fresh turn (see record gate\n // below), so keep turnIndex strict to prevent an earlier-turn fixture from\n // shadowing a longer request and skipping the new turn's recording.\n recordMatchOptions(!!defaults.record, defaults.logger),\n );\n\n if (fixture) {\n 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 await applyChaosAsync(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\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 const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictStatus = 503;\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n logger.error(\n strictNoMatchLogLine(req.method ?? \"POST\", req.url ?? \"/v2/chat\", skippedBySequenceOrTurn),\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: {\n status: strictStatus,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\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 === \"handled_by_hook\") return;\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 journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n const resolvedResponse = await resolveResponse(fixture, completionReq);\n const misbehavior = planMisbehavior({\n wire: \"cohere\",\n fixture,\n response: resolvedResponse,\n request: completionReq,\n stream: cohereReq.stream === true,\n emitsToolCallIds: true,\n defaults,\n rawHeaders: req.headers,\n url: req.url,\n });\n if (misbehavior.kind === \"error\") {\n const entry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/chat\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: misbehavior.status, fixture },\n });\n recordMisbehaviorOutcome({ entry, summary: misbehavior.summary, defaults, testId });\n if (!misbehavior.summary?.evaluations.length) logger.error(misbehavior.message);\n writeErrorResponse(\n res,\n misbehavior.status,\n JSON.stringify({ message: misbehavior.message, code: misbehavior.code }),\n );\n return;\n }\n // Cohere carries the same raw argument strings and call identities as Chat.\n // Reuse the accepted preparation so generated/duplicate IDs match metadata.\n const prepared =\n misbehavior.kind === \"applied\" ? prepareOpenAIChatMisbehavior(misbehavior) : undefined;\n const observedK5Stream =\n cohereReq.stream === true && prepared?.summary.fault === \"stop-length-mid-tool\";\n const appliedReasoning =\n prepared && \"reasoning\" in prepared.response\n ? resolveReasoningForModel(\n prepared.response.reasoning,\n cohereReq.model,\n resolveStrictMode(defaults.strict, req.headers),\n logger,\n )\n : undefined;\n const usage = prepared\n ? resolveOpenAIChatMisbehaviorUsage(prepared, completionReq, appliedReasoning !== undefined)\n : undefined;\n const response =\n prepared && usage\n ? {\n ...prepared.response,\n usage,\n ...(prepared.stop\n ? { finishReason: observedK5Stream ? \"tool_calls\" : prepared.stop }\n : {}),\n }\n : resolvedResponse;\n const summary = prepared?.summary ?? misbehavior.summary;\n const empty = prepared?.summary.fault === \"empty-response\";\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 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, fixture },\n });\n recordMisbehaviorOutcome({\n entry: journalEntry,\n summary,\n defaults,\n testId,\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n // Content + tool calls response (must be checked before text/tool-only branches)\n if (isCombinedFixtureResponse(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 effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = prepared\n ? appliedReasoning\n : resolveReasoningForModel(response.reasoning, cohereReq.model, effectiveStrict, logger);\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 recordMisbehaviorOutcome({\n entry: journalEntry,\n summary,\n defaults,\n testId,\n });\n const functionToolCalls = requireEmittedFunctionToolCalls(response, \"Cohere\");\n if (cohereReq.stream !== true) {\n const body = buildCohereContentWithToolCallsResponse(\n response.content ?? \"\",\n functionToolCalls,\n logger,\n effReasoning,\n overrides,\n response.blocks,\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 functionToolCalls,\n chunkSize,\n logger,\n effReasoning,\n overrides,\n response.blocks,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeCohereSSEStream(res, events, {\n terminalSentinel: observedK5Stream,\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\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 effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = prepared\n ? appliedReasoning\n : resolveReasoningForModel(response.reasoning, cohereReq.model, effectiveStrict, logger);\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 recordMisbehaviorOutcome({\n entry: journalEntry,\n summary,\n defaults,\n testId,\n });\n if (cohereReq.stream !== true) {\n const body = empty\n ? {\n ...buildCohereTextResponse(\"\", undefined, overrides),\n message: {\n role: \"assistant\",\n content: [],\n tool_calls: [],\n tool_plan: \"\",\n citations: [],\n },\n }\n : buildCohereTextResponse(response.content, effReasoning, 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 effReasoning,\n overrides,\n ).filter((event) => !empty || event.type === \"message-start\" || event.type === \"message-end\");\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeCohereSSEStream(res, events, {\n terminalSentinel: observedK5Stream,\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\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 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 effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = prepared\n ? appliedReasoning\n : resolveReasoningForModel(response.reasoning, cohereReq.model, effectiveStrict, logger);\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 recordMisbehaviorOutcome({\n entry: journalEntry,\n summary,\n defaults,\n testId,\n });\n const functionToolCalls = requireEmittedFunctionToolCalls(response, \"Cohere\");\n if (cohereReq.stream !== true) {\n const body = buildCohereToolCallResponse(functionToolCalls, logger, effReasoning, overrides);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildCohereToolCallStreamEvents(\n functionToolCalls,\n chunkSize,\n logger,\n effReasoning,\n overrides,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeCohereSSEStream(res, events, {\n terminalSentinel: observedK5Stream,\n latency,\n streamingProfile: fixture.streamingProfile,\n recordedTimings: fixture.recordedTimings,\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\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 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: 500, fixture },\n });\n recordMisbehaviorOutcome({ entry: journalEntry, summary, defaults, testId });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response did not match any known type\",\n type: \"server_error\",\n },\n }),\n );\n}\n\n// ─── Cohere v2 Embed API types ────────────────────────────────────────────\n\ninterface CohereEmbedRequest {\n texts: string[];\n model: string;\n input_type?: string;\n embedding_types?: string[];\n truncate?: string;\n}\n\ninterface CohereEmbedResponse {\n id: string;\n texts: string[];\n embeddings: Record<string, number[][]>;\n meta: { api_version: { version: string } };\n}\n\n// ─── Cohere Embed handler ─────────────────────────────────────────────────\n\nexport async function handleCohereEmbed(\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 embedReq: CohereEmbedRequest;\n try {\n embedReq = JSON.parse(raw) as CohereEmbedRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\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 body: ${detail}`,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Reject non-object bodies (e.g. `null`) before touching fields —\n // otherwise `embedReq.model` throws a TypeError that surfaces as a 500\n // instead of a 400.\n if (!isJsonObject(embedReq)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\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: \"Request body must be a JSON object\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Validate required fields\n if (!embedReq.model) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\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 (!embedReq.texts || !Array.isArray(embedReq.texts)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\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: texts array is required\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Every text must be a string — a number reaches createHash().update() in\n // the no-fixture fallback and throws a TypeError (500) instead of a 400.\n if (!embedReq.texts.every((text) => typeof text === \"string\")) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\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: texts must be an array of strings\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Concatenate all texts for fixture matching\n const combinedInput = embedReq.texts.join(\" \");\n\n // Build a synthetic ChatCompletionRequest for the fixture router\n const syntheticReq: ChatCompletionRequest = {\n model: embedReq.model,\n messages: [],\n embeddingInput: combinedInput,\n _endpointType: \"embedding\",\n _context: getContext(req),\n };\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n // Record mode proxies on a miss to capture a fresh turn (see record gate\n // below), so keep turnIndex strict to prevent an earlier-turn fixture from\n // shadowing a longer request and skipping the new turn's recording.\n recordMatchOptions(!!defaults.record, defaults.logger),\n );\n\n if (fixture) {\n 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 await applyChaosAsync(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n {\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n // Determine requested embedding types (default to float)\n const embeddingTypes =\n embedReq.embedding_types && embedReq.embedding_types.length > 0\n ? embedReq.embedding_types\n : [\"float\"];\n\n function rejectInvalidEmbeddingTypes(): boolean {\n if (embedReq.embedding_types == null) return false;\n const isArray = Array.isArray(embedReq.embedding_types);\n if (isArray && embedReq.embedding_types.every((type) => typeof type === \"string\")) return false;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 400, fixture: fixture ?? null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: isArray\n ? \"Invalid request: embedding_types must be an array of strings\"\n : \"Invalid request: embedding_types must be an array\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return true;\n }\n\n if (fixture) {\n const response = await resolveResponse(fixture, syntheticReq);\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/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n // Embedding response — use the fixture's embedding for each input text\n if (isEmbeddingResponse(response)) {\n if (rejectInvalidEmbeddingTypes()) return;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n const vectors = embedReq.texts.map(() => [...response.embedding]);\n const embeddings: Record<string, number[][]> = {};\n for (const t of embeddingTypes) {\n embeddings[t] = vectors;\n }\n const body: CohereEmbedResponse = {\n id: generateMessageId(),\n texts: embedReq.texts,\n embeddings,\n meta: { api_version: { version: \"2\" } },\n };\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n return;\n }\n\n // Fixture matched but response type is not compatible with embeddings\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message:\n \"Fixture response did not match any known embedding type (must have embedding or error)\",\n type: \"server_error\",\n },\n }),\n );\n return;\n }\n\n // No fixture match — check strict mode\n if (resolveStrictMode(defaults.strict, req.headers)) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n logger.error(\n strictNoMatchLogLine(req.method ?? \"POST\", req.url ?? \"/v2/embed\", skippedBySequenceOrTurn),\n );\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Try record-and-replay proxy\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"cohere\",\n req.url ?? \"/v2/embed\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n if (rejectInvalidEmbeddingTypes()) return;\n\n // No fixture match — generate deterministic embeddings from input texts\n logger.warn(\n `No embedding fixture matched for \"${combinedInput.slice(0, 80)}\" — returning deterministic fallback`,\n );\n const dimensions = 1024; // Cohere embed-v4.0 default\n const vectors = embedReq.texts.map((text) => generateDeterministicEmbedding(text, dimensions));\n const embeddings: Record<string, number[][]> = {};\n for (const t of embeddingTypes) {\n embeddings[t] = vectors;\n }\n\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v2/embed\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture: null },\n });\n\n const body: CohereEmbedResponse = {\n id: generateMessageId(),\n texts: embedReq.texts,\n embeddings,\n meta: { api_version: { version: \"2\" } },\n };\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n}\n"],"mappings":"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"}
@@ -2,8 +2,11 @@ const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
2
2
  const require_api_key_auth = require('./api-key-auth.cjs');
3
3
  const require_a2a_mock = require('./a2a-mock.cjs');
4
4
  const require_agui_handler = require('./agui-handler.cjs');
5
+ const require_misbehavior = require('./misbehavior.cjs');
5
6
  const require_logger = require('./logger.cjs');
6
7
  const require_agui_mock = require('./agui-mock.cjs');
8
+ const require_mcp_handler = require('./mcp-handler.cjs');
9
+ const require_mcp_recorder = require('./mcp-recorder.cjs');
7
10
  const require_mcp_mock = require('./mcp-mock.cjs');
8
11
  const require_llmock = require('./llmock.cjs');
9
12
  const require_vector_mock = require('./vector-mock.cjs');
@@ -13,12 +16,46 @@ let node_path = require("node:path");
13
16
  node_path = require_runtime.__toESM(node_path);
14
17
 
15
18
  //#region src/config-loader.ts
19
+ /** C10: the LLM part of `llm.record`. `mcp` is MCP-only; no `providers` means no LLM recording. */
20
+ function llmRecordOf(record) {
21
+ if (!record) return void 0;
22
+ const { mcp: _mcp, ...llm } = record;
23
+ return llm.providers === void 0 ? void 0 : llm;
24
+ }
16
25
  function loadConfig(configPath) {
17
26
  const raw = node_fs.readFileSync(configPath, "utf-8");
18
27
  return JSON.parse(raw);
19
28
  }
29
+ /** C3: `llm.record.mcp` is an object with at least one mount. */
30
+ function hasMcpRecordMount(mcp) {
31
+ return typeof mcp === "object" && mcp !== null && !Array.isArray(mcp) && Object.keys(mcp).length > 0;
32
+ }
20
33
  async function startFromConfig(config, overrides) {
21
34
  const logger = new require_logger.Logger("info");
35
+ const booleanOptIn = (key) => {
36
+ const value = config.llm?.[key];
37
+ if (value === void 0 || typeof value === "boolean") return value;
38
+ logger.warn(`Ignoring llm.${key} because it must be true or false, got ${JSON.stringify(value)}.`);
39
+ };
40
+ const configEnableMisbehavior = booleanOptIn("enableMisbehavior");
41
+ const configStrictToolArguments = booleanOptIn("strictToolArguments");
42
+ const enableMcpRecording = booleanOptIn("enableMcpRecording") === true;
43
+ const mcpRecord = enableMcpRecording ? config.llm?.record?.mcp : void 0;
44
+ const enableMisbehavior = (overrides?.enableMisbehavior ?? configEnableMisbehavior) === true;
45
+ let misbehavior;
46
+ if (config.llm?.misbehavior !== void 0) if (!enableMisbehavior) logger.warn("Ignoring llm.misbehavior because misbehavior is not enabled. Set llm.enableMisbehavior: true or pass --misbehavior to use it.");
47
+ else {
48
+ const parsed = require_misbehavior.parseMisbehavior(config.llm.misbehavior, "llm.misbehavior");
49
+ if (!parsed.ok) throw new TypeError(`${parsed.issue.rule}: ${parsed.issue.path}: ${parsed.issue.message}`);
50
+ misbehavior = parsed.config;
51
+ }
52
+ if (config.llm?.record?.mcp !== void 0 && !enableMcpRecording) logger.warn("Ignoring llm.record.mcp because MCP recording is not enabled. Set llm.enableMcpRecording: true to use it.");
53
+ let responsesTools = config.llm?.responsesTools;
54
+ if (responsesTools !== void 0 && responsesTools !== "legacy" && responsesTools !== "extended") {
55
+ const effective = overrides?.responsesTools !== void 0 ? `"${overrides.responsesTools}" from --responses-tools` : "\"legacy\"";
56
+ logger.warn(`Ignoring llm.responsesTools because it must be "legacy" or "extended", got ${JSON.stringify(responsesTools)}. Using ${effective}.`);
57
+ responsesTools = void 0;
58
+ }
22
59
  let replaySpeed = config.llm?.replaySpeed;
23
60
  if (replaySpeed != null && (!Number.isFinite(replaySpeed) || replaySpeed <= 0)) {
24
61
  logger.warn(`llm.replaySpeed must be a positive number, got ${replaySpeed}. Ignoring.`);
@@ -31,12 +68,17 @@ async function startFromConfig(config, overrides) {
31
68
  latency: config.llm?.latency,
32
69
  chunkSize: config.llm?.chunkSize,
33
70
  replaySpeed,
34
- logLevel: config.llm?.logLevel,
71
+ logLevel: config.llm?.logLevel ?? (hasMcpRecordMount(mcpRecord) ? "warn" : void 0),
35
72
  chaos: config.llm?.chaos,
36
- record: config.llm?.record,
73
+ misbehavior,
74
+ ...enableMisbehavior ? { enableMisbehavior: true } : {},
75
+ record: llmRecordOf(config.llm?.record),
37
76
  metrics: config.metrics,
38
- strict: config.strict
77
+ strict: config.strict,
78
+ strictToolArguments: overrides?.strictToolArguments ?? configStrictToolArguments,
79
+ responsesTools: overrides?.responsesTools ?? responsesTools
39
80
  }, resolvedAuth);
81
+ const configMounts = /* @__PURE__ */ new Map();
40
82
  if (config.llm?.fixtures) {
41
83
  const fixturePath = node_path.resolve(config.llm.fixtures);
42
84
  if (node_fs.statSync(fixturePath).isDirectory()) llmock.loadFixtureDir(fixturePath);
@@ -48,7 +90,11 @@ async function startFromConfig(config, overrides) {
48
90
  if (mcpConfig.tools) for (const tool of mcpConfig.tools) {
49
91
  const { result, ...def } = tool;
50
92
  mcp.addTool(def);
51
- if (result !== void 0) mcp.onToolCall(def.name, () => result);
93
+ if (result !== void 0) {
94
+ const answer = () => result;
95
+ require_mcp_handler.configToolHandlers.add(answer);
96
+ mcp.onToolCall(def.name, answer);
97
+ }
52
98
  }
53
99
  if (mcpConfig.resources) for (const res of mcpConfig.resources) mcp.addResource({
54
100
  uri: res.uri,
@@ -67,6 +113,7 @@ async function startFromConfig(config, overrides) {
67
113
  }
68
114
  const mcpPath = mcpConfig.path ?? "/mcp";
69
115
  llmock.mount(mcpPath, mcp);
116
+ configMounts.set(mcpPath, mcp);
70
117
  logger.info(`MCPMock mounted at ${mcpPath}`);
71
118
  }
72
119
  if (config.a2a) {
@@ -81,6 +128,7 @@ async function startFromConfig(config, overrides) {
81
128
  }
82
129
  const a2aPath = a2aConfig.path ?? "/a2a";
83
130
  llmock.mount(a2aPath, a2a);
131
+ configMounts.set(a2aPath, a2a);
84
132
  logger.info(`A2AMock mounted at ${a2aPath}`);
85
133
  }
86
134
  if (config.agui) {
@@ -112,6 +160,7 @@ async function startFromConfig(config, overrides) {
112
160
  }
113
161
  const aguiPath = aguiConfig.path ?? "/agui";
114
162
  llmock.mount(aguiPath, agui);
163
+ configMounts.set(aguiPath, agui);
115
164
  logger.info(`AGUIMock mounted at ${aguiPath}`);
116
165
  }
117
166
  if (config.vector) {
@@ -124,8 +173,17 @@ async function startFromConfig(config, overrides) {
124
173
  }
125
174
  const vectorPath = vectorConfig.path ?? "/vector";
126
175
  llmock.mount(vectorPath, vector);
176
+ configMounts.set(vectorPath, vector);
127
177
  logger.info(`VectorMock mounted at ${vectorPath}`);
128
178
  }
179
+ if (mcpRecord !== void 0) require_mcp_recorder.wireMcpRecording(llmock, mcpRecord, {
180
+ mounted: configMounts,
181
+ mcpMock: require_mcp_mock.MCPMock,
182
+ fixtures: config.llm?.fixtures,
183
+ fixturePath: config.llm?.record?.fixturePath,
184
+ strict: config.strict,
185
+ env: process.env
186
+ });
129
187
  if (config.services) {
130
188
  if (config.services.search) {
131
189
  llmock.onSearch(/.*/, []);
@@ -1 +1 @@
1
- {"version":3,"file":"config-loader.cjs","names":["fs","Logger","resolveInboundAuth","selectInboundAuthSource","createLLMockWithResolvedAuth","path","MCPMock","A2AMock","AGUIMock","buildTextResponse","VectorMock"],"sources":["../src/config-loader.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { LLMock, createLLMockWithResolvedAuth } from \"./llmock.js\";\nimport { resolveInboundAuth, selectInboundAuthSource } from \"./api-key-auth.js\";\nimport { MCPMock } from \"./mcp-mock.js\";\nimport { A2AMock } from \"./a2a-mock.js\";\nimport { AGUIMock } from \"./agui-mock.js\";\nimport type { ApiKeyAuthConfig, ChaosConfig, RecordConfig } from \"./types.js\";\nimport type { MCPToolDefinition, MCPPromptDefinition } from \"./mcp-types.js\";\nimport type { A2AAgentDefinition, A2APart, A2AArtifact, A2AStreamEvent } from \"./a2a-types.js\";\nimport type { AGUIEvent } from \"./agui-types.js\";\nimport { buildTextResponse } from \"./agui-handler.js\";\nimport { VectorMock } from \"./vector-mock.js\";\nimport type { QueryResult } from \"./vector-types.js\";\nimport { Logger } from \"./logger.js\";\n\nexport interface MCPConfigTool extends MCPToolDefinition {\n result?: string;\n}\n\nexport interface MCPConfigResource {\n uri: string;\n name: string;\n mimeType?: string;\n description?: string;\n text?: string;\n blob?: string;\n}\n\nexport interface MCPConfigPrompt extends MCPPromptDefinition {\n result?: {\n messages: Array<{ role: string; content: { type: string; text: string } }>;\n };\n}\n\nexport interface MCPConfig {\n path?: string;\n serverInfo?: { name: string; version: string };\n tools?: MCPConfigTool[];\n resources?: MCPConfigResource[];\n prompts?: MCPConfigPrompt[];\n}\n\nexport interface A2AConfigPattern {\n pattern: string;\n parts?: A2APart[];\n artifacts?: A2AArtifact[];\n events?: A2AStreamEvent[];\n delayMs?: number;\n}\n\nexport interface A2AConfigAgent extends A2AAgentDefinition {\n messages?: A2AConfigPattern[];\n tasks?: A2AConfigPattern[];\n streamingTasks?: A2AConfigPattern[];\n}\n\nexport interface A2AConfig {\n path?: string;\n agents?: A2AConfigAgent[];\n}\n\nexport interface AGUIConfigFixture {\n match: { message?: string; toolCallId?: string; toolName?: string; stateKey?: string };\n text?: string; // shorthand: uses buildTextResponse\n events?: AGUIEvent[]; // raw events\n delayMs?: number;\n}\n\nexport interface AGUIConfig {\n path?: string; // mount path, default \"/agui\"\n fixtures?: AGUIConfigFixture[];\n}\n\nexport interface VectorConfigCollection {\n name: string;\n dimension: number;\n vectors?: Array<{\n id: string;\n values: number[];\n metadata?: Record<string, unknown>;\n }>;\n queryResults?: QueryResult[];\n}\n\nexport interface VectorConfig {\n path?: string;\n collections?: VectorConfigCollection[];\n}\n\nexport interface AimockConfig {\n auth?: ApiKeyAuthConfig;\n llm?: {\n fixtures?: string;\n latency?: number;\n chunkSize?: number;\n replaySpeed?: number;\n logLevel?: \"silent\" | \"warn\" | \"info\" | \"debug\";\n chaos?: ChaosConfig;\n record?: RecordConfig;\n };\n mcp?: MCPConfig;\n a2a?: A2AConfig;\n agui?: AGUIConfig;\n vector?: VectorConfig;\n services?: { search?: boolean; rerank?: boolean; moderate?: boolean };\n metrics?: boolean;\n strict?: boolean;\n port?: number;\n host?: string;\n}\n\nexport function loadConfig(configPath: string): AimockConfig {\n const raw = fs.readFileSync(configPath, \"utf-8\");\n return JSON.parse(raw) as AimockConfig;\n}\n\nexport async function startFromConfig(\n config: AimockConfig,\n overrides?: { port?: number; host?: string },\n): Promise<{ llmock: LLMock; url: string }> {\n const logger = new Logger(\"info\");\n\n // A non-positive replaySpeed fails calculateDelay's `speed > 0` check and applies the\n // full delay rather than none. Mirrors the fixture-level guard in fixture-loader.ts.\n let replaySpeed = config.llm?.replaySpeed;\n if (replaySpeed != null && (!Number.isFinite(replaySpeed) || replaySpeed <= 0)) {\n logger.warn(`llm.replaySpeed must be a positive number, got ${replaySpeed}. Ignoring.`);\n replaySpeed = undefined;\n }\n\n // Load fixtures if specified\n const resolvedAuth = resolveInboundAuth(selectInboundAuthSource(config.auth));\n const llmock = createLLMockWithResolvedAuth(\n {\n port: overrides?.port ?? config.port ?? 0,\n host: overrides?.host ?? config.host ?? \"127.0.0.1\",\n latency: config.llm?.latency,\n chunkSize: config.llm?.chunkSize,\n replaySpeed,\n logLevel: config.llm?.logLevel,\n chaos: config.llm?.chaos,\n record: config.llm?.record,\n metrics: config.metrics,\n strict: config.strict,\n },\n resolvedAuth,\n );\n\n if (config.llm?.fixtures) {\n const fixturePath = path.resolve(config.llm.fixtures);\n const stat = fs.statSync(fixturePath);\n if (stat.isDirectory()) {\n llmock.loadFixtureDir(fixturePath);\n } else {\n llmock.loadFixtureFile(fixturePath);\n }\n }\n\n // MCP\n if (config.mcp) {\n const mcpConfig = config.mcp;\n const mcp = new MCPMock({\n serverInfo: mcpConfig.serverInfo,\n });\n\n if (mcpConfig.tools) {\n for (const tool of mcpConfig.tools) {\n const { result, ...def } = tool;\n mcp.addTool(def);\n if (result !== undefined) {\n mcp.onToolCall(def.name, () => result);\n }\n }\n }\n\n if (mcpConfig.resources) {\n for (const res of mcpConfig.resources) {\n mcp.addResource(\n { uri: res.uri, name: res.name, mimeType: res.mimeType, description: res.description },\n res.text !== undefined || res.blob !== undefined\n ? { text: res.text, blob: res.blob, mimeType: res.mimeType }\n : undefined,\n );\n }\n }\n\n if (mcpConfig.prompts) {\n for (const prompt of mcpConfig.prompts) {\n const { result, ...def } = prompt;\n if (result) {\n mcp.addPrompt(def, () => result as import(\"./mcp-types.js\").MCPPromptResult);\n } else {\n mcp.addPrompt(def);\n }\n }\n }\n\n const mcpPath = mcpConfig.path ?? \"/mcp\";\n llmock.mount(mcpPath, mcp);\n logger.info(`MCPMock mounted at ${mcpPath}`);\n }\n\n // A2A\n if (config.a2a) {\n const a2aConfig = config.a2a;\n const a2a = new A2AMock();\n\n if (a2aConfig.agents) {\n for (const agentConfig of a2aConfig.agents) {\n const { messages, tasks, streamingTasks, ...def } = agentConfig;\n a2a.registerAgent(def);\n\n if (messages) {\n for (const m of messages) {\n a2a.onMessage(def.name, m.pattern, m.parts ?? [{ text: \"\" }]);\n }\n }\n\n if (tasks) {\n for (const t of tasks) {\n a2a.onTask(def.name, t.pattern, t.artifacts ?? []);\n }\n }\n\n if (streamingTasks) {\n for (const s of streamingTasks) {\n a2a.onStreamingTask(def.name, s.pattern, s.events ?? [], s.delayMs);\n }\n }\n }\n }\n\n const a2aPath = a2aConfig.path ?? \"/a2a\";\n llmock.mount(a2aPath, a2a);\n logger.info(`A2AMock mounted at ${a2aPath}`);\n }\n\n // AG-UI\n if (config.agui) {\n const aguiConfig = config.agui;\n const agui = new AGUIMock();\n\n if (aguiConfig.fixtures) {\n for (const f of aguiConfig.fixtures) {\n if (f.match.toolCallId && f.text && !f.events) {\n logger.warn(\n `AG-UI fixture uses text shorthand with toolCallId — text shorthand ignores toolCallId matching; use events[] instead (match: ${JSON.stringify(f.match)})`,\n );\n }\n if (f.text) {\n if (f.match.message !== undefined) {\n agui.onMessage(f.match.message, f.text, { delayMs: f.delayMs });\n } else {\n // No message pattern — register via addFixture so it only matches\n // on other criteria (toolCallId, toolName, stateKey) instead of\n // becoming a catch-all that matches every request.\n agui.addFixture({\n match: {\n toolCallId: f.match.toolCallId,\n toolName: f.match.toolName,\n stateKey: f.match.stateKey,\n },\n events: buildTextResponse(f.text),\n delayMs: f.delayMs,\n });\n }\n } else if (f.events) {\n agui.addFixture({\n match: {\n message: f.match.message,\n toolCallId: f.match.toolCallId,\n toolName: f.match.toolName,\n stateKey: f.match.stateKey,\n },\n events: f.events,\n delayMs: f.delayMs,\n });\n } else {\n logger.warn(\n `AG-UI fixture has neither text nor events — it will be skipped (match: ${JSON.stringify(f.match)})`,\n );\n }\n }\n }\n\n const aguiPath = aguiConfig.path ?? \"/agui\";\n llmock.mount(aguiPath, agui);\n logger.info(`AGUIMock mounted at ${aguiPath}`);\n }\n\n // Vector\n if (config.vector) {\n const vectorConfig = config.vector;\n const vector = new VectorMock();\n\n if (vectorConfig.collections) {\n for (const col of vectorConfig.collections) {\n vector.addCollection(col.name, { dimension: col.dimension });\n\n if (col.vectors && col.vectors.length > 0) {\n vector.upsert(col.name, col.vectors);\n }\n\n if (col.queryResults) {\n vector.onQuery(col.name, col.queryResults);\n }\n }\n }\n\n const vectorPath = vectorConfig.path ?? \"/vector\";\n llmock.mount(vectorPath, vector);\n logger.info(`VectorMock mounted at ${vectorPath}`);\n }\n\n // Services — configure default catch-all responses\n if (config.services) {\n if (config.services.search) {\n llmock.onSearch(/.*/, []);\n logger.info(\"Search service enabled with default empty results\");\n }\n if (config.services.rerank) {\n llmock.onRerank(/.*/, []);\n logger.info(\"Rerank service enabled with default empty results\");\n }\n if (config.services.moderate) {\n llmock.onModerate(/.*/, { flagged: false, categories: {} });\n logger.info(\"Moderation service enabled with default unflagged results\");\n }\n }\n\n const url = await llmock.start();\n return { llmock, url };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"config-loader.cjs","names":["fs","Logger","parseMisbehavior","resolveInboundAuth","selectInboundAuthSource","createLLMockWithResolvedAuth","path","MCPMock","A2AMock","AGUIMock","buildTextResponse","VectorMock"],"sources":["../src/config-loader.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { LLMock, createLLMockWithResolvedAuth } from \"./llmock.js\";\nimport { resolveInboundAuth, selectInboundAuthSource } from \"./api-key-auth.js\";\nimport { MCPMock } from \"./mcp-mock.js\";\nimport { configToolHandlers } from \"./mcp-handler.js\";\nimport { A2AMock } from \"./a2a-mock.js\";\nimport { AGUIMock } from \"./agui-mock.js\";\nimport type {\n ApiKeyAuthConfig,\n ChaosConfig,\n McpRecordConfig,\n MisbehaviorConfig,\n MisbehaviorFaultId,\n Mountable,\n RecordConfig,\n ResponsesToolsMode,\n} from \"./types.js\";\nimport { parseMisbehavior } from \"./misbehavior.js\";\nimport type { MCPToolDefinition, MCPPromptDefinition } from \"./mcp-types.js\";\nimport type { A2AAgentDefinition, A2APart, A2AArtifact, A2AStreamEvent } from \"./a2a-types.js\";\nimport type { AGUIEvent } from \"./agui-types.js\";\nimport { buildTextResponse } from \"./agui-handler.js\";\nimport { VectorMock } from \"./vector-mock.js\";\nimport type { QueryResult } from \"./vector-types.js\";\nimport { Logger } from \"./logger.js\";\nimport { wireMcpRecording } from \"./mcp-recorder.js\";\n\nexport interface MCPConfigTool extends MCPToolDefinition {\n result?: string;\n}\n\nexport interface MCPConfigResource {\n uri: string;\n name: string;\n mimeType?: string;\n description?: string;\n text?: string;\n blob?: string;\n}\n\nexport interface MCPConfigPrompt extends MCPPromptDefinition {\n result?: {\n messages: Array<{ role: string; content: { type: string; text: string } }>;\n };\n}\n\nexport interface MCPConfig {\n path?: string;\n serverInfo?: { name: string; version: string };\n tools?: MCPConfigTool[];\n resources?: MCPConfigResource[];\n prompts?: MCPConfigPrompt[];\n}\n\nexport interface A2AConfigPattern {\n pattern: string;\n parts?: A2APart[];\n artifacts?: A2AArtifact[];\n events?: A2AStreamEvent[];\n delayMs?: number;\n}\n\nexport interface A2AConfigAgent extends A2AAgentDefinition {\n messages?: A2AConfigPattern[];\n tasks?: A2AConfigPattern[];\n streamingTasks?: A2AConfigPattern[];\n}\n\nexport interface A2AConfig {\n path?: string;\n agents?: A2AConfigAgent[];\n}\n\nexport interface AGUIConfigFixture {\n match: { message?: string; toolCallId?: string; toolName?: string; stateKey?: string };\n text?: string; // shorthand: uses buildTextResponse\n events?: AGUIEvent[]; // raw events\n delayMs?: number;\n}\n\nexport interface AGUIConfig {\n path?: string; // mount path, default \"/agui\"\n fixtures?: AGUIConfigFixture[];\n}\n\nexport interface VectorConfigCollection {\n name: string;\n dimension: number;\n vectors?: Array<{\n id: string;\n values: number[];\n metadata?: Record<string, unknown>;\n }>;\n queryResults?: QueryResult[];\n}\n\nexport interface VectorConfig {\n path?: string;\n collections?: VectorConfigCollection[];\n}\n\n/** `llm.record` in a config file: the LLM `RecordConfig`, plus MCP record mounts (C10). */\nexport interface AimockRecordConfig extends RecordConfig {\n /** MR1: mount path → upstream URL, or a full MCP record config. */\n mcp?: Record<string, string | McpRecordConfig>;\n}\n\nexport interface AimockConfig {\n auth?: ApiKeyAuthConfig;\n llm?: {\n fixtures?: string;\n latency?: number;\n chunkSize?: number;\n replaySpeed?: number;\n logLevel?: \"silent\" | \"warn\" | \"info\" | \"debug\";\n chaos?: ChaosConfig;\n /**\n * Server-wide misbehavior defaults. Read only when misbehavior is enabled\n * (`llm.enableMisbehavior: true` or `aimock --misbehavior`); otherwise the\n * key is ignored with a warning, as 1.44.0 ignored it.\n */\n misbehavior?: MisbehaviorConfig | MisbehaviorFaultId;\n /** See `MockServerOptions.enableMisbehavior`. */\n enableMisbehavior?: boolean;\n record?: AimockRecordConfig;\n /**\n * Turns on `llm.record.mcp`. Without it the key is ignored with a warning,\n * as 1.44.0 ignored it.\n */\n enableMcpRecording?: boolean;\n /** See `MockServerOptions.strictToolArguments`. */\n strictToolArguments?: boolean;\n /** See `MockServerOptions.responsesTools`. */\n responsesTools?: ResponsesToolsMode;\n };\n mcp?: MCPConfig;\n a2a?: A2AConfig;\n agui?: AGUIConfig;\n vector?: VectorConfig;\n services?: { search?: boolean; rerank?: boolean; moderate?: boolean };\n metrics?: boolean;\n strict?: boolean;\n port?: number;\n host?: string;\n}\n\n/** C10: the LLM part of `llm.record`. `mcp` is MCP-only; no `providers` means no LLM recording. */\nfunction llmRecordOf(record: AimockRecordConfig | undefined): RecordConfig | undefined {\n if (!record) return undefined;\n const { mcp: _mcp, ...llm } = record;\n void _mcp; // repo pattern for an intentionally unused binding (byteplus-video.ts:1379-1380)\n return llm.providers === undefined ? undefined : llm;\n}\n\nexport function loadConfig(configPath: string): AimockConfig {\n const raw = fs.readFileSync(configPath, \"utf-8\");\n return JSON.parse(raw) as AimockConfig;\n}\n\n/** C3: `llm.record.mcp` is an object with at least one mount. */\nfunction hasMcpRecordMount(mcp: unknown): boolean {\n return (\n typeof mcp === \"object\" && mcp !== null && !Array.isArray(mcp) && Object.keys(mcp).length > 0\n );\n}\n\n/**\n * Command-line overrides for `startFromConfig`. The opt-in flags win over the\n * matching `llm.*` config keys.\n */\nexport interface StartFromConfigOverrides {\n port?: number;\n host?: string;\n /** `aimock --misbehavior`: overrides `llm.enableMisbehavior`. */\n enableMisbehavior?: boolean;\n /** `aimock --strict-tool-arguments`: overrides `llm.strictToolArguments`. */\n strictToolArguments?: boolean;\n /** `aimock --responses-tools`: overrides `llm.responsesTools`. */\n responsesTools?: ResponsesToolsMode;\n}\n\nexport async function startFromConfig(\n config: AimockConfig,\n overrides?: StartFromConfigOverrides,\n): Promise<{ llmock: LLMock; url: string }> {\n const logger = new Logger(\"info\");\n // 1.44.0 ignored these keys, so a non-boolean value (such as the string\n // \"true\") is ignored with a warning, as `llm.misbehavior` is, and the\n // option stays off unless a CLI flag turns it on (`llm.enableMcpRecording`\n // has no CLI flag).\n const booleanOptIn = (\n key: \"enableMisbehavior\" | \"enableMcpRecording\" | \"strictToolArguments\",\n ): boolean | undefined => {\n const value: unknown = config.llm?.[key];\n if (value === undefined || typeof value === \"boolean\") return value;\n logger.warn(\n `Ignoring llm.${key} because it must be true or false, got ${JSON.stringify(value)}.`,\n );\n return undefined;\n };\n const configEnableMisbehavior = booleanOptIn(\"enableMisbehavior\");\n const configStrictToolArguments = booleanOptIn(\"strictToolArguments\");\n // MCP recording also needs an explicit opt-in. 1.44.0 ignored\n // `llm.record.mcp`, so without `llm.enableMcpRecording: true` the key is\n // ignored (with a warning): nothing is mounted or validated and the log level\n // is unchanged. With the opt-in, an invalid value fails startup.\n const enableMcpRecording = booleanOptIn(\"enableMcpRecording\") === true;\n const mcpRecord = enableMcpRecording ? config.llm?.record?.mcp : undefined;\n // Misbehavior needs an explicit opt-in that a 1.44.0 config cannot contain.\n // 1.44.0 ignored `llm.misbehavior`, so without the opt-in the key is ignored\n // (with a warning) and the server serves exactly what 1.44.0 served. With the\n // opt-in, an invalid value fails startup like any other enabled-mode error.\n const enableMisbehavior = (overrides?.enableMisbehavior ?? configEnableMisbehavior) === true;\n let misbehavior: MisbehaviorConfig | undefined;\n if (config.llm?.misbehavior !== undefined) {\n if (!enableMisbehavior) {\n logger.warn(\n \"Ignoring llm.misbehavior because misbehavior is not enabled. Set llm.enableMisbehavior: true or pass --misbehavior to use it.\",\n );\n } else {\n const parsed = parseMisbehavior(config.llm.misbehavior, \"llm.misbehavior\");\n if (!parsed.ok) {\n throw new TypeError(`${parsed.issue.rule}: ${parsed.issue.path}: ${parsed.issue.message}`);\n }\n misbehavior = parsed.config;\n }\n }\n if (config.llm?.record?.mcp !== undefined && !enableMcpRecording) {\n logger.warn(\n \"Ignoring llm.record.mcp because MCP recording is not enabled. Set llm.enableMcpRecording: true to use it.\",\n );\n }\n\n // 1.44.0 ignored `llm.responsesTools`, so an invalid value is ignored with a\n // warning (as `llm.misbehavior` is) and the server runs in \"legacy\" mode,\n // unless `--responses-tools` sets the mode. The warning names the mode that\n // actually runs.\n let responsesTools = config.llm?.responsesTools;\n if (\n responsesTools !== undefined &&\n responsesTools !== \"legacy\" &&\n responsesTools !== \"extended\"\n ) {\n const effective =\n overrides?.responsesTools !== undefined\n ? `\"${overrides.responsesTools}\" from --responses-tools`\n : '\"legacy\"';\n logger.warn(\n `Ignoring llm.responsesTools because it must be \"legacy\" or \"extended\", got ${JSON.stringify(responsesTools)}. Using ${effective}.`,\n );\n responsesTools = undefined;\n }\n\n // A non-positive replaySpeed fails calculateDelay's `speed > 0` check and applies the\n // full delay rather than none. Mirrors the fixture-level guard in fixture-loader.ts.\n let replaySpeed = config.llm?.replaySpeed;\n if (replaySpeed != null && (!Number.isFinite(replaySpeed) || replaySpeed <= 0)) {\n logger.warn(`llm.replaySpeed must be a positive number, got ${replaySpeed}. Ignoring.`);\n replaySpeed = undefined;\n }\n\n // Load fixtures if specified\n const resolvedAuth = resolveInboundAuth(selectInboundAuthSource(config.auth));\n const llmock = createLLMockWithResolvedAuth(\n {\n port: overrides?.port ?? config.port ?? 0,\n host: overrides?.host ?? config.host ?? \"127.0.0.1\",\n latency: config.llm?.latency,\n chunkSize: config.llm?.chunkSize,\n replaySpeed,\n // llm.record.mcp reports skipped or failed recordings only as MCP-RECORD: warnings,\n // so an enabled config with at least one mount defaults to \"warn\" rather than the silent\n // default. An empty llm.record.mcp records nothing. An explicit logLevel wins.\n logLevel: config.llm?.logLevel ?? (hasMcpRecordMount(mcpRecord) ? \"warn\" : undefined),\n chaos: config.llm?.chaos,\n misbehavior,\n ...(enableMisbehavior ? { enableMisbehavior: true } : {}),\n record: llmRecordOf(config.llm?.record),\n metrics: config.metrics,\n strict: config.strict,\n strictToolArguments: overrides?.strictToolArguments ?? configStrictToolArguments,\n responsesTools: overrides?.responsesTools ?? responsesTools,\n },\n resolvedAuth,\n );\n\n // What this function mounted, by path (MR1: llm.record.mcp records through an MCP mount).\n const configMounts = new Map<string, Mountable>();\n\n if (config.llm?.fixtures) {\n const fixturePath = path.resolve(config.llm.fixtures);\n const stat = fs.statSync(fixturePath);\n if (stat.isDirectory()) {\n llmock.loadFixtureDir(fixturePath);\n } else {\n llmock.loadFixtureFile(fixturePath);\n }\n }\n\n // MCP\n if (config.mcp) {\n const mcpConfig = config.mcp;\n const mcp = new MCPMock({\n serverInfo: mcpConfig.serverInfo,\n });\n\n if (mcpConfig.tools) {\n for (const tool of mcpConfig.tools) {\n const { result, ...def } = tool;\n mcp.addTool(def);\n if (result !== undefined) {\n const answer = () => result;\n configToolHandlers.add(answer);\n mcp.onToolCall(def.name, answer);\n }\n }\n }\n\n if (mcpConfig.resources) {\n for (const res of mcpConfig.resources) {\n mcp.addResource(\n { uri: res.uri, name: res.name, mimeType: res.mimeType, description: res.description },\n res.text !== undefined || res.blob !== undefined\n ? { text: res.text, blob: res.blob, mimeType: res.mimeType }\n : undefined,\n );\n }\n }\n\n if (mcpConfig.prompts) {\n for (const prompt of mcpConfig.prompts) {\n const { result, ...def } = prompt;\n if (result) {\n mcp.addPrompt(def, () => result as import(\"./mcp-types.js\").MCPPromptResult);\n } else {\n mcp.addPrompt(def);\n }\n }\n }\n\n const mcpPath = mcpConfig.path ?? \"/mcp\";\n llmock.mount(mcpPath, mcp);\n configMounts.set(mcpPath, mcp);\n logger.info(`MCPMock mounted at ${mcpPath}`);\n }\n\n // A2A\n if (config.a2a) {\n const a2aConfig = config.a2a;\n const a2a = new A2AMock();\n\n if (a2aConfig.agents) {\n for (const agentConfig of a2aConfig.agents) {\n const { messages, tasks, streamingTasks, ...def } = agentConfig;\n a2a.registerAgent(def);\n\n if (messages) {\n for (const m of messages) {\n a2a.onMessage(def.name, m.pattern, m.parts ?? [{ text: \"\" }]);\n }\n }\n\n if (tasks) {\n for (const t of tasks) {\n a2a.onTask(def.name, t.pattern, t.artifacts ?? []);\n }\n }\n\n if (streamingTasks) {\n for (const s of streamingTasks) {\n a2a.onStreamingTask(def.name, s.pattern, s.events ?? [], s.delayMs);\n }\n }\n }\n }\n\n const a2aPath = a2aConfig.path ?? \"/a2a\";\n llmock.mount(a2aPath, a2a);\n configMounts.set(a2aPath, a2a);\n logger.info(`A2AMock mounted at ${a2aPath}`);\n }\n\n // AG-UI\n if (config.agui) {\n const aguiConfig = config.agui;\n const agui = new AGUIMock();\n\n if (aguiConfig.fixtures) {\n for (const f of aguiConfig.fixtures) {\n if (f.match.toolCallId && f.text && !f.events) {\n logger.warn(\n `AG-UI fixture uses text shorthand with toolCallId — text shorthand ignores toolCallId matching; use events[] instead (match: ${JSON.stringify(f.match)})`,\n );\n }\n if (f.text) {\n if (f.match.message !== undefined) {\n agui.onMessage(f.match.message, f.text, { delayMs: f.delayMs });\n } else {\n // No message pattern — register via addFixture so it only matches\n // on other criteria (toolCallId, toolName, stateKey) instead of\n // becoming a catch-all that matches every request.\n agui.addFixture({\n match: {\n toolCallId: f.match.toolCallId,\n toolName: f.match.toolName,\n stateKey: f.match.stateKey,\n },\n events: buildTextResponse(f.text),\n delayMs: f.delayMs,\n });\n }\n } else if (f.events) {\n agui.addFixture({\n match: {\n message: f.match.message,\n toolCallId: f.match.toolCallId,\n toolName: f.match.toolName,\n stateKey: f.match.stateKey,\n },\n events: f.events,\n delayMs: f.delayMs,\n });\n } else {\n logger.warn(\n `AG-UI fixture has neither text nor events — it will be skipped (match: ${JSON.stringify(f.match)})`,\n );\n }\n }\n }\n\n const aguiPath = aguiConfig.path ?? \"/agui\";\n llmock.mount(aguiPath, agui);\n configMounts.set(aguiPath, agui);\n logger.info(`AGUIMock mounted at ${aguiPath}`);\n }\n\n // Vector\n if (config.vector) {\n const vectorConfig = config.vector;\n const vector = new VectorMock();\n\n if (vectorConfig.collections) {\n for (const col of vectorConfig.collections) {\n vector.addCollection(col.name, { dimension: col.dimension });\n\n if (col.vectors && col.vectors.length > 0) {\n vector.upsert(col.name, col.vectors);\n }\n\n if (col.queryResults) {\n vector.onQuery(col.name, col.queryResults);\n }\n }\n }\n\n const vectorPath = vectorConfig.path ?? \"/vector\";\n llmock.mount(vectorPath, vector);\n configMounts.set(vectorPath, vector);\n logger.info(`VectorMock mounted at ${vectorPath}`);\n }\n\n // MR1: llm.record.mcp — record mounts (auto-mount an MCPMock where none is).\n // Read only with llm.enableMcpRecording: true. Any value that is present is then\n // validated, so null, false, 0 and \"\" fail at start too.\n if (mcpRecord !== undefined) {\n wireMcpRecording(llmock, mcpRecord, {\n mounted: configMounts,\n mcpMock: MCPMock,\n fixtures: config.llm?.fixtures,\n fixturePath: config.llm?.record?.fixturePath,\n strict: config.strict,\n env: process.env,\n });\n }\n\n // Services — configure default catch-all responses\n if (config.services) {\n if (config.services.search) {\n llmock.onSearch(/.*/, []);\n logger.info(\"Search service enabled with default empty results\");\n }\n if (config.services.rerank) {\n llmock.onRerank(/.*/, []);\n logger.info(\"Rerank service enabled with default empty results\");\n }\n if (config.services.moderate) {\n llmock.onModerate(/.*/, { flagged: false, categories: {} });\n logger.info(\"Moderation service enabled with default unflagged results\");\n }\n }\n\n const url = await llmock.start();\n return { llmock, url };\n}\n"],"mappings":"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"}