@copilotkit/aimock 1.42.0 → 1.43.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 (341) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +56 -0
  4. package/README.md +102 -16
  5. package/dist/agui-mock.cjs +1 -1
  6. package/dist/agui-mock.cjs.map +1 -1
  7. package/dist/agui-mock.d.cts.map +1 -1
  8. package/dist/agui-mock.d.ts.map +1 -1
  9. package/dist/agui-mock.js +1 -1
  10. package/dist/agui-mock.js.map +1 -1
  11. package/dist/agui-recorder.cjs +33 -11
  12. package/dist/agui-recorder.cjs.map +1 -1
  13. package/dist/agui-recorder.d.cts +10 -1
  14. package/dist/agui-recorder.d.cts.map +1 -1
  15. package/dist/agui-recorder.d.ts +10 -1
  16. package/dist/agui-recorder.d.ts.map +1 -1
  17. package/dist/agui-recorder.js +33 -11
  18. package/dist/agui-recorder.js.map +1 -1
  19. package/dist/agui-types.d.cts +1 -0
  20. package/dist/agui-types.d.cts.map +1 -1
  21. package/dist/agui-types.d.ts +1 -0
  22. package/dist/agui-types.d.ts.map +1 -1
  23. package/dist/aimock-cli.cjs +38 -10
  24. package/dist/aimock-cli.cjs.map +1 -1
  25. package/dist/aimock-cli.d.cts +5 -0
  26. package/dist/aimock-cli.d.cts.map +1 -1
  27. package/dist/aimock-cli.d.ts +5 -0
  28. package/dist/aimock-cli.d.ts.map +1 -1
  29. package/dist/aimock-cli.js +38 -10
  30. package/dist/aimock-cli.js.map +1 -1
  31. package/dist/batches.cjs +458 -0
  32. package/dist/batches.cjs.map +1 -0
  33. package/dist/batches.d.cts +57 -0
  34. package/dist/batches.d.cts.map +1 -0
  35. package/dist/batches.d.ts +57 -0
  36. package/dist/batches.d.ts.map +1 -0
  37. package/dist/batches.js +453 -0
  38. package/dist/batches.js.map +1 -0
  39. package/dist/bedrock-converse.cjs +12 -8
  40. package/dist/bedrock-converse.cjs.map +1 -1
  41. package/dist/bedrock-converse.d.cts.map +1 -1
  42. package/dist/bedrock-converse.d.ts.map +1 -1
  43. package/dist/bedrock-converse.js +14 -10
  44. package/dist/bedrock-converse.js.map +1 -1
  45. package/dist/bedrock.cjs +10 -8
  46. package/dist/bedrock.cjs.map +1 -1
  47. package/dist/bedrock.d.cts.map +1 -1
  48. package/dist/bedrock.d.ts.map +1 -1
  49. package/dist/bedrock.js +12 -10
  50. package/dist/bedrock.js.map +1 -1
  51. package/dist/byteplus-video.cjs +3 -3
  52. package/dist/byteplus-video.cjs.map +1 -1
  53. package/dist/byteplus-video.js +4 -4
  54. package/dist/byteplus-video.js.map +1 -1
  55. package/dist/chaos.cjs +622 -72
  56. package/dist/chaos.cjs.map +1 -1
  57. package/dist/chaos.d.cts +164 -7
  58. package/dist/chaos.d.cts.map +1 -1
  59. package/dist/chaos.d.ts +164 -7
  60. package/dist/chaos.d.ts.map +1 -1
  61. package/dist/chaos.js +613 -74
  62. package/dist/chaos.js.map +1 -1
  63. package/dist/cli.cjs +42 -23
  64. package/dist/cli.cjs.map +1 -1
  65. package/dist/cli.js +42 -23
  66. package/dist/cli.js.map +1 -1
  67. package/dist/cohere.cjs +10 -8
  68. package/dist/cohere.cjs.map +1 -1
  69. package/dist/cohere.d.cts.map +1 -1
  70. package/dist/cohere.d.ts.map +1 -1
  71. package/dist/cohere.js +12 -10
  72. package/dist/cohere.js.map +1 -1
  73. package/dist/config-loader.d.cts.map +1 -1
  74. package/dist/config-loader.d.ts.map +1 -1
  75. package/dist/convert.cjs +1 -1
  76. package/dist/convert.cjs.map +1 -1
  77. package/dist/convert.js +1 -1
  78. package/dist/convert.js.map +1 -1
  79. package/dist/elevenlabs-audio.cjs +3 -3
  80. package/dist/elevenlabs-audio.cjs.map +1 -1
  81. package/dist/elevenlabs-audio.js +4 -4
  82. package/dist/elevenlabs-audio.js.map +1 -1
  83. package/dist/elevenlabs-voice.cjs +1053 -0
  84. package/dist/elevenlabs-voice.cjs.map +1 -0
  85. package/dist/elevenlabs-voice.d.cts +72 -0
  86. package/dist/elevenlabs-voice.d.cts.map +1 -0
  87. package/dist/elevenlabs-voice.d.ts +72 -0
  88. package/dist/elevenlabs-voice.d.ts.map +1 -0
  89. package/dist/elevenlabs-voice.js +1048 -0
  90. package/dist/elevenlabs-voice.js.map +1 -0
  91. package/dist/embeddings.cjs +8 -4
  92. package/dist/embeddings.cjs.map +1 -1
  93. package/dist/embeddings.d.cts.map +1 -1
  94. package/dist/embeddings.d.ts.map +1 -1
  95. package/dist/embeddings.js +9 -5
  96. package/dist/embeddings.js.map +1 -1
  97. package/dist/fal-audio.cjs +3 -3
  98. package/dist/fal-audio.cjs.map +1 -1
  99. package/dist/fal-audio.js +4 -4
  100. package/dist/fal-audio.js.map +1 -1
  101. package/dist/fal.cjs +28 -4
  102. package/dist/fal.cjs.map +1 -1
  103. package/dist/fal.d.cts +16 -1
  104. package/dist/fal.d.cts.map +1 -1
  105. package/dist/fal.d.ts +16 -1
  106. package/dist/fal.d.ts.map +1 -1
  107. package/dist/fal.js +28 -5
  108. package/dist/fal.js.map +1 -1
  109. package/dist/files.cjs +1071 -0
  110. package/dist/files.cjs.map +1 -0
  111. package/dist/files.d.cts +68 -0
  112. package/dist/files.d.cts.map +1 -0
  113. package/dist/files.d.ts +68 -0
  114. package/dist/files.d.ts.map +1 -0
  115. package/dist/files.js +1059 -0
  116. package/dist/files.js.map +1 -0
  117. package/dist/fine-tuning.cjs +1051 -0
  118. package/dist/fine-tuning.cjs.map +1 -0
  119. package/dist/fine-tuning.d.cts +96 -0
  120. package/dist/fine-tuning.d.cts.map +1 -0
  121. package/dist/fine-tuning.d.ts +96 -0
  122. package/dist/fine-tuning.d.ts.map +1 -0
  123. package/dist/fine-tuning.js +1044 -0
  124. package/dist/fine-tuning.js.map +1 -0
  125. package/dist/fixture-loader.cjs +0 -0
  126. package/dist/fixture-loader.cjs.map +1 -1
  127. package/dist/fixture-loader.d.cts +37 -5
  128. package/dist/fixture-loader.d.cts.map +1 -1
  129. package/dist/fixture-loader.d.ts +37 -5
  130. package/dist/fixture-loader.d.ts.map +1 -1
  131. package/dist/fixture-loader.js +0 -0
  132. package/dist/fixture-loader.js.map +1 -1
  133. package/dist/gemini-embeddings.cjs +2 -2
  134. package/dist/gemini-embeddings.cjs.map +1 -1
  135. package/dist/gemini-embeddings.js +3 -3
  136. package/dist/gemini-embeddings.js.map +1 -1
  137. package/dist/gemini-interactions.cjs +13 -7
  138. package/dist/gemini-interactions.cjs.map +1 -1
  139. package/dist/gemini-interactions.d.cts.map +1 -1
  140. package/dist/gemini-interactions.d.ts.map +1 -1
  141. package/dist/gemini-interactions.js +15 -9
  142. package/dist/gemini-interactions.js.map +1 -1
  143. package/dist/gemini.cjs +11 -7
  144. package/dist/gemini.cjs.map +1 -1
  145. package/dist/gemini.d.cts.map +1 -1
  146. package/dist/gemini.d.ts.map +1 -1
  147. package/dist/gemini.js +13 -9
  148. package/dist/gemini.js.map +1 -1
  149. package/dist/grok-video.cjs +14 -14
  150. package/dist/grok-video.cjs.map +1 -1
  151. package/dist/grok-video.js +15 -15
  152. package/dist/grok-video.js.map +1 -1
  153. package/dist/helpers.cjs +229 -7
  154. package/dist/helpers.cjs.map +1 -1
  155. package/dist/helpers.d.cts +38 -2
  156. package/dist/helpers.d.cts.map +1 -1
  157. package/dist/helpers.d.ts +38 -2
  158. package/dist/helpers.d.ts.map +1 -1
  159. package/dist/helpers.js +221 -8
  160. package/dist/helpers.js.map +1 -1
  161. package/dist/images.cjs +54 -123
  162. package/dist/images.cjs.map +1 -1
  163. package/dist/images.d.cts.map +1 -1
  164. package/dist/images.d.ts.map +1 -1
  165. package/dist/images.js +55 -124
  166. package/dist/images.js.map +1 -1
  167. package/dist/index.cjs +41 -8
  168. package/dist/index.d.cts +12 -7
  169. package/dist/index.d.ts +12 -7
  170. package/dist/index.js +14 -10
  171. package/dist/jest.cjs +14 -7
  172. package/dist/jest.cjs.map +1 -1
  173. package/dist/jest.d.cts +3 -2
  174. package/dist/jest.d.cts.map +1 -1
  175. package/dist/jest.d.ts +3 -2
  176. package/dist/jest.d.ts.map +1 -1
  177. package/dist/jest.js +14 -7
  178. package/dist/jest.js.map +1 -1
  179. package/dist/journal.cjs +41 -4
  180. package/dist/journal.cjs.map +1 -1
  181. package/dist/journal.d.cts +44 -3
  182. package/dist/journal.d.cts.map +1 -1
  183. package/dist/journal.d.ts +44 -3
  184. package/dist/journal.d.ts.map +1 -1
  185. package/dist/journal.js +41 -5
  186. package/dist/journal.js.map +1 -1
  187. package/dist/live-fixture.cjs +1192 -0
  188. package/dist/live-fixture.cjs.map +1 -0
  189. package/dist/live-fixture.js +1187 -0
  190. package/dist/live-fixture.js.map +1 -0
  191. package/dist/live-recorder.cjs +256 -0
  192. package/dist/live-recorder.cjs.map +1 -0
  193. package/dist/live-recorder.js +254 -0
  194. package/dist/live-recorder.js.map +1 -0
  195. package/dist/live-replay.cjs +286 -0
  196. package/dist/live-replay.cjs.map +1 -0
  197. package/dist/live-replay.js +285 -0
  198. package/dist/live-replay.js.map +1 -0
  199. package/dist/live-sanitize.cjs +196 -0
  200. package/dist/live-sanitize.cjs.map +1 -0
  201. package/dist/live-sanitize.js +196 -0
  202. package/dist/live-sanitize.js.map +1 -0
  203. package/dist/live-types.d.cts +71 -0
  204. package/dist/live-types.d.cts.map +1 -0
  205. package/dist/live-types.d.ts +71 -0
  206. package/dist/live-types.d.ts.map +1 -0
  207. package/dist/llmock.cjs +52 -41
  208. package/dist/llmock.cjs.map +1 -1
  209. package/dist/llmock.d.cts +16 -5
  210. package/dist/llmock.d.cts.map +1 -1
  211. package/dist/llmock.d.ts +16 -5
  212. package/dist/llmock.d.ts.map +1 -1
  213. package/dist/llmock.js +53 -42
  214. package/dist/llmock.js.map +1 -1
  215. package/dist/messages.cjs +11 -7
  216. package/dist/messages.cjs.map +1 -1
  217. package/dist/messages.d.cts.map +1 -1
  218. package/dist/messages.d.ts.map +1 -1
  219. package/dist/messages.js +13 -9
  220. package/dist/messages.js.map +1 -1
  221. package/dist/metrics.cjs +258 -5
  222. package/dist/metrics.cjs.map +1 -1
  223. package/dist/metrics.d.cts +3 -1
  224. package/dist/metrics.d.cts.map +1 -1
  225. package/dist/metrics.d.ts +3 -1
  226. package/dist/metrics.d.ts.map +1 -1
  227. package/dist/metrics.js +255 -6
  228. package/dist/metrics.js.map +1 -1
  229. package/dist/moderation.cjs +10 -1
  230. package/dist/moderation.cjs.map +1 -1
  231. package/dist/moderation.d.cts.map +1 -1
  232. package/dist/moderation.d.ts.map +1 -1
  233. package/dist/moderation.js +10 -1
  234. package/dist/moderation.js.map +1 -1
  235. package/dist/ollama.cjs +5 -5
  236. package/dist/ollama.cjs.map +1 -1
  237. package/dist/ollama.js +6 -6
  238. package/dist/ollama.js.map +1 -1
  239. package/dist/openrouter-video.cjs +5 -5
  240. package/dist/openrouter-video.cjs.map +1 -1
  241. package/dist/openrouter-video.js +6 -6
  242. package/dist/openrouter-video.js.map +1 -1
  243. package/dist/recorder.cjs +45 -9
  244. package/dist/recorder.cjs.map +1 -1
  245. package/dist/recorder.d.cts.map +1 -1
  246. package/dist/recorder.d.ts.map +1 -1
  247. package/dist/recorder.js +43 -11
  248. package/dist/recorder.js.map +1 -1
  249. package/dist/responses.cjs +4 -3
  250. package/dist/responses.cjs.map +1 -1
  251. package/dist/responses.js +5 -5
  252. package/dist/responses.js.map +1 -1
  253. package/dist/router.cjs +20 -33
  254. package/dist/router.cjs.map +1 -1
  255. package/dist/router.d.cts +4 -1
  256. package/dist/router.d.cts.map +1 -1
  257. package/dist/router.d.ts +4 -1
  258. package/dist/router.d.ts.map +1 -1
  259. package/dist/router.js +20 -34
  260. package/dist/router.js.map +1 -1
  261. package/dist/server.cjs +701 -625
  262. package/dist/server.cjs.map +1 -1
  263. package/dist/server.d.cts +1 -0
  264. package/dist/server.d.cts.map +1 -1
  265. package/dist/server.d.ts +1 -0
  266. package/dist/server.d.ts.map +1 -1
  267. package/dist/server.js +704 -628
  268. package/dist/server.js.map +1 -1
  269. package/dist/speech.cjs +2 -2
  270. package/dist/speech.cjs.map +1 -1
  271. package/dist/speech.js +3 -3
  272. package/dist/speech.js.map +1 -1
  273. package/dist/transcription.cjs +4 -4
  274. package/dist/transcription.cjs.map +1 -1
  275. package/dist/transcription.js +5 -5
  276. package/dist/transcription.js.map +1 -1
  277. package/dist/types.d.cts +119 -16
  278. package/dist/types.d.cts.map +1 -1
  279. package/dist/types.d.ts +119 -16
  280. package/dist/types.d.ts.map +1 -1
  281. package/dist/validate-cli.cjs +925 -0
  282. package/dist/validate-cli.cjs.map +1 -0
  283. package/dist/validate-cli.js +924 -0
  284. package/dist/validate-cli.js.map +1 -0
  285. package/dist/vector-types.d.cts.map +1 -1
  286. package/dist/vector-types.d.ts.map +1 -1
  287. package/dist/veo-video.cjs +13 -13
  288. package/dist/veo-video.cjs.map +1 -1
  289. package/dist/veo-video.js +14 -14
  290. package/dist/veo-video.js.map +1 -1
  291. package/dist/video.cjs +4 -4
  292. package/dist/video.cjs.map +1 -1
  293. package/dist/video.d.cts +1 -1
  294. package/dist/video.d.cts.map +1 -1
  295. package/dist/video.d.ts +1 -1
  296. package/dist/video.d.ts.map +1 -1
  297. package/dist/video.js +5 -5
  298. package/dist/video.js.map +1 -1
  299. package/dist/vitest.cjs +13 -6
  300. package/dist/vitest.cjs.map +1 -1
  301. package/dist/vitest.d.cts +2 -1
  302. package/dist/vitest.d.cts.map +1 -1
  303. package/dist/vitest.d.ts +2 -1
  304. package/dist/vitest.d.ts.map +1 -1
  305. package/dist/vitest.js +14 -7
  306. package/dist/vitest.js.map +1 -1
  307. package/dist/watcher.cjs +2 -1
  308. package/dist/watcher.cjs.map +1 -1
  309. package/dist/watcher.js +2 -1
  310. package/dist/watcher.js.map +1 -1
  311. package/dist/ws-framing.cjs +150 -35
  312. package/dist/ws-framing.cjs.map +1 -1
  313. package/dist/ws-framing.d.cts +18 -3
  314. package/dist/ws-framing.d.cts.map +1 -1
  315. package/dist/ws-framing.d.ts +18 -3
  316. package/dist/ws-framing.d.ts.map +1 -1
  317. package/dist/ws-framing.js +151 -36
  318. package/dist/ws-framing.js.map +1 -1
  319. package/dist/ws-gemini-live.cjs +2 -2
  320. package/dist/ws-gemini-live.d.ts +2 -2
  321. package/dist/ws-gemini-live.js +2 -2
  322. package/dist/ws-live.cjs +401 -0
  323. package/dist/ws-live.cjs.map +1 -0
  324. package/dist/ws-live.js +400 -0
  325. package/dist/ws-live.js.map +1 -0
  326. package/dist/ws-realtime.cjs +46 -2
  327. package/dist/ws-realtime.cjs.map +1 -1
  328. package/dist/ws-realtime.d.cts.map +1 -1
  329. package/dist/ws-realtime.d.ts +2 -2
  330. package/dist/ws-realtime.d.ts.map +1 -1
  331. package/dist/ws-realtime.js +46 -2
  332. package/dist/ws-realtime.js.map +1 -1
  333. package/dist/ws-responses.cjs +2 -2
  334. package/dist/ws-responses.js +2 -2
  335. package/dist/ws-upstream.cjs +118 -0
  336. package/dist/ws-upstream.cjs.map +1 -0
  337. package/dist/ws-upstream.js +115 -0
  338. package/dist/ws-upstream.js.map +1 -0
  339. package/fixtures/openai-live-client.json +390 -0
  340. package/fixtures/openai-live-managed.json +709 -0
  341. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"llmock.js","names":[],"sources":["../src/llmock.ts"],"sourcesContent":["import type {\n AudioResponse,\n ChaosConfig,\n EmbeddingFixtureOpts,\n FalQueueOpts,\n Fixture,\n FixtureFileEntry,\n FixtureFileResponse,\n FixtureMatch,\n FixtureOpts,\n FixtureResponse,\n ImageResponse,\n MockServerOptions,\n Mountable,\n RecordConfig,\n ResponseFactory,\n TranscriptionResponse,\n VideoResponse,\n} from \"./types.js\";\nimport {\n createServer,\n createServerWithResolvedAuth,\n performFullReset,\n type ServerInstance,\n} from \"./server.js\";\nimport type { ResolvedInboundAuth } from \"./api-key-auth.js\";\nimport {\n isInjectableStatus,\n INJECTED_STATUS_RANGE,\n loadFixtureFile,\n loadFixturesFromDir,\n entryToFixture,\n normalizeResponse,\n validateFixtures,\n} from \"./fixture-loader.js\";\nimport { Journal } from \"./journal.js\";\nimport type { SearchFixture, SearchResult } from \"./search.js\";\nimport type { RerankFixture, RerankResult } from \"./rerank.js\";\nimport type { ModerationFixture, ModerationResult } from \"./moderation.js\";\nimport { imageResponseToFalJson, videoResponseToFalJson } from \"./fal.js\";\n\nexport class LLMock {\n private fixtures: Fixture[] = [];\n private searchFixtures: SearchFixture[] = [];\n private rerankFixtures: RerankFixture[] = [];\n private moderationFixtures: ModerationFixture[] = [];\n private mounts: Array<{ path: string; handler: Mountable }> = [];\n private serverInstance: ServerInstance | null = null;\n private options: MockServerOptions;\n private readonly resolvedInboundAuth?: ResolvedInboundAuth;\n\n constructor(options?: MockServerOptions, resolvedInboundAuth?: ResolvedInboundAuth) {\n this.options = options ?? {};\n this.resolvedInboundAuth = resolvedInboundAuth;\n }\n\n // ---- Fixture management ----\n\n addFixture(fixture: Fixture): this {\n this.fixtures.push(fixture);\n return this;\n }\n\n addFixtures(fixtures: Fixture[]): this {\n this.fixtures.push(...fixtures);\n return this;\n }\n\n prependFixture(fixture: Fixture): this {\n this.fixtures.unshift(fixture);\n return this;\n }\n\n getFixtures(): readonly Fixture[] {\n return this.fixtures;\n }\n\n loadFixtureFile(filePath: string): this {\n this.fixtures.push(...loadFixtureFile(filePath));\n return this;\n }\n\n loadFixtureDir(dirPath: string): this {\n this.fixtures.push(...loadFixturesFromDir(dirPath));\n return this;\n }\n\n /**\n * Add fixtures from a JSON string or pre-parsed array of fixture entries.\n * Validates all fixtures and throws if any have severity \"error\".\n */\n addFixturesFromJSON(input: string | FixtureFileEntry[]): this {\n let entries: FixtureFileEntry[];\n if (typeof input === \"string\") {\n try {\n entries = JSON.parse(input);\n } catch (err) {\n throw new Error(\n `addFixturesFromJSON: invalid JSON — ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n } else {\n entries = input;\n }\n const converted = entries.map((e) => entryToFixture(e));\n const issues = validateFixtures(converted);\n const errors = issues.filter((i) => i.severity === \"error\");\n if (errors.length > 0) {\n throw new Error(`Fixture validation failed: ${JSON.stringify(errors)}`);\n }\n this.fixtures.push(...converted);\n return this;\n }\n\n // Uses length = 0 to preserve array reference identity — the running\n // server reads this same array on every request.\n clearFixtures(): this {\n this.fixtures.length = 0;\n return this;\n }\n\n // ---- Convenience ----\n\n on(\n match: FixtureMatch,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.addFixture({\n match,\n response: typeof response === \"function\" ? response : normalizeResponse(response),\n ...opts,\n });\n }\n\n onMessage(\n pattern: string | RegExp,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ userMessage: pattern }, response, opts);\n }\n\n onEmbedding(\n pattern: string | RegExp,\n response: FixtureFileResponse | ResponseFactory,\n opts?: EmbeddingFixtureOpts,\n ): this {\n return this.on({ inputText: pattern }, response, opts);\n }\n\n onJsonOutput(pattern: string | RegExp, jsonContent: object | string, opts?: FixtureOpts): this {\n const content = typeof jsonContent === \"string\" ? jsonContent : JSON.stringify(jsonContent);\n return this.on({ userMessage: pattern, responseFormat: \"json_object\" }, { content }, opts);\n }\n\n onToolCall(\n name: string,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ toolName: name }, response, opts);\n }\n\n onToolResult(\n id: string,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ toolCallId: id }, response, opts);\n }\n\n onTurn(\n turn: number,\n pattern: string | RegExp,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ userMessage: pattern, turnIndex: turn }, response, opts);\n }\n\n onImage(prompt: string | RegExp, response: ImageResponse): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"image\" },\n response,\n });\n }\n\n onSpeech(input: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: input, endpoint: \"speech\" },\n response,\n });\n }\n\n onTranscription(response: TranscriptionResponse): this {\n return this.addFixture({\n match: { endpoint: \"transcription\" },\n response,\n });\n }\n\n onTranslation(response: TranscriptionResponse): this {\n return this.addFixture({\n match: { endpoint: \"translation\" },\n response,\n });\n }\n\n onVideo(prompt: string | RegExp, response: VideoResponse): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"video\" },\n response,\n });\n }\n\n onAudio(input: string | RegExp, response: AudioResponse): this {\n return this.addFixture({ match: { userMessage: input }, response });\n }\n\n onSoundEffect(text: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: text, endpoint: \"audio-gen\" },\n response,\n });\n }\n\n onMusic(prompt: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"audio-gen\" },\n response,\n });\n }\n\n onElevenLabsTTS(text: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: text, endpoint: \"elevenlabs-tts\" },\n response,\n });\n }\n\n onFalAudio(prompt: string | RegExp, response: AudioResponse, model?: string): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"fal-audio\", ...(model ? { model } : {}) },\n response,\n });\n }\n\n // fal.queue.* is the dominant client API; onFalRun is a sync alias.\n //\n // `opts.billableUnits` rides through to the completed `queue-result`\n // response's `x-fal-billable-units` header (emitted alongside\n // `x-fal-request-id`), letting consumers like `@tanstack/ai-fal` surface a\n // billed-units value on replay. Omit it to preserve the header-less default.\n onFalQueue(modelOrPrompt: string | RegExp, response: unknown, opts?: FalQueueOpts): this {\n const { billableUnits, ...fixtureOpts } = opts ?? {};\n return this.addFixture({\n match: { model: modelOrPrompt, endpoint: \"fal\" },\n response: { json: response, ...(billableUnits != null ? { billableUnits } : {}) },\n ...fixtureOpts,\n });\n }\n\n onFalRun(modelOrPrompt: string | RegExp, response: unknown, opts?: FalQueueOpts): this {\n return this.onFalQueue(modelOrPrompt, response, opts);\n }\n\n /**\n * Register a fal.ai image fixture. Wraps an `ImageResponse` (the shape used\n * by `onImage` and OpenAI/Azure image fixtures) into fal's image envelope\n * before storing it as a `RawJSONResponse`. Defaults `width`/`height` to\n * 1024 when the fixture's `ImageItem` doesn't carry them.\n */\n onFalImage(modelOrPrompt: string | RegExp, response: ImageResponse, opts?: FalQueueOpts): this {\n return this.onFalQueue(modelOrPrompt, imageResponseToFalJson(response), opts);\n }\n\n /**\n * Register a fal.ai video fixture. Wraps a `VideoResponse` into fal's video\n * envelope (`{ video: { url, content_type, file_name, file_size }, seed }`)\n * before storing it as a `RawJSONResponse`.\n */\n onFalVideo(modelOrPrompt: string | RegExp, response: VideoResponse, opts?: FalQueueOpts): this {\n return this.onFalQueue(modelOrPrompt, videoResponseToFalJson(response), opts);\n }\n\n // ---- Service mock convenience methods ----\n\n onSearch(pattern: string | RegExp, results: SearchResult[]): this {\n this.searchFixtures.push({ match: pattern, results });\n return this;\n }\n\n onRerank(pattern: string | RegExp, results: RerankResult[]): this {\n this.rerankFixtures.push({ match: pattern, results });\n return this;\n }\n\n onModerate(pattern: string | RegExp, result: ModerationResult): this {\n this.moderationFixtures.push({ match: pattern, result });\n return this;\n }\n\n /**\n * Queue a one-shot error that will be returned for the next matching\n * request, then automatically removed. Implemented as an internal fixture\n * with a `predicate` that always matches (so it fires first) and spliced\n * at the front of the fixture list.\n */\n nextRequestError(\n status: number,\n errorBody?: { message?: string; type?: string; code?: string },\n ): this {\n // Same gate as `POST /__aimock/error` and fixture validation — this is the\n // form the docs use, and an unchecked status reaches `res.writeHead` on\n // the next matched request: 99/1000 throw there (the injected error is\n // lost and the caller sees a generic 500), and 1xx hangs the request until\n // the client times out. Throwing HERE names the offending call instead.\n if (!isInjectableStatus(status)) {\n throw new RangeError(\n `nextRequestError: invalid status ${String(status)} — must be ${INJECTED_STATUS_RANGE}`,\n );\n }\n const errorResponse: FixtureResponse = {\n error: {\n message: errorBody?.message ?? \"Injected error\",\n type: errorBody?.type ?? \"server_error\",\n code: errorBody?.code,\n },\n status,\n };\n // An injected error is only a valid response for endpoints that can carry\n // an error envelope. Mirror the router's endpoint-compat table\n // (matchFixtureDiagnostic in router.ts): error responses are compatible\n // with chat / embedding / realtime* / fal and with requests that carry no\n // endpoint type, but NOT with multimedia endpoints (image, speech, video,\n // transcription, …). Gating consumption on this prevents an incompatible\n // request from matching the predicate and splicing — and thereby\n // destroying — a one-shot error intended for a different endpoint before\n // the router's own compat check would have skipped it.\n const errorEndpointCompatible = (req: import(\"./types.js\").ChatCompletionRequest) => {\n const reqEndpoint = req._endpointType as string | undefined;\n if (\n reqEndpoint === undefined ||\n reqEndpoint === \"chat\" ||\n reqEndpoint === \"embedding\" ||\n reqEndpoint.startsWith(\"realtime\") ||\n reqEndpoint === \"fal\"\n ) {\n return true;\n }\n return false;\n };\n const fixture: Fixture = {\n match: { predicate: errorEndpointCompatible },\n response: errorResponse,\n };\n // Insert at front so it matches before everything else\n this.fixtures.unshift(fixture);\n // Remove after first match — the journal records it so tests can assert.\n // Only consume (and splice) when the request endpoint is compatible; an\n // incompatible request returns false here, falls through to other\n // fixtures, and leaves this error pending for its intended endpoint.\n const original = fixture.match.predicate!;\n fixture.match.predicate = (req) => {\n const result = original(req);\n if (result) {\n // Remove synchronously on first match to prevent race conditions\n const idx = this.fixtures.indexOf(fixture);\n if (idx !== -1) this.fixtures.splice(idx, 1);\n }\n return result;\n };\n return this;\n }\n\n // ---- Mounts ----\n\n mount(path: string, handler: Mountable): this {\n this.mounts.push({ path, handler });\n\n // If server is already running, wire up journal, registry, and baseUrl immediately\n // so late mounts behave identically to pre-start mounts.\n if (this.serverInstance) {\n if (handler.setJournal) handler.setJournal(this.serverInstance.journal);\n if (handler.setBaseUrl) handler.setBaseUrl(this.serverInstance.url + path);\n const registry = this.serverInstance.defaults.registry;\n if (registry && handler.setRegistry) handler.setRegistry(registry);\n }\n\n return this;\n }\n\n // ---- Journal proxies ----\n\n getRequests(): import(\"./types.js\").JournalEntry[] {\n return this.journal.getAll();\n }\n\n getLastRequest(): import(\"./types.js\").JournalEntry | null {\n return this.journal.getLast();\n }\n\n clearRequests(): void {\n this.journal.clear();\n }\n\n resetMatchCounts(testId?: string): this {\n if (this.serverInstance) {\n this.serverInstance.journal.clearMatchCounts(testId);\n }\n return this;\n }\n\n // ---- Chaos ----\n\n /**\n * Set the server-wide chaos baseline. Writes through to a RUNNING server as\n * well as the construction options: an untagged `POST /__aimock/chaos`\n * installs a baseline override that shadows `options.chaos`, and without this\n * the call would silently do nothing until the next `reset()`. Per-testId\n * overrides still win over the baseline.\n */\n setChaos(config: ChaosConfig): this {\n this.options.chaos = config;\n if (this.serverInstance) this.serverInstance.defaults.chaos = config;\n return this;\n }\n\n /**\n * Turn chaos off everywhere: the construction config, the runtime baseline,\n * and every per-testId override (assigning `undefined` is the full-clear\n * signal the `defaults.chaos` setter defines).\n */\n clearChaos(): this {\n delete this.options.chaos;\n if (this.serverInstance) this.serverInstance.defaults.chaos = undefined;\n return this;\n }\n\n // ---- Recording ----\n\n enableRecording(config: RecordConfig): this {\n this.options.record = config;\n return this;\n }\n\n disableRecording(): this {\n delete this.options.record;\n return this;\n }\n\n // ---- Reset ----\n\n /**\n * Full reset — the in-process equivalent of `POST /__aimock/reset`. Shares\n * one implementation with the control-API route so the two cannot drift.\n *\n * The one deliberate difference: search / rerank / moderation fixtures are\n * also cleared here. Those are registered through this class only — the\n * control API has no route that creates them, so the HTTP reset can neither\n * reach nor observe them.\n *\n * NOT ALL OF THIS IS PER-INSTANCE. `performFullReset` clears module-global\n * state as well: the Gemini interaction and event-id counters\n * (`resetInteractionCounter` / `resetEventIdCounter` in\n * `./gemini-interactions.js`) and the fal.ai job/queue maps (`falJobs`,\n * `falQueueStates`). With two `LLMock` instances live in one process,\n * `a.reset()` rewinds the Gemini id sequence that `b` is mid-way through —\n * `b` then re-emits `aimock-int-0` / `evt_1`, ids it has already handed\n * out — and drops `b`'s in-flight fal jobs. Give each instance its own\n * process (or its own vitest worker) if that matters.\n *\n * The global stores are cleared even before `start()`, when there is no\n * server instance to reset.\n */\n reset(): this {\n this.searchFixtures.length = 0;\n this.rerankFixtures.length = 0;\n this.moderationFixtures.length = 0;\n performFullReset(this.fixtures, this.serverInstance);\n return this;\n }\n\n // ---- Server lifecycle ----\n\n async start(): Promise<string> {\n if (this.serverInstance) {\n throw new Error(\"Server already started\");\n }\n this.serverInstance = await (this.resolvedInboundAuth\n ? createServerWithResolvedAuth(\n this.fixtures,\n this.options,\n this.resolvedInboundAuth,\n this.mounts,\n {\n search: this.searchFixtures,\n rerank: this.rerankFixtures,\n moderation: this.moderationFixtures,\n },\n )\n : createServer(this.fixtures, this.options, this.mounts, {\n search: this.searchFixtures,\n rerank: this.rerankFixtures,\n moderation: this.moderationFixtures,\n }));\n return this.serverInstance.url;\n }\n\n async stop(): Promise<void> {\n if (!this.serverInstance) {\n throw new Error(\"Server not started\");\n }\n const { server } = this.serverInstance;\n await new Promise<void>((resolve, reject) => {\n server.close((err: Error | undefined) => (err ? reject(err) : resolve()));\n });\n this.serverInstance = null;\n }\n\n // ---- Accessors ----\n\n get journal(): Journal {\n if (!this.serverInstance) {\n throw new Error(\"Server not started\");\n }\n return this.serverInstance.journal;\n }\n\n get url(): string {\n if (!this.serverInstance) {\n throw new Error(\"Server not started\");\n }\n return this.serverInstance.url;\n }\n\n get baseUrl(): string {\n return this.url;\n }\n\n get port(): number {\n const parsed = new URL(this.url); // this.url throws if not started\n if (!parsed.port) {\n throw new Error(`Server URL has no explicit port: ${this.url}`);\n }\n return parseInt(parsed.port, 10);\n }\n\n // ---- Static factory ----\n\n static async create(options?: MockServerOptions): Promise<LLMock> {\n const instance = new LLMock(options);\n await instance.start();\n return instance;\n }\n}\n\n/** @internal Configuration startup preserves a policy resolved from the selected source. */\nexport function createLLMockWithResolvedAuth(\n options: MockServerOptions,\n resolvedAuth: ResolvedInboundAuth,\n): LLMock {\n return new LLMock(options, resolvedAuth);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"llmock.js","names":[],"sources":["../src/llmock.ts"],"sourcesContent":["import type { LiveTranscript } from \"./live-types.js\";\nimport { normalizeLiveFixture, normalizeLiveOptions } from \"./live-fixture.js\";\nimport { isLiveResponse } from \"./helpers.js\";\nimport type {\n AudioResponse,\n ChaosConfig,\n EmbeddingFixtureOpts,\n FalQueueOpts,\n Fixture,\n FixtureFileEntry,\n FixtureFileResponse,\n FixtureMatch,\n FixtureOpts,\n ImageResponse,\n MockServerOptions,\n Mountable,\n RecordConfig,\n ResponseFactory,\n TranscriptionResponse,\n VideoResponse,\n VoiceDesignResponse,\n} from \"./types.js\";\nimport {\n createServer,\n createServerWithResolvedAuth,\n performFullReset,\n type ServerInstance,\n} from \"./server.js\";\nimport type { ResolvedInboundAuth } from \"./api-key-auth.js\";\nimport {\n isInjectableStatus,\n INJECTED_STATUS_RANGE,\n queueOneShotError,\n clearFixtureQueue,\n loadFixtureFile,\n loadFixturesFromDir,\n entryToFixture,\n normalizeResponse,\n validateFixtures,\n} from \"./fixture-loader.js\";\nimport { Journal } from \"./journal.js\";\nimport type { SearchFixture, SearchResult } from \"./search.js\";\nimport type { RerankFixture, RerankResult } from \"./rerank.js\";\nimport type { ModerationFixture, ModerationResult } from \"./moderation.js\";\nimport { imageResponseToFalJson, videoResponseToFalJson } from \"./fal.js\";\nimport { voiceDesignToJson } from \"./elevenlabs-voice.js\";\n\nexport class LLMock {\n private fixtures: Fixture[] = [];\n private searchFixtures: SearchFixture[] = [];\n private rerankFixtures: RerankFixture[] = [];\n private moderationFixtures: ModerationFixture[] = [];\n private mounts: Array<{ path: string; handler: Mountable }> = [];\n private serverInstance: ServerInstance | null = null;\n private options: MockServerOptions;\n private readonly resolvedInboundAuth?: ResolvedInboundAuth;\n\n constructor(options?: MockServerOptions, resolvedInboundAuth?: ResolvedInboundAuth) {\n this.options = options ?? {};\n if (this.options.live !== undefined) normalizeLiveOptions(this.options.live);\n this.resolvedInboundAuth = resolvedInboundAuth;\n }\n\n // ---- Fixture management ----\n\n private normalizeFixture(fixture: Fixture): Fixture {\n if (\n isLiveResponse(fixture.response) ||\n (fixture.match.endpoint === \"openai-live\" && typeof fixture.response !== \"function\")\n ) {\n return {\n ...fixture,\n match: { ...fixture.match },\n response: normalizeLiveFixture(fixture.response, this.options.live),\n };\n }\n return fixture;\n }\n\n addFixture(fixture: Fixture): this {\n this.fixtures.push(this.normalizeFixture(fixture));\n return this;\n }\n\n addFixtures(fixtures: Fixture[]): this {\n this.fixtures.push(...fixtures.map((fixture) => this.normalizeFixture(fixture)));\n return this;\n }\n\n prependFixture(fixture: Fixture): this {\n this.fixtures.unshift(this.normalizeFixture(fixture));\n return this;\n }\n\n getFixtures(): readonly Fixture[] {\n return this.fixtures;\n }\n\n loadFixtureFile(filePath: string): this {\n this.fixtures.push(...loadFixtureFile(filePath, undefined, this.options.live));\n return this;\n }\n\n loadFixtureDir(dirPath: string): this {\n this.fixtures.push(...loadFixturesFromDir(dirPath, undefined, this.options.live));\n return this;\n }\n\n /**\n * Add fixtures from a JSON string or pre-parsed array of fixture entries.\n * Validates all fixtures and throws if any have severity \"error\".\n */\n addFixturesFromJSON(input: string | FixtureFileEntry[]): this {\n let entries: FixtureFileEntry[];\n if (typeof input === \"string\") {\n try {\n entries = JSON.parse(input);\n } catch (err) {\n throw new Error(\n `addFixturesFromJSON: invalid JSON — ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n } else {\n entries = input;\n }\n const converted = entries.map((e) => entryToFixture(e, undefined, this.options.live));\n const issues = validateFixtures(converted, this.options.live);\n const errors = issues.filter((i) => i.severity === \"error\");\n if (errors.length > 0) {\n throw new Error(`Fixture validation failed: ${JSON.stringify(errors)}`);\n }\n this.fixtures.push(...converted);\n return this;\n }\n\n // Clears in place to preserve array reference identity — the running\n // server reads this same array on every request — and invalidates any\n // one-shot claim parked in flight so it cannot re-arm into the cleared queue.\n clearFixtures(): this {\n clearFixtureQueue(this.fixtures);\n return this;\n }\n\n // ---- Convenience ----\n\n on(\n match: FixtureMatch,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.addFixture({\n match,\n response:\n typeof response === \"function\" ? response : normalizeResponse(response, this.options.live),\n ...opts,\n });\n }\n\n onLive(\n match: Omit<FixtureMatch, \"endpoint\">,\n transcript: LiveTranscript,\n opts?: FixtureOpts,\n ): this {\n return this.on({ ...match, endpoint: \"openai-live\" }, { live: transcript }, opts);\n }\n\n onMessage(\n pattern: string | RegExp,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ userMessage: pattern }, response, opts);\n }\n\n onEmbedding(\n pattern: string | RegExp,\n response: FixtureFileResponse | ResponseFactory,\n opts?: EmbeddingFixtureOpts,\n ): this {\n return this.on({ inputText: pattern }, response, opts);\n }\n\n onJsonOutput(pattern: string | RegExp, jsonContent: object | string, opts?: FixtureOpts): this {\n const content = typeof jsonContent === \"string\" ? jsonContent : JSON.stringify(jsonContent);\n return this.on({ userMessage: pattern, responseFormat: \"json_object\" }, { content }, opts);\n }\n\n onToolCall(\n name: string,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ toolName: name }, response, opts);\n }\n\n onToolResult(\n id: string,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ toolCallId: id }, response, opts);\n }\n\n onTurn(\n turn: number,\n pattern: string | RegExp,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ userMessage: pattern, turnIndex: turn }, response, opts);\n }\n\n onImage(prompt: string | RegExp, response: ImageResponse): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"image\" },\n response,\n });\n }\n\n onSpeech(input: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: input, endpoint: \"speech\" },\n response,\n });\n }\n\n onTranscription(response: TranscriptionResponse): this {\n return this.addFixture({\n match: { endpoint: \"transcription\" },\n response,\n });\n }\n\n onTranslation(response: TranscriptionResponse): this {\n return this.addFixture({\n match: { endpoint: \"translation\" },\n response,\n });\n }\n\n onVideo(prompt: string | RegExp, response: VideoResponse): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"video\" },\n response,\n });\n }\n\n onAudio(input: string | RegExp, response: AudioResponse): this {\n return this.addFixture({ match: { userMessage: input }, response });\n }\n\n onSoundEffect(text: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: text, endpoint: \"audio-gen\" },\n response,\n });\n }\n\n onMusic(prompt: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"audio-gen\" },\n response,\n });\n }\n\n onElevenLabsTTS(text: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: text, endpoint: \"elevenlabs-tts\" },\n response,\n });\n }\n\n onElevenLabsVoiceDesign(description: string | RegExp, response: VoiceDesignResponse): this {\n return this.addFixture({\n match: { userMessage: description, endpoint: \"elevenlabs-voice-design\" },\n response: voiceDesignToJson(response),\n });\n }\n\n onFalAudio(prompt: string | RegExp, response: AudioResponse, model?: string): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"fal-audio\", ...(model ? { model } : {}) },\n response,\n });\n }\n\n // fal.queue.* is the dominant client API; onFalRun is a sync alias.\n //\n // `opts.billableUnits` rides through to the completed `queue-result`\n // response's `x-fal-billable-units` header (emitted alongside\n // `x-fal-request-id`), letting consumers like `@tanstack/ai-fal` surface a\n // billed-units value on replay. Omit it to preserve the header-less default.\n onFalQueue(modelOrPrompt: string | RegExp, response: unknown, opts?: FalQueueOpts): this {\n const { billableUnits, ...fixtureOpts } = opts ?? {};\n return this.addFixture({\n match: { model: modelOrPrompt, endpoint: \"fal\" },\n response: { json: response, ...(billableUnits != null ? { billableUnits } : {}) },\n ...fixtureOpts,\n });\n }\n\n onFalRun(modelOrPrompt: string | RegExp, response: unknown, opts?: FalQueueOpts): this {\n return this.onFalQueue(modelOrPrompt, response, opts);\n }\n\n /**\n * Register a fal.ai image fixture. Wraps an `ImageResponse` (the shape used\n * by `onImage` and OpenAI/Azure image fixtures) into fal's image envelope\n * before storing it as a `RawJSONResponse`. Defaults `width`/`height` to\n * 1024 when the fixture's `ImageItem` doesn't carry them.\n */\n onFalImage(modelOrPrompt: string | RegExp, response: ImageResponse, opts?: FalQueueOpts): this {\n return this.onFalQueue(modelOrPrompt, imageResponseToFalJson(response), opts);\n }\n\n /**\n * Register a fal.ai video fixture. Wraps a `VideoResponse` into fal's video\n * envelope (`{ video: { url, content_type, file_name, file_size }, seed }`)\n * before storing it as a `RawJSONResponse`.\n */\n onFalVideo(modelOrPrompt: string | RegExp, response: VideoResponse, opts?: FalQueueOpts): this {\n return this.onFalQueue(modelOrPrompt, videoResponseToFalJson(response), opts);\n }\n\n // ---- Service mock convenience methods ----\n\n onSearch(pattern: string | RegExp, results: SearchResult[]): this {\n this.searchFixtures.push({ match: pattern, results });\n return this;\n }\n\n onRerank(pattern: string | RegExp, results: RerankResult[]): this {\n this.rerankFixtures.push({ match: pattern, results });\n return this;\n }\n\n onModerate(pattern: string | RegExp, result: ModerationResult): this {\n this.moderationFixtures.push({ match: pattern, result });\n return this;\n }\n\n /**\n * Queue a one-shot error that will be returned for the next matching\n * request, then automatically removed. Implemented as an internal fixture\n * inserted at the front of the fixture list; see `queueOneShotError` for\n * the endpoint gate and the served-not-evaluated consumption rule.\n */\n nextRequestError(\n status: number,\n errorBody?: { message?: string; type?: string; code?: string },\n ): this {\n // Same gate as `POST /__aimock/error` and fixture validation — this is the\n // form the docs use, and an unchecked status reaches `res.writeHead` on\n // the next matched request: 99/1000 throw there (the injected error is\n // lost and the caller sees a generic 500), and 1xx hangs the request until\n // the client times out. Throwing HERE names the offending call instead.\n if (!isInjectableStatus(status)) {\n throw new RangeError(\n `nextRequestError: invalid status ${String(status)} — must be ${INJECTED_STATUS_RANGE}`,\n );\n }\n queueOneShotError(this.fixtures, status, errorBody);\n return this;\n }\n\n // ---- Mounts ----\n\n mount(path: string, handler: Mountable): this {\n this.mounts.push({ path, handler });\n\n // If server is already running, wire up journal, registry, and baseUrl immediately\n // so late mounts behave identically to pre-start mounts.\n if (this.serverInstance) {\n if (handler.setJournal) handler.setJournal(this.serverInstance.journal);\n if (handler.setBaseUrl) handler.setBaseUrl(this.serverInstance.url + path);\n const registry = this.serverInstance.defaults.registry;\n if (registry && handler.setRegistry) handler.setRegistry(registry);\n }\n\n return this;\n }\n\n // ---- Journal proxies ----\n\n getRequests(): import(\"./types.js\").JournalEntry[] {\n return this.journal.getAll();\n }\n\n getLastRequest(): import(\"./types.js\").JournalEntry | null {\n return this.journal.getLast();\n }\n\n /**\n * Clear the request journal. Fixture match-counts (sequencing state) are\n * left intact — use `resetMatchCounts()` for those.\n */\n clearRequests(): void {\n this.journal.clearEntries();\n }\n\n resetMatchCounts(testId?: string): this {\n if (this.serverInstance) {\n this.serverInstance.journal.clearMatchCounts(testId);\n }\n return this;\n }\n\n // ---- Chaos ----\n\n /**\n * Set the server-wide chaos baseline. Writes through to a RUNNING server as\n * well as the construction options: an untagged `POST /__aimock/chaos`\n * installs a baseline override that shadows `options.chaos`, and without this\n * the call would silently do nothing until the next `reset()`. Per-testId\n * overrides still win over the baseline.\n */\n setChaos(config: ChaosConfig): this {\n this.options.chaos = config;\n if (this.serverInstance) this.serverInstance.defaults.chaos = config;\n return this;\n }\n\n /**\n * Turn chaos off everywhere: the construction config, the runtime baseline,\n * and every per-testId override (assigning `undefined` is the full-clear\n * signal the `defaults.chaos` setter defines).\n */\n clearChaos(): this {\n delete this.options.chaos;\n if (this.serverInstance) this.serverInstance.defaults.chaos = undefined;\n return this;\n }\n\n // ---- Recording ----\n\n enableRecording(config: RecordConfig): this {\n this.options.record = config;\n return this;\n }\n\n disableRecording(): this {\n delete this.options.record;\n return this;\n }\n\n // ---- Reset ----\n\n /**\n * Full reset — the in-process equivalent of `POST /__aimock/reset`. Shares\n * one implementation with the control-API route so the two cannot drift.\n *\n * The one deliberate difference: search / rerank / moderation fixtures are\n * also cleared here. Those are registered through this class only — the\n * control API has no route that creates them, so the HTTP reset can neither\n * reach nor observe them.\n *\n * NOT ALL OF THIS IS PER-INSTANCE. `performFullReset` clears module-global\n * state as well: the Gemini interaction and event-id counters\n * (`resetInteractionCounter` / `resetEventIdCounter` in\n * `./gemini-interactions.js`), the fal.ai job/queue maps (`falJobs`,\n * `falQueueStates`), the fine-tuning job store (`clearFineTuningStore`),\n * and the ElevenLabs Voice Design store (`clearElevenLabsVoices`). With two\n * `LLMock` instances live in one process,\n * `a.reset()` rewinds the Gemini id sequence that `b` is mid-way through —\n * `b` then re-emits `aimock-int-0` / `evt_1`, ids it has already handed\n * out — and drops `b`'s in-flight fal jobs. Give each instance its own\n * process (or its own vitest worker) if that matters.\n *\n * The global stores are cleared even before `start()`, when there is no\n * server instance to reset.\n */\n reset(): this {\n this.searchFixtures.length = 0;\n this.rerankFixtures.length = 0;\n this.moderationFixtures.length = 0;\n performFullReset(this.fixtures, this.serverInstance);\n return this;\n }\n\n // ---- Server lifecycle ----\n\n async start(): Promise<string> {\n if (this.serverInstance) {\n throw new Error(\"Server already started\");\n }\n this.serverInstance = await (this.resolvedInboundAuth\n ? createServerWithResolvedAuth(\n this.fixtures,\n this.options,\n this.resolvedInboundAuth,\n this.mounts,\n {\n search: this.searchFixtures,\n rerank: this.rerankFixtures,\n moderation: this.moderationFixtures,\n },\n )\n : createServer(this.fixtures, this.options, this.mounts, {\n search: this.searchFixtures,\n rerank: this.rerankFixtures,\n moderation: this.moderationFixtures,\n }));\n return this.serverInstance.url;\n }\n\n closeLiveSessions(testId?: string): this {\n this.serverInstance?.closeLiveSessions(testId);\n return this;\n }\n\n async stop(): Promise<void> {\n if (!this.serverInstance) {\n throw new Error(\"Server not started\");\n }\n const { server } = this.serverInstance;\n await new Promise<void>((resolve, reject) => {\n server.close((err: Error | undefined) => (err ? reject(err) : resolve()));\n });\n this.serverInstance = null;\n }\n\n // ---- Accessors ----\n\n get journal(): Journal {\n if (!this.serverInstance) {\n throw new Error(\"Server not started\");\n }\n return this.serverInstance.journal;\n }\n\n get url(): string {\n if (!this.serverInstance) {\n throw new Error(\"Server not started\");\n }\n return this.serverInstance.url;\n }\n\n get baseUrl(): string {\n return this.url;\n }\n\n get port(): number {\n const parsed = new URL(this.url); // this.url throws if not started\n if (!parsed.port) {\n throw new Error(`Server URL has no explicit port: ${this.url}`);\n }\n return parseInt(parsed.port, 10);\n }\n\n // ---- Static factory ----\n\n static async create(options?: MockServerOptions): Promise<LLMock> {\n const instance = new LLMock(options);\n await instance.start();\n return instance;\n }\n}\n\n/** @internal Configuration startup preserves a policy resolved from the selected source. */\nexport function createLLMockWithResolvedAuth(\n options: MockServerOptions,\n resolvedAuth: ResolvedInboundAuth,\n): LLMock {\n return new LLMock(options, resolvedAuth);\n}\n"],"mappings":"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"}
package/dist/messages.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  const require_helpers = require('./helpers.cjs');
2
- const require_router = require('./router.cjs');
3
2
  const require_sse_writer = require('./sse-writer.cjs');
4
- const require_interruption = require('./interruption.cjs');
5
3
  const require_chaos = require('./chaos.cjs');
4
+ const require_router = require('./router.cjs');
6
5
  const require_recorder = require('./recorder.cjs');
6
+ const require_interruption = require('./interruption.cjs');
7
7
 
8
8
  //#region src/messages.ts
9
9
  /**
@@ -562,7 +562,8 @@ function buildClaudeContentWithToolCallsStreamEvents(content, toolCalls, model,
562
562
  blockIndex++;
563
563
  }
564
564
  if (blocks && blocks.length > 0) {
565
- const ordered = require_helpers.resolveFixtureBlocks(blocks);
565
+ const outcome = require_helpers.resolveFixtureBlockOutcome(blocks);
566
+ const ordered = outcome.ordered;
566
567
  for (const block of ordered) if (block.type === "text") {
567
568
  events.push({
568
569
  type: "content_block_start",
@@ -628,7 +629,7 @@ function buildClaudeContentWithToolCallsStreamEvents(content, toolCalls, model,
628
629
  events.push({
629
630
  type: "message_delta",
630
631
  delta: {
631
- stop_reason: claudeStopReason(overrides?.finishReason, "tool_use"),
632
+ stop_reason: claudeStopReason(overrides?.finishReason, outcome.hasToolCalls ? "tool_use" : "end_turn"),
632
633
  stop_sequence: null
633
634
  },
634
635
  usage: { output_tokens: claudeUsage(overrides).output_tokens }
@@ -731,8 +732,11 @@ function buildClaudeContentWithToolCallsResponse(content, toolCalls, model, logg
731
732
  input: argsObj
732
733
  };
733
734
  };
735
+ let blockHasTools;
734
736
  if (blocks && blocks.length > 0) {
735
- const ordered = require_helpers.resolveFixtureBlocks(blocks);
737
+ const outcome = require_helpers.resolveFixtureBlockOutcome(blocks);
738
+ const ordered = outcome.ordered;
739
+ blockHasTools = outcome.hasToolCalls;
736
740
  for (const block of ordered) if (block.type === "text") contentBlocks.push({
737
741
  type: "text",
738
742
  text: block.text
@@ -755,7 +759,7 @@ function buildClaudeContentWithToolCallsResponse(content, toolCalls, model, logg
755
759
  role: overrides?.role ?? "assistant",
756
760
  content: contentBlocks,
757
761
  model: overrides?.model ?? model,
758
- stop_reason: claudeStopReason(overrides?.finishReason, "tool_use"),
762
+ stop_reason: claudeStopReason(overrides?.finishReason, blockHasTools === false ? "end_turn" : "tool_use"),
759
763
  stop_sequence: null,
760
764
  usage: claudeUsage(overrides)
761
765
  };
@@ -866,7 +870,7 @@ async function handleMessages(req, res, raw, fixtures, journal, defaults, setCor
866
870
  const snippet = typeof lastUserMsg?.content === "string" ? lastUserMsg.content.slice(0, 80) : "";
867
871
  logger.debug(`No fixture matched for request (model=${completionReq.model ?? "?"}, msg="${snippet}")`);
868
872
  }
869
- if (require_chaos.applyChaos(res, fixture, defaults.chaos, req.headers, req.url, journal, {
873
+ if (await require_chaos.applyChaosAsync(res, fixture, defaults.chaos, req.headers, req.url, journal, {
870
874
  method: req.method ?? "POST",
871
875
  path: req.url ?? "/v1/messages",
872
876
  headers: require_helpers.flattenHeaders(req.headers),
@@ -1 +1 @@
1
- {"version":3,"file":"messages.cjs","names":["generateToolUseId","generateMessageId","resolveFixtureBlocks","calculateDelay","delay","flattenHeaders","isJsonObject","resolveStrictMode","strictOverrideField","getContext","getTestId","matchFixtureDiagnostic","recordMatchOptions","applyChaos","strictNoMatchMessage","strictNoMatchLogLine","proxyAndRecord","resolveResponse","isErrorResponse","isContentWithToolCallsResponse","extractOverrides","resolveReasoningForModel","resolveReasoningArtifactsForModel","createInterruptionSignal","isTextResponse","isToolCallResponse"],"sources":["../src/messages.ts"],"sourcesContent":["/**\n * Anthropic Claude Messages API support.\n *\n * Translates incoming /v1/messages requests into the ChatCompletionRequest\n * format used by the fixture router, and converts fixture responses back into\n * the Claude Messages API streaming (or non-streaming) format.\n */\n\nimport type * as http from \"node:http\";\nimport type {\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n HandlerDefaults,\n RecordedTimings,\n FixtureBlock,\n ResponseOverrides,\n StreamingProfile,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n generateMessageId,\n generateToolUseId,\n extractOverrides,\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n resolveFixtureBlocks,\n flattenHeaders,\n isJsonObject,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n resolveReasoningForModel,\n resolveReasoningArtifactsForModel,\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 { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n/**\n * Non-empty placeholder signature written into emitted `thinking` blocks.\n *\n * The real Anthropic signature is a cryptographic value aimock cannot\n * reproduce, but extended-thinking invariant (b) requires a non-empty\n * `signature` on the leading thinking block of a tool-loop continuation turn.\n * Emitting \"\" would make a record→replay round-trip of an aimock thinking turn\n * self-trip that invariant under strict mode. A non-empty placeholder keeps\n * round-trips green; the invariant only checks for non-emptiness, not value.\n */\nconst PLACEHOLDER_SIGNATURE = \"aimock-placeholder-signature\";\n\n// ─── Claude Messages API request types ──────────────────────────────────────\n\ninterface ClaudeContentBlock {\n type:\n | \"text\"\n | \"tool_use\"\n | \"tool_result\"\n | \"image\"\n | \"document\"\n | \"thinking\"\n | \"redacted_thinking\";\n text?: string;\n id?: string;\n name?: string;\n input?: unknown;\n tool_use_id?: string;\n content?: string | ClaudeContentBlock[];\n is_error?: boolean;\n // Extended-thinking fields (Anthropic): `thinking` blocks carry the reasoning\n // text plus a cryptographic `signature`; `redacted_thinking` blocks carry an\n // opaque `data` payload instead.\n thinking?: string;\n signature?: string;\n data?: string;\n}\n\ninterface ClaudeMessage {\n role: \"user\" | \"assistant\";\n content: string | ClaudeContentBlock[];\n}\n\ninterface ClaudeToolDef {\n name: string;\n description?: string;\n input_schema?: object;\n}\n\ninterface ClaudeRequest {\n model: string;\n messages: ClaudeMessage[];\n system?: string | ClaudeContentBlock[];\n tools?: ClaudeToolDef[];\n tool_choice?: unknown;\n stream?: boolean;\n max_tokens: number;\n temperature?: number;\n // Extended-thinking config. Explicitly modeled so it is no longer swallowed\n // by the index signature below; read defensively (may be a non-object).\n thinking?: { type?: \"enabled\" | \"disabled\"; budget_tokens?: number };\n [key: string]: unknown;\n}\n\n// ─── Extended-thinking request invariants (Anthropic) ───────────────────────\n\n/**\n * A detected violation of the Anthropic extended-thinking request invariants on\n * a tool-loop continuation turn. `kind` distinguishes the three failure modes\n * so callers can template a per-kind error message and tests can assert without\n * string matching.\n */\ninterface ThinkingViolation {\n kind: \"missing_thinking_first\" | \"missing_signature\" | \"dropped_redacted_thinking\";\n messageIndex: number;\n observedFirstBlockType?: string;\n}\n\n// ─── Input conversion: Claude → ChatCompletions messages ────────────────────\n\nfunction extractClaudeTextContent(content: string | ClaudeContentBlock[]): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .filter((b) => b != null && typeof b === \"object\" && b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\");\n}\n\nexport function claudeToCompletionRequest(req: ClaudeRequest): ChatCompletionRequest {\n const messages: ChatMessage[] = [];\n\n // system field → system message\n if (req.system) {\n const systemText =\n typeof req.system === \"string\"\n ? req.system\n : Array.isArray(req.system)\n ? req.system\n .filter((b) => b != null && typeof b === \"object\" && b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\")\n : \"\";\n if (systemText) {\n messages.push({ role: \"system\", content: systemText });\n }\n }\n\n const reqMessages = Array.isArray(req.messages) ? req.messages : [];\n for (const msg of reqMessages) {\n // `req.messages` is untrusted JSON; entries may be null / non-object.\n if (!msg || typeof msg !== \"object\") continue;\n if (msg.role === \"user\") {\n // Check for tool_result blocks\n if (typeof msg.content !== \"string\" && Array.isArray(msg.content)) {\n // Content blocks are equally untrusted; skip null / non-object entries.\n const blocks = msg.content.filter((b) => b != null && typeof b === \"object\");\n const toolResults = blocks.filter((b) => b.type === \"tool_result\");\n const textBlocks = blocks.filter((b) => b.type === \"text\");\n\n if (toolResults.length > 0) {\n // Anthropic bundles a leg-2 tool_result and any accompanying user text\n // into ONE user-role message. We emit the accompanying text FIRST, then\n // the tool message(s), so the normalized shape is\n // `[..., user(text), tool]` — the tool message trails the last user\n // message and the current-turn `hasToolResult` predicate\n // ({@link currentTurnHasToolResult}) correctly classifies it `true`\n // (this IS a leg-2 turn that carries a tool result). Emitting the tool\n // FIRST would produce `[..., tool, user(text)]`, which is byte-identical\n // to a genuine turn-N leg-1 (a fresh user question after a completed\n // tool turn) and would be misclassified `false`. The source-message\n // grouping — that this text and this tool_result came from the SAME\n // Anthropic message — is only available here, so this ordering is the\n // only place the two cases can be told apart. The common\n // tool_result-only follow-up (no text blocks) is unaffected.\n if (textBlocks.length > 0) {\n messages.push({\n role: \"user\",\n content: textBlocks.map((b) => b.text ?? \"\").join(\"\"),\n });\n }\n // Each tool_result → tool message\n for (const tr of toolResults) {\n const resultContent =\n typeof tr.content === \"string\"\n ? tr.content\n : Array.isArray(tr.content)\n ? tr.content\n .filter((b) => b != null && typeof b === \"object\" && b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\")\n : \"\";\n messages.push({\n role: \"tool\",\n content: resultContent,\n tool_call_id: tr.tool_use_id,\n });\n }\n continue;\n }\n }\n // Regular user message\n messages.push({\n role: \"user\",\n content: extractClaudeTextContent(msg.content),\n });\n } else if (msg.role === \"assistant\") {\n if (typeof msg.content === \"string\") {\n messages.push({ role: \"assistant\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n const toolUseBlocks = msg.content.filter(\n (b) => b != null && typeof b === \"object\" && b.type === \"tool_use\",\n );\n // Only `text` blocks feed fixture matching; `thinking` /\n // `redacted_thinking` blocks are intentionally excluded from the\n // matchable content.\n const textContent = extractClaudeTextContent(msg.content);\n\n if (toolUseBlocks.length > 0) {\n messages.push({\n role: \"assistant\",\n content: textContent || null,\n tool_calls: toolUseBlocks.map((b) => ({\n id: b.id ?? generateToolUseId(),\n type: \"function\" as const,\n function: {\n name: b.name ?? \"\",\n arguments: typeof b.input === \"string\" ? b.input : JSON.stringify(b.input ?? {}),\n },\n })),\n });\n } else {\n messages.push({ role: \"assistant\", content: textContent || null });\n }\n } else {\n // null/undefined content — tool-only assistant turn\n messages.push({ role: \"assistant\", content: null });\n }\n }\n }\n\n // Convert tools\n let tools: ToolDefinition[] | undefined;\n if (req.tools && req.tools.length > 0) {\n tools = req.tools.map((t) => ({\n type: \"function\" as const,\n function: {\n name: t.name,\n description: t.description,\n parameters: t.input_schema,\n },\n }));\n }\n\n return {\n model: req.model,\n messages,\n stream: req.stream,\n temperature: req.temperature,\n max_tokens: req.max_tokens,\n tools,\n _endpointType: \"chat\",\n };\n}\n\n// ─── Extended-thinking invariant validation ─────────────────────────────────\n\n/** True iff `req.thinking` is an object with `type === \"enabled\"`. */\nfunction isThinkingEnabled(req: ClaudeRequest): boolean {\n const t = req.thinking;\n return typeof t === \"object\" && t !== null && (t as { type?: unknown }).type === \"enabled\";\n}\n\n/**\n * True iff the user turn at `req.messages[userIndex]` carries a `tool_result`\n * referencing one of `toolUseIds` — i.e. it answers the preceding assistant\n * turn's `tool_use` block(s), making that assistant turn a tool-loop\n * continuation point.\n */\nfunction userTurnAnswersToolUse(msg: ClaudeMessage | undefined, toolUseIds: Set<string>): boolean {\n if (!msg || msg.role !== \"user\" || !Array.isArray(msg.content)) return false;\n return msg.content.some(\n (b) =>\n b != null &&\n typeof b === \"object\" &&\n b.type === \"tool_result\" &&\n typeof b.tool_use_id === \"string\" &&\n toolUseIds.has(b.tool_use_id),\n );\n}\n\n/**\n * Validate the Anthropic extended-thinking request invariants on tool-loop\n * continuation turns. Pure: returns the first detected `ThinkingViolation` or\n * `null` when thinking is disabled or every in-scope turn is well-formed.\n *\n * Scope: an assistant turn is in-scope only when it (a) is array content\n * carrying at least one `tool_use` block and (b) is followed by a matching\n * `tool_result` on the next user turn. Text-only / `end_turn` turns, string or\n * empty turns, and trailing unanswered `tool_use` turns are all exempt.\n *\n * Scope detection assumes well-formed Anthropic transcripts: `tool_use` ids are\n * unique, and a tool_use turn is answered by the immediately-following user\n * turn's `tool_result` (adjacency). Malformed shapes — non-adjacent answers,\n * idless `tool_use` blocks, or a `tool_result` separated from its `tool_use` by\n * intervening turns — are intentionally treated as out-of-scope (and therefore\n * not 400'd) rather than validated, since the real Anthropic API would never\n * have produced them.\n */\nexport function validateThinkingInvariants(req: ClaudeRequest): ThinkingViolation | null {\n if (!isThinkingEnabled(req)) return null;\n\n const messages = Array.isArray(req.messages) ? req.messages : [];\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n // `req.messages` is untrusted JSON; entries may be null / non-object.\n if (!msg || typeof msg !== \"object\") continue;\n if (msg.role !== \"assistant\" || !Array.isArray(msg.content) || msg.content.length === 0) {\n continue;\n }\n\n const toolUseIds = new Set<string>();\n for (const b of msg.content) {\n // Content blocks are equally untrusted; skip null / non-object entries.\n if (!b || typeof b !== \"object\") continue;\n if (b.type === \"tool_use\" && typeof b.id === \"string\") toolUseIds.add(b.id);\n }\n // Not a tool_use-bearing turn → not a reasoning-bearing continuation turn.\n if (toolUseIds.size === 0) continue;\n // Trailing/unanswered tool_use (no matching tool_result follows) → out of scope.\n if (!userTurnAnswersToolUse(messages[i + 1], toolUseIds)) continue;\n\n const first = msg.content[0];\n\n // A null / non-object leading block cannot be a thinking block → it\n // violates invariant (a) just as a wrong-typed block would.\n if (!first || typeof first !== \"object\") {\n return {\n kind: \"missing_thinking_first\",\n messageIndex: i,\n observedFirstBlockType: undefined,\n };\n }\n\n // (a) The in-scope turn must lead with a thinking / redacted_thinking block.\n if (first.type !== \"thinking\" && first.type !== \"redacted_thinking\") {\n return {\n kind: \"missing_thinking_first\",\n messageIndex: i,\n observedFirstBlockType: first.type,\n };\n }\n\n // (b) A leading `thinking` block must carry a non-empty string `signature`.\n if (first.type === \"thinking\") {\n if (typeof first.signature !== \"string\" || first.signature.length === 0) {\n return { kind: \"missing_signature\", messageIndex: i };\n }\n }\n\n // (c) A leading `redacted_thinking` block must preserve a non-empty `data`.\n if (first.type === \"redacted_thinking\") {\n if (typeof first.data !== \"string\" || first.data.length === 0) {\n return { kind: \"dropped_redacted_thinking\", messageIndex: i };\n }\n }\n }\n\n return null;\n}\n\n/** Render the Anthropic-shaped 400 error message for a thinking violation. */\nfunction thinkingViolationMessage(v: ThinkingViolation): string {\n const prefix = `messages.${v.messageIndex}.content.0`;\n switch (v.kind) {\n case \"missing_thinking_first\":\n return `${prefix}: when \\`thinking\\` is enabled, a tool-loop continuation assistant turn must begin with a \\`thinking\\` block; got \\`${v.observedFirstBlockType ?? \"unknown\"}\\`.`;\n case \"missing_signature\":\n return `${prefix}: the leading \\`thinking\\` block is missing a non-empty \\`signature\\`.`;\n case \"dropped_redacted_thinking\":\n return `${prefix}: the leading \\`redacted_thinking\\` block must preserve its \\`data\\`.`;\n }\n}\n\n// ─── Response building: fixture → Claude Messages API format ────────────────\n\nfunction claudeStopReason(finishReason: string | undefined, defaultReason: string): string {\n if (!finishReason) return defaultReason;\n if (finishReason === \"stop\") return \"end_turn\";\n if (finishReason === \"tool_calls\") return \"tool_use\";\n if (finishReason === \"length\") return \"max_tokens\";\n return finishReason;\n}\n\nfunction claudeUsage(overrides?: ResponseOverrides): {\n input_tokens: number;\n output_tokens: number;\n} {\n if (!overrides?.usage) return { input_tokens: 0, output_tokens: 0 };\n return {\n input_tokens: overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? 0,\n output_tokens: overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? 0,\n };\n}\n\ninterface ClaudeSSEEvent {\n type: string;\n [key: string]: unknown;\n}\n\n/**\n * Emit faithful Anthropic `redacted_thinking` content-block events at the head\n * of a streamed turn — one `content_block_start` (carrying the opaque `data`)\n * and `content_block_stop` per recorded block, with NO deltas (real Anthropic\n * delivers the encrypted reasoning entirely on the start event). Returns the\n * next free block index. When `redactedThinking` is empty/absent this is a\n * no-op, so no events are added.\n *\n * Leading placement keeps the turn round-trip-safe for the extended-thinking\n * leading-block invariant (a thinking / redacted_thinking block must come\n * first). It does NOT reproduce real Anthropic's stream order: aimock joins all\n * plaintext reasoning into one block and emits all redacted blocks ahead of it,\n * whereas real Anthropic interleaves `thinking` and `redacted_thinking` in the\n * order they occurred. The interleaving between the two is not preserved.\n */\nfunction pushRedactedThinkingStreamEvents(\n events: ClaudeSSEEvent[],\n startIndex: number,\n redactedThinking: string[] | undefined,\n): number {\n let blockIndex = startIndex;\n for (const data of redactedThinking ?? []) {\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"redacted_thinking\", data },\n });\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n blockIndex++;\n }\n return blockIndex;\n}\n\nfunction buildClaudeTextStreamEvents(\n content: string,\n model: string,\n chunkSize: number,\n reasoning?: string,\n overrides?: ResponseOverrides,\n reasoningSignature?: string,\n redactedThinking?: string[],\n): ClaudeSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const effectiveModel = overrides?.model ?? model;\n // Prefer a recorded real signature when one was captured; otherwise fall back\n // to the round-trip-safe placeholder.\n const signature = reasoningSignature ?? PLACEHOLDER_SIGNATURE;\n const events: ClaudeSSEEvent[] = [];\n\n // message_start\n events.push({\n type: \"message_start\",\n message: {\n id: msgId,\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: [],\n model: effectiveModel,\n stop_reason: null,\n stop_sequence: null,\n usage: claudeUsage(overrides),\n },\n });\n\n let blockIndex = 0;\n\n // Redacted-thinking blocks lead the turn (before any thinking / text) to\n // satisfy the leading-block invariant on replay; see the helper for the\n // ordering caveat.\n blockIndex = pushRedactedThinkingStreamEvents(events, blockIndex, redactedThinking);\n\n // Thinking block (emitted before text when reasoning is present)\n if (reasoning) {\n // Real Anthropic emits an empty `signature` on the thinking\n // `content_block_start`; the cryptographic signature arrives only via the\n // trailing `signature_delta`. Mirror that wire shape here.\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"thinking\", thinking: \"\", signature: \"\" },\n });\n\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"thinking_delta\", thinking: slice },\n });\n }\n\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"signature_delta\", signature },\n });\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n // content_block_start (text)\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"text\", text: \"\" },\n });\n\n // content_block_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_block_delta\",\n index: blockIndex,\n delta: { type: \"text_delta\", text: slice },\n });\n }\n\n // content_block_stop\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(overrides?.finishReason, \"end_turn\"),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n}\n\nfunction buildClaudeToolCallStreamEvents(\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n reasoningSignature?: string,\n redactedThinking?: string[],\n): ClaudeSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const effectiveModel = overrides?.model ?? model;\n // Prefer a recorded real signature when one was captured; otherwise fall back\n // to the round-trip-safe placeholder.\n const signature = reasoningSignature ?? PLACEHOLDER_SIGNATURE;\n const events: ClaudeSSEEvent[] = [];\n\n // message_start\n events.push({\n type: \"message_start\",\n message: {\n id: msgId,\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: [],\n model: effectiveModel,\n stop_reason: null,\n stop_sequence: null,\n usage: claudeUsage(overrides),\n },\n });\n\n let blockIndex = 0;\n\n // Redacted-thinking blocks lead the turn (before thinking / tool_use blocks)\n // to satisfy the extended-thinking leading-block invariant on replay; see the\n // helper for the ordering caveat.\n blockIndex = pushRedactedThinkingStreamEvents(events, blockIndex, redactedThinking);\n\n // Optional thinking block (emitted before the tool_use blocks when reasoning\n // is present). Mirrors buildClaudeContentWithToolCallsStreamEvents exactly so\n // a pure-tool-call turn under extended thinking emits a leading thinking\n // block — without it, replaying the emitted turn under strict self-trips\n // `missing_thinking_first`.\n if (reasoning) {\n // Real Anthropic emits an empty `signature` on the thinking\n // `content_block_start`; the cryptographic signature arrives only via the\n // trailing `signature_delta`. Mirror that wire shape here.\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"thinking\", thinking: \"\", signature: \"\" },\n });\n\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"thinking_delta\", thinking: slice },\n });\n }\n\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"signature_delta\", signature },\n });\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n for (const tc of toolCalls) {\n const toolUseId = tc.id || generateToolUseId();\n\n // Parse arguments to JSON object (Claude uses objects, not strings)\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n const argsJson = JSON.stringify(argsObj);\n\n // content_block_start\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: {\n type: \"tool_use\",\n id: toolUseId,\n name: tc.name,\n input: {},\n },\n });\n\n // content_block_delta — input_json_delta chunks\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"input_json_delta\", partial_json: slice },\n });\n }\n\n // content_block_stop\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n}\n\n// Non-streaming response builders\n\n/**\n * Push faithful Anthropic `redacted_thinking` content blocks (each a\n * `{ type: \"redacted_thinking\", data }`) onto a non-streaming content array, in\n * recorded order. No-op when `redactedThinking` is empty/absent, so no blocks\n * are added.\n *\n * Leading placement keeps the turn round-trip-safe for the extended-thinking\n * leading-block invariant. It does NOT reproduce real Anthropic's block order:\n * aimock joins all plaintext reasoning into one block and emits all redacted\n * blocks ahead of it, whereas real Anthropic interleaves `thinking` and\n * `redacted_thinking` in occurrence order. The interleaving is not preserved.\n */\nfunction pushRedactedThinkingBlocks(\n contentBlocks: object[],\n redactedThinking: string[] | undefined,\n): void {\n for (const data of redactedThinking ?? []) {\n contentBlocks.push({ type: \"redacted_thinking\", data });\n }\n}\n\nfunction buildClaudeTextResponse(\n content: string,\n model: string,\n reasoning?: string,\n overrides?: ResponseOverrides,\n reasoningSignature?: string,\n redactedThinking?: string[],\n): object {\n const contentBlocks: object[] = [];\n\n // Redacted-thinking blocks lead the content array (before thinking / text);\n // see the helper for the ordering caveat.\n pushRedactedThinkingBlocks(contentBlocks, redactedThinking);\n\n if (reasoning) {\n contentBlocks.push({\n type: \"thinking\",\n thinking: reasoning,\n // Prefer a recorded real signature; otherwise the round-trip-safe placeholder.\n signature: reasoningSignature ?? PLACEHOLDER_SIGNATURE,\n });\n }\n\n contentBlocks.push({ type: \"text\", text: content });\n\n return {\n id: overrides?.id ?? generateMessageId(),\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: contentBlocks,\n model: overrides?.model ?? model,\n stop_reason: claudeStopReason(overrides?.finishReason, \"end_turn\"),\n stop_sequence: null,\n usage: claudeUsage(overrides),\n };\n}\n\nfunction buildClaudeToolCallResponse(\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n reasoningSignature?: string,\n redactedThinking?: string[],\n): object {\n const contentBlocks: object[] = [];\n\n // Redacted-thinking blocks lead the content array (before thinking / tool_use)\n // to satisfy the leading-block invariant on replay; see the helper for the\n // ordering caveat.\n pushRedactedThinkingBlocks(contentBlocks, redactedThinking);\n\n // Leading thinking block when reasoning is present — mirrors\n // buildClaudeContentWithToolCallsResponse so a pure-tool-call turn under\n // extended thinking carries the same leading thinking block.\n if (reasoning) {\n contentBlocks.push({\n type: \"thinking\",\n thinking: reasoning,\n // Prefer a recorded real signature; otherwise the round-trip-safe placeholder.\n signature: reasoningSignature ?? PLACEHOLDER_SIGNATURE,\n });\n }\n\n for (const tc of toolCalls) {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n contentBlocks.push({\n type: \"tool_use\",\n id: tc.id || generateToolUseId(),\n name: tc.name,\n input: argsObj,\n });\n }\n\n return {\n id: overrides?.id ?? generateMessageId(),\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: contentBlocks,\n model: overrides?.model ?? model,\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n usage: claudeUsage(overrides),\n };\n}\n\nfunction buildClaudeContentWithToolCallsStreamEvents(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n reasoningSignature?: string,\n redactedThinking?: string[],\n blocks?: FixtureBlock[],\n): ClaudeSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const effectiveModel = overrides?.model ?? model;\n // Prefer a recorded real signature when one was captured; otherwise fall back\n // to the round-trip-safe placeholder.\n const signature = reasoningSignature ?? PLACEHOLDER_SIGNATURE;\n const events: ClaudeSSEEvent[] = [];\n\n // message_start\n events.push({\n type: \"message_start\",\n message: {\n id: msgId,\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: [],\n model: effectiveModel,\n stop_reason: null,\n stop_sequence: null,\n usage: claudeUsage(overrides),\n },\n });\n\n let blockIndex = 0;\n\n // Redacted-thinking blocks lead the turn (before thinking / text / tool_use);\n // see the helper for the ordering caveat. Applies to both the legacy and the\n // ordered-`blocks` paths.\n blockIndex = pushRedactedThinkingStreamEvents(events, blockIndex, redactedThinking);\n\n // Optional thinking block — also shared by both paths.\n if (reasoning) {\n // Real Anthropic emits an empty `signature` on the thinking\n // `content_block_start`; the cryptographic signature arrives only via the\n // trailing `signature_delta`. Mirror that wire shape here.\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"thinking\", thinking: \"\", signature: \"\" },\n });\n\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"thinking_delta\", thinking: slice },\n });\n }\n\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"signature_delta\", signature },\n });\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n if (blocks && blocks.length > 0) {\n // NEW PATH: stream `text`/`tool_use` content blocks in the fixture's array\n // order. Anthropic is fully tool-first capable — a `toolCall` block can take\n // a lower `index` than a `text` block. Content-block indices are assigned in\n // encounter order, continuing from any leading thinking/redacted blocks.\n const ordered = resolveFixtureBlocks(blocks);\n\n for (const block of ordered) {\n if (block.type === \"text\") {\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"text\", text: \"\" },\n });\n\n for (let i = 0; i < block.text.length; i += chunkSize) {\n const slice = block.text.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"text_delta\", text: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n } else {\n const toolUseId = block.id || generateToolUseId();\n\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(block.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${block.name}\": ${block.arguments}`,\n );\n argsObj = {};\n }\n const argsJson = JSON.stringify(argsObj);\n\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: {\n type: \"tool_use\",\n id: toolUseId,\n name: block.name,\n input: {},\n },\n });\n\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"input_json_delta\", partial_json: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n }\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n }\n\n // LEGACY PATH (byte-for-byte unchanged): text content block, then tool_use\n // blocks in `toolCalls` order. Reached only when `blocks` is absent; the\n // leading redacted-thinking/thinking blocks above are shared with the new\n // path and produce identical wire output here.\n // Text content block\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"text\", text: \"\" },\n });\n\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"text_delta\", text: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n\n // Tool use blocks\n for (const tc of toolCalls) {\n const toolUseId = tc.id || generateToolUseId();\n\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n const argsJson = JSON.stringify(argsObj);\n\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: {\n type: \"tool_use\",\n id: toolUseId,\n name: tc.name,\n input: {},\n },\n });\n\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"input_json_delta\", partial_json: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n}\n\nfunction buildClaudeContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n reasoningSignature?: string,\n redactedThinking?: string[],\n blocks?: FixtureBlock[],\n): object {\n const contentBlocks: object[] = [];\n\n // Redacted-thinking blocks lead the content array (before thinking / text /\n // tool_use); see the helper for the ordering caveat.\n pushRedactedThinkingBlocks(contentBlocks, redactedThinking);\n\n if (reasoning) {\n contentBlocks.push({\n type: \"thinking\",\n thinking: reasoning,\n // Prefer a recorded real signature; otherwise the round-trip-safe placeholder.\n signature: reasoningSignature ?? PLACEHOLDER_SIGNATURE,\n });\n }\n\n // Build a tool_use content block from a fixture tool call, parsing its\n // string `arguments` into the object `input` Anthropic emits (warning on\n // malformed JSON, same idiom as the streaming/legacy paths).\n const toolUseBlock = (tc: { name: string; arguments: string; id?: string }): object => {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n type: \"tool_use\",\n id: tc.id || generateToolUseId(),\n name: tc.name,\n input: argsObj,\n };\n };\n\n if (blocks && blocks.length > 0) {\n // NEW PATH: the non-streaming `content[]` array is positionally observable,\n // so emit `text`/`tool_use` content blocks in the fixture's ARRAY ORDER\n // (after any leading redacted/thinking blocks). A toolCall block before a\n // text block therefore yields a tool_use ahead of the text — matching the\n // streaming path for the same `blocks` fixture.\n const ordered = resolveFixtureBlocks(blocks);\n for (const block of ordered) {\n if (block.type === \"text\") {\n contentBlocks.push({ type: \"text\", text: block.text });\n } else {\n contentBlocks.push(\n toolUseBlock({ name: block.name, arguments: block.arguments, id: block.id }),\n );\n }\n }\n } else {\n // LEGACY PATH (unchanged): text content block, then tool_use blocks.\n contentBlocks.push({ type: \"text\", text: content });\n for (const tc of toolCalls) {\n contentBlocks.push(toolUseBlock(tc));\n }\n }\n\n return {\n id: overrides?.id ?? generateMessageId(),\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: contentBlocks,\n model: overrides?.model ?? model,\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n usage: claudeUsage(overrides),\n };\n}\n\n// ─── SSE writer for Claude Messages API ─────────────────────────────────────\n\ninterface ClaudeStreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n recordedTimings?: RecordedTimings;\n replaySpeed?: number;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n}\n\nasync function writeClaudeSSEStream(\n res: http.ServerResponse,\n events: ClaudeSSEEvent[],\n optionsOrLatency?: number | ClaudeStreamOptions,\n): Promise<boolean> {\n const opts: ClaudeStreamOptions =\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 handleMessages(\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 claudeReq: ClaudeRequest;\n try {\n claudeReq = JSON.parse(raw) as ClaudeRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Malformed JSON: ${detail}`,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `claudeReq.thinking` throws a TypeError that\n // surfaces as a 500 instead of a 400.\n if (!isJsonObject(claudeReq)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\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 // Extended-thinking invariant validation. The validator runs whenever\n // thinking is enabled (it self-short-circuits to null otherwise). On a\n // detected violation: strict ON → 400, strict OFF → warn + replay. Mirrors\n // the real Anthropic API, which 400s on these.\n const thinkingViolation = validateThinkingInvariants(claudeReq);\n if (thinkingViolation) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const violationMessage = thinkingViolationMessage(thinkingViolation);\n if (effectiveStrict) {\n logger.error(`THINKING: ${violationMessage}`);\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: null,\n response: {\n status: 400,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n type: \"error\",\n error: {\n type: \"invalid_request_error\",\n message: violationMessage,\n },\n }),\n );\n return;\n }\n logger.warn(`THINKING: ${violationMessage} (strict off — replaying anyway)`);\n // Fall through to existing match/replay behavior.\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = claudeToCompletionRequest(claudeReq);\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 const lastUserMsg = completionReq.messages.filter((m) => m.role === \"user\").pop();\n const snippet =\n typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content.slice(0, 80) : \"\";\n logger.debug(\n `No fixture matched for request (model=${completionReq.model ?? \"?\"}, msg=\"${snippet}\")`,\n );\n }\n\n if (\n applyChaos(\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 ?? \"/v1/messages\",\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(\n req.method ?? \"POST\",\n req.url ?? \"/v1/messages\",\n skippedBySequenceOrTurn,\n ),\n );\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\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 \"anthropic\",\n req.url ?? \"/v1/messages\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\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 ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n // Anthropic-style error format: { type: \"error\", error: { type, message } }\n const anthropicError = {\n type: \"error\",\n error: {\n type: response.error.type ?? \"api_error\",\n message: response.error.message,\n },\n };\n writeErrorResponse(res, status, JSON.stringify(anthropicError), {\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 Claude Messages 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 completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const { reasoningSignature: effReasoningSignature, redactedThinking: effRedactedThinking } =\n resolveReasoningArtifactsForModel(\n response.reasoningSignature,\n response.redactedThinking,\n completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (claudeReq.stream !== true) {\n const body = buildClaudeContentWithToolCallsResponse(\n response.content ?? \"\",\n response.toolCalls ?? [],\n completionReq.model,\n logger,\n effReasoning,\n overrides,\n effReasoningSignature,\n effRedactedThinking,\n response.blocks,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildClaudeContentWithToolCallsStreamEvents(\n response.content ?? \"\",\n response.toolCalls ?? [],\n completionReq.model,\n chunkSize,\n logger,\n effReasoning,\n overrides,\n effReasoningSignature,\n effRedactedThinking,\n response.blocks,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeClaudeSSEStream(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 Claude Messages 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 completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const { reasoningSignature: effReasoningSignature, redactedThinking: effRedactedThinking } =\n resolveReasoningArtifactsForModel(\n response.reasoningSignature,\n response.redactedThinking,\n completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (claudeReq.stream !== true) {\n const body = buildClaudeTextResponse(\n response.content,\n completionReq.model,\n effReasoning,\n overrides,\n effReasoningSignature,\n effRedactedThinking,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildClaudeTextStreamEvents(\n response.content,\n completionReq.model,\n chunkSize,\n effReasoning,\n overrides,\n effReasoningSignature,\n effRedactedThinking,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeClaudeSSEStream(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 Claude Messages 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 completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const { reasoningSignature: effReasoningSignature, redactedThinking: effRedactedThinking } =\n resolveReasoningArtifactsForModel(\n response.reasoningSignature,\n response.redactedThinking,\n completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (claudeReq.stream !== true) {\n const body = buildClaudeToolCallResponse(\n response.toolCalls,\n completionReq.model,\n logger,\n effReasoning,\n overrides,\n effReasoningSignature,\n effRedactedThinking,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildClaudeToolCallStreamEvents(\n response.toolCalls,\n completionReq.model,\n chunkSize,\n logger,\n effReasoning,\n overrides,\n effReasoningSignature,\n effRedactedThinking,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeClaudeSSEStream(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 ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response did not match any known type\",\n type: \"server_error\",\n },\n }),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"messages.cjs","names":["generateToolUseId","generateMessageId","resolveFixtureBlockOutcome","calculateDelay","delay","flattenHeaders","isJsonObject","resolveStrictMode","strictOverrideField","getContext","getTestId","matchFixtureDiagnostic","recordMatchOptions","applyChaosAsync","strictNoMatchMessage","strictNoMatchLogLine","proxyAndRecord","resolveResponse","isErrorResponse","isContentWithToolCallsResponse","extractOverrides","resolveReasoningForModel","resolveReasoningArtifactsForModel","createInterruptionSignal","isTextResponse","isToolCallResponse"],"sources":["../src/messages.ts"],"sourcesContent":["/**\n * Anthropic Claude Messages API support.\n *\n * Translates incoming /v1/messages requests into the ChatCompletionRequest\n * format used by the fixture router, and converts fixture responses back into\n * the Claude Messages API streaming (or non-streaming) format.\n */\n\nimport type * as http from \"node:http\";\nimport type {\n ChatCompletionRequest,\n ChatMessage,\n Fixture,\n HandlerDefaults,\n RecordedTimings,\n FixtureBlock,\n ResponseOverrides,\n StreamingProfile,\n ToolCall,\n ToolDefinition,\n} from \"./types.js\";\nimport {\n generateMessageId,\n generateToolUseId,\n extractOverrides,\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n resolveFixtureBlockOutcome,\n flattenHeaders,\n isJsonObject,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n resolveReasoningForModel,\n resolveReasoningArtifactsForModel,\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/**\n * Non-empty placeholder signature written into emitted `thinking` blocks.\n *\n * The real Anthropic signature is a cryptographic value aimock cannot\n * reproduce, but extended-thinking invariant (b) requires a non-empty\n * `signature` on the leading thinking block of a tool-loop continuation turn.\n * Emitting \"\" would make a record→replay round-trip of an aimock thinking turn\n * self-trip that invariant under strict mode. A non-empty placeholder keeps\n * round-trips green; the invariant only checks for non-emptiness, not value.\n */\nconst PLACEHOLDER_SIGNATURE = \"aimock-placeholder-signature\";\n\n// ─── Claude Messages API request types ──────────────────────────────────────\n\ninterface ClaudeContentBlock {\n type:\n | \"text\"\n | \"tool_use\"\n | \"tool_result\"\n | \"image\"\n | \"document\"\n | \"thinking\"\n | \"redacted_thinking\";\n text?: string;\n id?: string;\n name?: string;\n input?: unknown;\n tool_use_id?: string;\n content?: string | ClaudeContentBlock[];\n is_error?: boolean;\n // Extended-thinking fields (Anthropic): `thinking` blocks carry the reasoning\n // text plus a cryptographic `signature`; `redacted_thinking` blocks carry an\n // opaque `data` payload instead.\n thinking?: string;\n signature?: string;\n data?: string;\n}\n\ninterface ClaudeMessage {\n role: \"user\" | \"assistant\";\n content: string | ClaudeContentBlock[];\n}\n\ninterface ClaudeToolDef {\n name: string;\n description?: string;\n input_schema?: object;\n}\n\ninterface ClaudeRequest {\n model: string;\n messages: ClaudeMessage[];\n system?: string | ClaudeContentBlock[];\n tools?: ClaudeToolDef[];\n tool_choice?: unknown;\n stream?: boolean;\n max_tokens: number;\n temperature?: number;\n // Extended-thinking config. Explicitly modeled so it is no longer swallowed\n // by the index signature below; read defensively (may be a non-object).\n thinking?: { type?: \"enabled\" | \"disabled\"; budget_tokens?: number };\n [key: string]: unknown;\n}\n\n// ─── Extended-thinking request invariants (Anthropic) ───────────────────────\n\n/**\n * A detected violation of the Anthropic extended-thinking request invariants on\n * a tool-loop continuation turn. `kind` distinguishes the three failure modes\n * so callers can template a per-kind error message and tests can assert without\n * string matching.\n */\ninterface ThinkingViolation {\n kind: \"missing_thinking_first\" | \"missing_signature\" | \"dropped_redacted_thinking\";\n messageIndex: number;\n observedFirstBlockType?: string;\n}\n\n// ─── Input conversion: Claude → ChatCompletions messages ────────────────────\n\nfunction extractClaudeTextContent(content: string | ClaudeContentBlock[]): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .filter((b) => b != null && typeof b === \"object\" && b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\");\n}\n\nexport function claudeToCompletionRequest(req: ClaudeRequest): ChatCompletionRequest {\n const messages: ChatMessage[] = [];\n\n // system field → system message\n if (req.system) {\n const systemText =\n typeof req.system === \"string\"\n ? req.system\n : Array.isArray(req.system)\n ? req.system\n .filter((b) => b != null && typeof b === \"object\" && b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\")\n : \"\";\n if (systemText) {\n messages.push({ role: \"system\", content: systemText });\n }\n }\n\n const reqMessages = Array.isArray(req.messages) ? req.messages : [];\n for (const msg of reqMessages) {\n // `req.messages` is untrusted JSON; entries may be null / non-object.\n if (!msg || typeof msg !== \"object\") continue;\n if (msg.role === \"user\") {\n // Check for tool_result blocks\n if (typeof msg.content !== \"string\" && Array.isArray(msg.content)) {\n // Content blocks are equally untrusted; skip null / non-object entries.\n const blocks = msg.content.filter((b) => b != null && typeof b === \"object\");\n const toolResults = blocks.filter((b) => b.type === \"tool_result\");\n const textBlocks = blocks.filter((b) => b.type === \"text\");\n\n if (toolResults.length > 0) {\n // Anthropic bundles a leg-2 tool_result and any accompanying user text\n // into ONE user-role message. We emit the accompanying text FIRST, then\n // the tool message(s), so the normalized shape is\n // `[..., user(text), tool]` — the tool message trails the last user\n // message and the current-turn `hasToolResult` predicate\n // ({@link currentTurnHasToolResult}) correctly classifies it `true`\n // (this IS a leg-2 turn that carries a tool result). Emitting the tool\n // FIRST would produce `[..., tool, user(text)]`, which is byte-identical\n // to a genuine turn-N leg-1 (a fresh user question after a completed\n // tool turn) and would be misclassified `false`. The source-message\n // grouping — that this text and this tool_result came from the SAME\n // Anthropic message — is only available here, so this ordering is the\n // only place the two cases can be told apart. The common\n // tool_result-only follow-up (no text blocks) is unaffected.\n if (textBlocks.length > 0) {\n messages.push({\n role: \"user\",\n content: textBlocks.map((b) => b.text ?? \"\").join(\"\"),\n });\n }\n // Each tool_result → tool message\n for (const tr of toolResults) {\n const resultContent =\n typeof tr.content === \"string\"\n ? tr.content\n : Array.isArray(tr.content)\n ? tr.content\n .filter((b) => b != null && typeof b === \"object\" && b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\")\n : \"\";\n messages.push({\n role: \"tool\",\n content: resultContent,\n tool_call_id: tr.tool_use_id,\n });\n }\n continue;\n }\n }\n // Regular user message\n messages.push({\n role: \"user\",\n content: extractClaudeTextContent(msg.content),\n });\n } else if (msg.role === \"assistant\") {\n if (typeof msg.content === \"string\") {\n messages.push({ role: \"assistant\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n const toolUseBlocks = msg.content.filter(\n (b) => b != null && typeof b === \"object\" && b.type === \"tool_use\",\n );\n // Only `text` blocks feed fixture matching; `thinking` /\n // `redacted_thinking` blocks are intentionally excluded from the\n // matchable content.\n const textContent = extractClaudeTextContent(msg.content);\n\n if (toolUseBlocks.length > 0) {\n messages.push({\n role: \"assistant\",\n content: textContent || null,\n tool_calls: toolUseBlocks.map((b) => ({\n id: b.id ?? generateToolUseId(),\n type: \"function\" as const,\n function: {\n name: b.name ?? \"\",\n arguments: typeof b.input === \"string\" ? b.input : JSON.stringify(b.input ?? {}),\n },\n })),\n });\n } else {\n messages.push({ role: \"assistant\", content: textContent || null });\n }\n } else {\n // null/undefined content — tool-only assistant turn\n messages.push({ role: \"assistant\", content: null });\n }\n }\n }\n\n // Convert tools\n let tools: ToolDefinition[] | undefined;\n if (req.tools && req.tools.length > 0) {\n tools = req.tools.map((t) => ({\n type: \"function\" as const,\n function: {\n name: t.name,\n description: t.description,\n parameters: t.input_schema,\n },\n }));\n }\n\n return {\n model: req.model,\n messages,\n stream: req.stream,\n temperature: req.temperature,\n max_tokens: req.max_tokens,\n tools,\n _endpointType: \"chat\",\n };\n}\n\n// ─── Extended-thinking invariant validation ─────────────────────────────────\n\n/** True iff `req.thinking` is an object with `type === \"enabled\"`. */\nfunction isThinkingEnabled(req: ClaudeRequest): boolean {\n const t = req.thinking;\n return typeof t === \"object\" && t !== null && (t as { type?: unknown }).type === \"enabled\";\n}\n\n/**\n * True iff the user turn at `req.messages[userIndex]` carries a `tool_result`\n * referencing one of `toolUseIds` — i.e. it answers the preceding assistant\n * turn's `tool_use` block(s), making that assistant turn a tool-loop\n * continuation point.\n */\nfunction userTurnAnswersToolUse(msg: ClaudeMessage | undefined, toolUseIds: Set<string>): boolean {\n if (!msg || msg.role !== \"user\" || !Array.isArray(msg.content)) return false;\n return msg.content.some(\n (b) =>\n b != null &&\n typeof b === \"object\" &&\n b.type === \"tool_result\" &&\n typeof b.tool_use_id === \"string\" &&\n toolUseIds.has(b.tool_use_id),\n );\n}\n\n/**\n * Validate the Anthropic extended-thinking request invariants on tool-loop\n * continuation turns. Pure: returns the first detected `ThinkingViolation` or\n * `null` when thinking is disabled or every in-scope turn is well-formed.\n *\n * Scope: an assistant turn is in-scope only when it (a) is array content\n * carrying at least one `tool_use` block and (b) is followed by a matching\n * `tool_result` on the next user turn. Text-only / `end_turn` turns, string or\n * empty turns, and trailing unanswered `tool_use` turns are all exempt.\n *\n * Scope detection assumes well-formed Anthropic transcripts: `tool_use` ids are\n * unique, and a tool_use turn is answered by the immediately-following user\n * turn's `tool_result` (adjacency). Malformed shapes — non-adjacent answers,\n * idless `tool_use` blocks, or a `tool_result` separated from its `tool_use` by\n * intervening turns — are intentionally treated as out-of-scope (and therefore\n * not 400'd) rather than validated, since the real Anthropic API would never\n * have produced them.\n */\nexport function validateThinkingInvariants(req: ClaudeRequest): ThinkingViolation | null {\n if (!isThinkingEnabled(req)) return null;\n\n const messages = Array.isArray(req.messages) ? req.messages : [];\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n // `req.messages` is untrusted JSON; entries may be null / non-object.\n if (!msg || typeof msg !== \"object\") continue;\n if (msg.role !== \"assistant\" || !Array.isArray(msg.content) || msg.content.length === 0) {\n continue;\n }\n\n const toolUseIds = new Set<string>();\n for (const b of msg.content) {\n // Content blocks are equally untrusted; skip null / non-object entries.\n if (!b || typeof b !== \"object\") continue;\n if (b.type === \"tool_use\" && typeof b.id === \"string\") toolUseIds.add(b.id);\n }\n // Not a tool_use-bearing turn → not a reasoning-bearing continuation turn.\n if (toolUseIds.size === 0) continue;\n // Trailing/unanswered tool_use (no matching tool_result follows) → out of scope.\n if (!userTurnAnswersToolUse(messages[i + 1], toolUseIds)) continue;\n\n const first = msg.content[0];\n\n // A null / non-object leading block cannot be a thinking block → it\n // violates invariant (a) just as a wrong-typed block would.\n if (!first || typeof first !== \"object\") {\n return {\n kind: \"missing_thinking_first\",\n messageIndex: i,\n observedFirstBlockType: undefined,\n };\n }\n\n // (a) The in-scope turn must lead with a thinking / redacted_thinking block.\n if (first.type !== \"thinking\" && first.type !== \"redacted_thinking\") {\n return {\n kind: \"missing_thinking_first\",\n messageIndex: i,\n observedFirstBlockType: first.type,\n };\n }\n\n // (b) A leading `thinking` block must carry a non-empty string `signature`.\n if (first.type === \"thinking\") {\n if (typeof first.signature !== \"string\" || first.signature.length === 0) {\n return { kind: \"missing_signature\", messageIndex: i };\n }\n }\n\n // (c) A leading `redacted_thinking` block must preserve a non-empty `data`.\n if (first.type === \"redacted_thinking\") {\n if (typeof first.data !== \"string\" || first.data.length === 0) {\n return { kind: \"dropped_redacted_thinking\", messageIndex: i };\n }\n }\n }\n\n return null;\n}\n\n/** Render the Anthropic-shaped 400 error message for a thinking violation. */\nfunction thinkingViolationMessage(v: ThinkingViolation): string {\n const prefix = `messages.${v.messageIndex}.content.0`;\n switch (v.kind) {\n case \"missing_thinking_first\":\n return `${prefix}: when \\`thinking\\` is enabled, a tool-loop continuation assistant turn must begin with a \\`thinking\\` block; got \\`${v.observedFirstBlockType ?? \"unknown\"}\\`.`;\n case \"missing_signature\":\n return `${prefix}: the leading \\`thinking\\` block is missing a non-empty \\`signature\\`.`;\n case \"dropped_redacted_thinking\":\n return `${prefix}: the leading \\`redacted_thinking\\` block must preserve its \\`data\\`.`;\n }\n}\n\n// ─── Response building: fixture → Claude Messages API format ────────────────\n\nfunction claudeStopReason(finishReason: string | undefined, defaultReason: string): string {\n if (!finishReason) return defaultReason;\n if (finishReason === \"stop\") return \"end_turn\";\n if (finishReason === \"tool_calls\") return \"tool_use\";\n if (finishReason === \"length\") return \"max_tokens\";\n return finishReason;\n}\n\nfunction claudeUsage(overrides?: ResponseOverrides): {\n input_tokens: number;\n output_tokens: number;\n} {\n if (!overrides?.usage) return { input_tokens: 0, output_tokens: 0 };\n return {\n input_tokens: overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? 0,\n output_tokens: overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? 0,\n };\n}\n\ninterface ClaudeSSEEvent {\n type: string;\n [key: string]: unknown;\n}\n\n/**\n * Emit faithful Anthropic `redacted_thinking` content-block events at the head\n * of a streamed turn — one `content_block_start` (carrying the opaque `data`)\n * and `content_block_stop` per recorded block, with NO deltas (real Anthropic\n * delivers the encrypted reasoning entirely on the start event). Returns the\n * next free block index. When `redactedThinking` is empty/absent this is a\n * no-op, so no events are added.\n *\n * Leading placement keeps the turn round-trip-safe for the extended-thinking\n * leading-block invariant (a thinking / redacted_thinking block must come\n * first). It does NOT reproduce real Anthropic's stream order: aimock joins all\n * plaintext reasoning into one block and emits all redacted blocks ahead of it,\n * whereas real Anthropic interleaves `thinking` and `redacted_thinking` in the\n * order they occurred. The interleaving between the two is not preserved.\n */\nfunction pushRedactedThinkingStreamEvents(\n events: ClaudeSSEEvent[],\n startIndex: number,\n redactedThinking: string[] | undefined,\n): number {\n let blockIndex = startIndex;\n for (const data of redactedThinking ?? []) {\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"redacted_thinking\", data },\n });\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n blockIndex++;\n }\n return blockIndex;\n}\n\nfunction buildClaudeTextStreamEvents(\n content: string,\n model: string,\n chunkSize: number,\n reasoning?: string,\n overrides?: ResponseOverrides,\n reasoningSignature?: string,\n redactedThinking?: string[],\n): ClaudeSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const effectiveModel = overrides?.model ?? model;\n // Prefer a recorded real signature when one was captured; otherwise fall back\n // to the round-trip-safe placeholder.\n const signature = reasoningSignature ?? PLACEHOLDER_SIGNATURE;\n const events: ClaudeSSEEvent[] = [];\n\n // message_start\n events.push({\n type: \"message_start\",\n message: {\n id: msgId,\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: [],\n model: effectiveModel,\n stop_reason: null,\n stop_sequence: null,\n usage: claudeUsage(overrides),\n },\n });\n\n let blockIndex = 0;\n\n // Redacted-thinking blocks lead the turn (before any thinking / text) to\n // satisfy the leading-block invariant on replay; see the helper for the\n // ordering caveat.\n blockIndex = pushRedactedThinkingStreamEvents(events, blockIndex, redactedThinking);\n\n // Thinking block (emitted before text when reasoning is present)\n if (reasoning) {\n // Real Anthropic emits an empty `signature` on the thinking\n // `content_block_start`; the cryptographic signature arrives only via the\n // trailing `signature_delta`. Mirror that wire shape here.\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"thinking\", thinking: \"\", signature: \"\" },\n });\n\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"thinking_delta\", thinking: slice },\n });\n }\n\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"signature_delta\", signature },\n });\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n // content_block_start (text)\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"text\", text: \"\" },\n });\n\n // content_block_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_block_delta\",\n index: blockIndex,\n delta: { type: \"text_delta\", text: slice },\n });\n }\n\n // content_block_stop\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(overrides?.finishReason, \"end_turn\"),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n}\n\nfunction buildClaudeToolCallStreamEvents(\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n reasoningSignature?: string,\n redactedThinking?: string[],\n): ClaudeSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const effectiveModel = overrides?.model ?? model;\n // Prefer a recorded real signature when one was captured; otherwise fall back\n // to the round-trip-safe placeholder.\n const signature = reasoningSignature ?? PLACEHOLDER_SIGNATURE;\n const events: ClaudeSSEEvent[] = [];\n\n // message_start\n events.push({\n type: \"message_start\",\n message: {\n id: msgId,\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: [],\n model: effectiveModel,\n stop_reason: null,\n stop_sequence: null,\n usage: claudeUsage(overrides),\n },\n });\n\n let blockIndex = 0;\n\n // Redacted-thinking blocks lead the turn (before thinking / tool_use blocks)\n // to satisfy the extended-thinking leading-block invariant on replay; see the\n // helper for the ordering caveat.\n blockIndex = pushRedactedThinkingStreamEvents(events, blockIndex, redactedThinking);\n\n // Optional thinking block (emitted before the tool_use blocks when reasoning\n // is present). Mirrors buildClaudeContentWithToolCallsStreamEvents exactly so\n // a pure-tool-call turn under extended thinking emits a leading thinking\n // block — without it, replaying the emitted turn under strict self-trips\n // `missing_thinking_first`.\n if (reasoning) {\n // Real Anthropic emits an empty `signature` on the thinking\n // `content_block_start`; the cryptographic signature arrives only via the\n // trailing `signature_delta`. Mirror that wire shape here.\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"thinking\", thinking: \"\", signature: \"\" },\n });\n\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"thinking_delta\", thinking: slice },\n });\n }\n\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"signature_delta\", signature },\n });\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n for (const tc of toolCalls) {\n const toolUseId = tc.id || generateToolUseId();\n\n // Parse arguments to JSON object (Claude uses objects, not strings)\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n const argsJson = JSON.stringify(argsObj);\n\n // content_block_start\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: {\n type: \"tool_use\",\n id: toolUseId,\n name: tc.name,\n input: {},\n },\n });\n\n // content_block_delta — input_json_delta chunks\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"input_json_delta\", partial_json: slice },\n });\n }\n\n // content_block_stop\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n}\n\n// Non-streaming response builders\n\n/**\n * Push faithful Anthropic `redacted_thinking` content blocks (each a\n * `{ type: \"redacted_thinking\", data }`) onto a non-streaming content array, in\n * recorded order. No-op when `redactedThinking` is empty/absent, so no blocks\n * are added.\n *\n * Leading placement keeps the turn round-trip-safe for the extended-thinking\n * leading-block invariant. It does NOT reproduce real Anthropic's block order:\n * aimock joins all plaintext reasoning into one block and emits all redacted\n * blocks ahead of it, whereas real Anthropic interleaves `thinking` and\n * `redacted_thinking` in occurrence order. The interleaving is not preserved.\n */\nfunction pushRedactedThinkingBlocks(\n contentBlocks: object[],\n redactedThinking: string[] | undefined,\n): void {\n for (const data of redactedThinking ?? []) {\n contentBlocks.push({ type: \"redacted_thinking\", data });\n }\n}\n\nfunction buildClaudeTextResponse(\n content: string,\n model: string,\n reasoning?: string,\n overrides?: ResponseOverrides,\n reasoningSignature?: string,\n redactedThinking?: string[],\n): object {\n const contentBlocks: object[] = [];\n\n // Redacted-thinking blocks lead the content array (before thinking / text);\n // see the helper for the ordering caveat.\n pushRedactedThinkingBlocks(contentBlocks, redactedThinking);\n\n if (reasoning) {\n contentBlocks.push({\n type: \"thinking\",\n thinking: reasoning,\n // Prefer a recorded real signature; otherwise the round-trip-safe placeholder.\n signature: reasoningSignature ?? PLACEHOLDER_SIGNATURE,\n });\n }\n\n contentBlocks.push({ type: \"text\", text: content });\n\n return {\n id: overrides?.id ?? generateMessageId(),\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: contentBlocks,\n model: overrides?.model ?? model,\n stop_reason: claudeStopReason(overrides?.finishReason, \"end_turn\"),\n stop_sequence: null,\n usage: claudeUsage(overrides),\n };\n}\n\nfunction buildClaudeToolCallResponse(\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n reasoningSignature?: string,\n redactedThinking?: string[],\n): object {\n const contentBlocks: object[] = [];\n\n // Redacted-thinking blocks lead the content array (before thinking / tool_use)\n // to satisfy the leading-block invariant on replay; see the helper for the\n // ordering caveat.\n pushRedactedThinkingBlocks(contentBlocks, redactedThinking);\n\n // Leading thinking block when reasoning is present — mirrors\n // buildClaudeContentWithToolCallsResponse so a pure-tool-call turn under\n // extended thinking carries the same leading thinking block.\n if (reasoning) {\n contentBlocks.push({\n type: \"thinking\",\n thinking: reasoning,\n // Prefer a recorded real signature; otherwise the round-trip-safe placeholder.\n signature: reasoningSignature ?? PLACEHOLDER_SIGNATURE,\n });\n }\n\n for (const tc of toolCalls) {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n contentBlocks.push({\n type: \"tool_use\",\n id: tc.id || generateToolUseId(),\n name: tc.name,\n input: argsObj,\n });\n }\n\n return {\n id: overrides?.id ?? generateMessageId(),\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: contentBlocks,\n model: overrides?.model ?? model,\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n usage: claudeUsage(overrides),\n };\n}\n\nfunction buildClaudeContentWithToolCallsStreamEvents(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n reasoningSignature?: string,\n redactedThinking?: string[],\n blocks?: FixtureBlock[],\n): ClaudeSSEEvent[] {\n const msgId = overrides?.id ?? generateMessageId();\n const effectiveModel = overrides?.model ?? model;\n // Prefer a recorded real signature when one was captured; otherwise fall back\n // to the round-trip-safe placeholder.\n const signature = reasoningSignature ?? PLACEHOLDER_SIGNATURE;\n const events: ClaudeSSEEvent[] = [];\n\n // message_start\n events.push({\n type: \"message_start\",\n message: {\n id: msgId,\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: [],\n model: effectiveModel,\n stop_reason: null,\n stop_sequence: null,\n usage: claudeUsage(overrides),\n },\n });\n\n let blockIndex = 0;\n\n // Redacted-thinking blocks lead the turn (before thinking / text / tool_use);\n // see the helper for the ordering caveat. Applies to both the legacy and the\n // ordered-`blocks` paths.\n blockIndex = pushRedactedThinkingStreamEvents(events, blockIndex, redactedThinking);\n\n // Optional thinking block — also shared by both paths.\n if (reasoning) {\n // Real Anthropic emits an empty `signature` on the thinking\n // `content_block_start`; the cryptographic signature arrives only via the\n // trailing `signature_delta`. Mirror that wire shape here.\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"thinking\", thinking: \"\", signature: \"\" },\n });\n\n for (let i = 0; i < reasoning.length; i += chunkSize) {\n const slice = reasoning.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"thinking_delta\", thinking: slice },\n });\n }\n\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"signature_delta\", signature },\n });\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n if (blocks && blocks.length > 0) {\n // NEW PATH: stream `text`/`tool_use` content blocks in the fixture's array\n // order. Anthropic is fully tool-first capable — a `toolCall` block can take\n // a lower `index` than a `text` block. Content-block indices are assigned in\n // encounter order, continuing from any leading thinking/redacted blocks.\n const outcome = resolveFixtureBlockOutcome(blocks);\n const ordered = outcome.ordered;\n\n for (const block of ordered) {\n if (block.type === \"text\") {\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"text\", text: \"\" },\n });\n\n for (let i = 0; i < block.text.length; i += chunkSize) {\n const slice = block.text.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"text_delta\", text: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n } else {\n const toolUseId = block.id || generateToolUseId();\n\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(block.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${block.name}\": ${block.arguments}`,\n );\n argsObj = {};\n }\n const argsJson = JSON.stringify(argsObj);\n\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: {\n type: \"tool_use\",\n id: toolUseId,\n name: block.name,\n input: {},\n },\n });\n\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"input_json_delta\", partial_json: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n }\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(\n overrides?.finishReason,\n outcome.hasToolCalls ? \"tool_use\" : \"end_turn\",\n ),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n }\n\n // LEGACY PATH (byte-for-byte unchanged): text content block, then tool_use\n // blocks in `toolCalls` order. Reached only when `blocks` is absent; the\n // leading redacted-thinking/thinking blocks above are shared with the new\n // path and produce identical wire output here.\n // Text content block\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: { type: \"text\", text: \"\" },\n });\n\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"text_delta\", text: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n\n // Tool use blocks\n for (const tc of toolCalls) {\n const toolUseId = tc.id || generateToolUseId();\n\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n const argsJson = JSON.stringify(argsObj);\n\n events.push({\n type: \"content_block_start\",\n index: blockIndex,\n content_block: {\n type: \"tool_use\",\n id: toolUseId,\n name: tc.name,\n input: {},\n },\n });\n\n for (let i = 0; i < argsJson.length; i += chunkSize) {\n const slice = argsJson.slice(i, i + chunkSize);\n events.push({\n type: \"content_block_delta\",\n index: blockIndex,\n delta: { type: \"input_json_delta\", partial_json: slice },\n });\n }\n\n events.push({\n type: \"content_block_stop\",\n index: blockIndex,\n });\n\n blockIndex++;\n }\n\n // message_delta\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: claudeStopReason(overrides?.finishReason, \"tool_use\"),\n stop_sequence: null,\n },\n usage: { output_tokens: claudeUsage(overrides).output_tokens },\n });\n\n // message_stop\n events.push({ type: \"message_stop\" });\n\n return events;\n}\n\nfunction buildClaudeContentWithToolCallsResponse(\n content: string,\n toolCalls: ToolCall[],\n model: string,\n logger: Logger,\n reasoning?: string,\n overrides?: ResponseOverrides,\n reasoningSignature?: string,\n redactedThinking?: string[],\n blocks?: FixtureBlock[],\n): object {\n const contentBlocks: object[] = [];\n\n // Redacted-thinking blocks lead the content array (before thinking / text /\n // tool_use); see the helper for the ordering caveat.\n pushRedactedThinkingBlocks(contentBlocks, redactedThinking);\n\n if (reasoning) {\n contentBlocks.push({\n type: \"thinking\",\n thinking: reasoning,\n // Prefer a recorded real signature; otherwise the round-trip-safe placeholder.\n signature: reasoningSignature ?? PLACEHOLDER_SIGNATURE,\n });\n }\n\n // Build a tool_use content block from a fixture tool call, parsing its\n // string `arguments` into the object `input` Anthropic emits (warning on\n // malformed JSON, same idiom as the streaming/legacy paths).\n const toolUseBlock = (tc: { name: string; arguments: string; id?: string }): object => {\n let argsObj: unknown;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\");\n } catch {\n logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n type: \"tool_use\",\n id: tc.id || generateToolUseId(),\n name: tc.name,\n input: argsObj,\n };\n };\n\n let blockHasTools: boolean | undefined;\n if (blocks && blocks.length > 0) {\n // NEW PATH: the non-streaming `content[]` array is positionally observable,\n // so emit `text`/`tool_use` content blocks in the fixture's ARRAY ORDER\n // (after any leading redacted/thinking blocks). A toolCall block before a\n // text block therefore yields a tool_use ahead of the text — matching the\n // streaming path for the same `blocks` fixture.\n const outcome = resolveFixtureBlockOutcome(blocks);\n const ordered = outcome.ordered;\n blockHasTools = outcome.hasToolCalls;\n for (const block of ordered) {\n if (block.type === \"text\") {\n contentBlocks.push({ type: \"text\", text: block.text });\n } else {\n contentBlocks.push(\n toolUseBlock({ name: block.name, arguments: block.arguments, id: block.id }),\n );\n }\n }\n } else {\n // LEGACY PATH (unchanged): text content block, then tool_use blocks.\n contentBlocks.push({ type: \"text\", text: content });\n for (const tc of toolCalls) {\n contentBlocks.push(toolUseBlock(tc));\n }\n }\n\n return {\n id: overrides?.id ?? generateMessageId(),\n type: \"message\",\n role: overrides?.role ?? \"assistant\",\n content: contentBlocks,\n model: overrides?.model ?? model,\n stop_reason: claudeStopReason(\n overrides?.finishReason,\n blockHasTools === false ? \"end_turn\" : \"tool_use\",\n ),\n stop_sequence: null,\n usage: claudeUsage(overrides),\n };\n}\n\n// ─── SSE writer for Claude Messages API ─────────────────────────────────────\n\ninterface ClaudeStreamOptions {\n latency?: number;\n streamingProfile?: StreamingProfile;\n recordedTimings?: RecordedTimings;\n replaySpeed?: number;\n signal?: AbortSignal;\n onChunkSent?: () => void;\n}\n\nasync function writeClaudeSSEStream(\n res: http.ServerResponse,\n events: ClaudeSSEEvent[],\n optionsOrLatency?: number | ClaudeStreamOptions,\n): Promise<boolean> {\n const opts: ClaudeStreamOptions =\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 handleMessages(\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 claudeReq: ClaudeRequest;\n try {\n claudeReq = JSON.parse(raw) as ClaudeRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Malformed JSON: ${detail}`,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `claudeReq.thinking` throws a TypeError that\n // surfaces as a 500 instead of a 400.\n if (!isJsonObject(claudeReq)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\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 // Extended-thinking invariant validation. The validator runs whenever\n // thinking is enabled (it self-short-circuits to null otherwise). On a\n // detected violation: strict ON → 400, strict OFF → warn + replay. Mirrors\n // the real Anthropic API, which 400s on these.\n const thinkingViolation = validateThinkingInvariants(claudeReq);\n if (thinkingViolation) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const violationMessage = thinkingViolationMessage(thinkingViolation);\n if (effectiveStrict) {\n logger.error(`THINKING: ${violationMessage}`);\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: null,\n response: {\n status: 400,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n type: \"error\",\n error: {\n type: \"invalid_request_error\",\n message: violationMessage,\n },\n }),\n );\n return;\n }\n logger.warn(`THINKING: ${violationMessage} (strict off — replaying anyway)`);\n // Fall through to existing match/replay behavior.\n }\n\n // Convert to ChatCompletionRequest for fixture matching\n const completionReq = claudeToCompletionRequest(claudeReq);\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 const lastUserMsg = completionReq.messages.filter((m) => m.role === \"user\").pop();\n const snippet =\n typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content.slice(0, 80) : \"\";\n logger.debug(\n `No fixture matched for request (model=${completionReq.model ?? \"?\"}, msg=\"${snippet}\")`,\n );\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 ?? \"/v1/messages\",\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(\n req.method ?? \"POST\",\n req.url ?? \"/v1/messages\",\n skippedBySequenceOrTurn,\n ),\n );\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\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 \"anthropic\",\n req.url ?? \"/v1/messages\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\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 ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status, fixture },\n });\n // Anthropic-style error format: { type: \"error\", error: { type, message } }\n const anthropicError = {\n type: \"error\",\n error: {\n type: response.error.type ?? \"api_error\",\n message: response.error.message,\n },\n };\n writeErrorResponse(res, status, JSON.stringify(anthropicError), {\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 Claude Messages 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 completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const { reasoningSignature: effReasoningSignature, redactedThinking: effRedactedThinking } =\n resolveReasoningArtifactsForModel(\n response.reasoningSignature,\n response.redactedThinking,\n completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (claudeReq.stream !== true) {\n const body = buildClaudeContentWithToolCallsResponse(\n response.content ?? \"\",\n response.toolCalls ?? [],\n completionReq.model,\n logger,\n effReasoning,\n overrides,\n effReasoningSignature,\n effRedactedThinking,\n response.blocks,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildClaudeContentWithToolCallsStreamEvents(\n response.content ?? \"\",\n response.toolCalls ?? [],\n completionReq.model,\n chunkSize,\n logger,\n effReasoning,\n overrides,\n effReasoningSignature,\n effRedactedThinking,\n response.blocks,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeClaudeSSEStream(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 Claude Messages 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 completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const { reasoningSignature: effReasoningSignature, redactedThinking: effRedactedThinking } =\n resolveReasoningArtifactsForModel(\n response.reasoningSignature,\n response.redactedThinking,\n completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (claudeReq.stream !== true) {\n const body = buildClaudeTextResponse(\n response.content,\n completionReq.model,\n effReasoning,\n overrides,\n effReasoningSignature,\n effRedactedThinking,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildClaudeTextStreamEvents(\n response.content,\n completionReq.model,\n chunkSize,\n effReasoning,\n overrides,\n effReasoningSignature,\n effRedactedThinking,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeClaudeSSEStream(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 Claude Messages 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 completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const { reasoningSignature: effReasoningSignature, redactedThinking: effRedactedThinking } =\n resolveReasoningArtifactsForModel(\n response.reasoningSignature,\n response.redactedThinking,\n completionReq.model,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 200, fixture },\n });\n if (claudeReq.stream !== true) {\n const body = buildClaudeToolCallResponse(\n response.toolCalls,\n completionReq.model,\n logger,\n effReasoning,\n overrides,\n effReasoningSignature,\n effRedactedThinking,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n } else {\n const events = buildClaudeToolCallStreamEvents(\n response.toolCalls,\n completionReq.model,\n chunkSize,\n logger,\n effReasoning,\n overrides,\n effReasoningSignature,\n effRedactedThinking,\n );\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeClaudeSSEStream(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 ?? \"/v1/messages\",\n headers: flattenHeaders(req.headers),\n body: completionReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response did not match any known type\",\n type: \"server_error\",\n },\n }),\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.cts","names":[],"sources":["../src/messages.ts"],"sourcesContent":[],"mappings":";;;;;;iBAsrCsB,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}
1
+ {"version":3,"file":"messages.d.cts","names":[],"sources":["../src/messages.ts"],"sourcesContent":[],"mappings":";;;;;;iBAgsCsB,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","names":[],"sources":["../src/messages.ts"],"sourcesContent":[],"mappings":";;;;;;iBAsrCsB,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}
1
+ {"version":3,"file":"messages.d.ts","names":[],"sources":["../src/messages.ts"],"sourcesContent":[],"mappings":";;;;;;iBAgsCsB,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B"}