@copilotkit/aimock 1.43.0 → 1.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +46 -0
  4. package/README.md +14 -2
  5. package/dist/agui-handler.d.ts.map +1 -1
  6. package/dist/aimock-cli.cjs +31 -5
  7. package/dist/aimock-cli.cjs.map +1 -1
  8. package/dist/aimock-cli.d.cts.map +1 -1
  9. package/dist/aimock-cli.d.ts.map +1 -1
  10. package/dist/aimock-cli.js +31 -5
  11. package/dist/aimock-cli.js.map +1 -1
  12. package/dist/bedrock-converse.cjs +344 -43
  13. package/dist/bedrock-converse.cjs.map +1 -1
  14. package/dist/bedrock-converse.d.cts.map +1 -1
  15. package/dist/bedrock-converse.d.ts.map +1 -1
  16. package/dist/bedrock-converse.js +345 -44
  17. package/dist/bedrock-converse.js.map +1 -1
  18. package/dist/bedrock.cjs +195 -42
  19. package/dist/bedrock.cjs.map +1 -1
  20. package/dist/bedrock.d.cts.map +1 -1
  21. package/dist/bedrock.d.ts.map +1 -1
  22. package/dist/bedrock.js +196 -43
  23. package/dist/bedrock.js.map +1 -1
  24. package/dist/chaos.cjs +9 -5
  25. package/dist/chaos.cjs.map +1 -1
  26. package/dist/chaos.d.cts.map +1 -1
  27. package/dist/chaos.d.ts.map +1 -1
  28. package/dist/chaos.js +10 -7
  29. package/dist/chaos.js.map +1 -1
  30. package/dist/cli.cjs +238 -9
  31. package/dist/cli.cjs.map +1 -1
  32. package/dist/cli.js +242 -13
  33. package/dist/cli.js.map +1 -1
  34. package/dist/cohere.cjs +159 -72
  35. package/dist/cohere.cjs.map +1 -1
  36. package/dist/cohere.d.cts.map +1 -1
  37. package/dist/cohere.d.ts.map +1 -1
  38. package/dist/cohere.js +160 -73
  39. package/dist/cohere.js.map +1 -1
  40. package/dist/config-loader.cjs +63 -5
  41. package/dist/config-loader.cjs.map +1 -1
  42. package/dist/config-loader.d.cts +37 -4
  43. package/dist/config-loader.d.cts.map +1 -1
  44. package/dist/config-loader.d.ts +37 -4
  45. package/dist/config-loader.d.ts.map +1 -1
  46. package/dist/config-loader.js +63 -5
  47. package/dist/config-loader.js.map +1 -1
  48. package/dist/constants.cjs +8 -0
  49. package/dist/constants.cjs.map +1 -1
  50. package/dist/constants.d.cts +6 -2
  51. package/dist/constants.d.ts +6 -2
  52. package/dist/constants.js +8 -1
  53. package/dist/constants.js.map +1 -1
  54. package/dist/echo-text.cjs +65 -0
  55. package/dist/echo-text.cjs.map +1 -0
  56. package/dist/echo-text.d.cts +22 -0
  57. package/dist/echo-text.d.cts.map +1 -0
  58. package/dist/echo-text.d.ts +22 -0
  59. package/dist/echo-text.d.ts.map +1 -0
  60. package/dist/echo-text.js +65 -0
  61. package/dist/echo-text.js.map +1 -0
  62. package/dist/embeddings.cjs +18 -1
  63. package/dist/embeddings.cjs.map +1 -1
  64. package/dist/embeddings.d.cts +1 -1
  65. package/dist/embeddings.d.cts.map +1 -1
  66. package/dist/embeddings.d.ts +1 -1
  67. package/dist/embeddings.d.ts.map +1 -1
  68. package/dist/embeddings.js +18 -1
  69. package/dist/embeddings.js.map +1 -1
  70. package/dist/fakes-plugin.cjs +131 -0
  71. package/dist/fakes-plugin.cjs.map +1 -0
  72. package/dist/fakes-plugin.d.cts +23 -0
  73. package/dist/fakes-plugin.d.cts.map +1 -0
  74. package/dist/fakes-plugin.d.ts +23 -0
  75. package/dist/fakes-plugin.d.ts.map +1 -0
  76. package/dist/fakes-plugin.js +127 -0
  77. package/dist/fakes-plugin.js.map +1 -0
  78. package/dist/files.cjs +9 -11
  79. package/dist/files.cjs.map +1 -1
  80. package/dist/files.d.cts.map +1 -1
  81. package/dist/files.d.ts.map +1 -1
  82. package/dist/files.js +10 -13
  83. package/dist/files.js.map +1 -1
  84. package/dist/fine-tuning.cjs +1 -19
  85. package/dist/fine-tuning.cjs.map +1 -1
  86. package/dist/fine-tuning.d.cts.map +1 -1
  87. package/dist/fine-tuning.d.ts.map +1 -1
  88. package/dist/fine-tuning.js +2 -20
  89. package/dist/fine-tuning.js.map +1 -1
  90. package/dist/fixture-loader-services.cjs +116 -0
  91. package/dist/fixture-loader-services.cjs.map +1 -0
  92. package/dist/fixture-loader-services.d.cts +48 -0
  93. package/dist/fixture-loader-services.d.cts.map +1 -0
  94. package/dist/fixture-loader-services.d.ts +48 -0
  95. package/dist/fixture-loader-services.d.ts.map +1 -0
  96. package/dist/fixture-loader-services.js +114 -0
  97. package/dist/fixture-loader-services.js.map +1 -0
  98. package/dist/fixture-loader.cjs +552 -29
  99. package/dist/fixture-loader.cjs.map +1 -1
  100. package/dist/fixture-loader.d.cts +140 -2
  101. package/dist/fixture-loader.d.cts.map +1 -1
  102. package/dist/fixture-loader.d.ts +140 -2
  103. package/dist/fixture-loader.d.ts.map +1 -1
  104. package/dist/fixture-loader.js +542 -31
  105. package/dist/fixture-loader.js.map +1 -1
  106. package/dist/gemini-embeddings.cjs +42 -2
  107. package/dist/gemini-embeddings.cjs.map +1 -1
  108. package/dist/gemini-embeddings.js +43 -3
  109. package/dist/gemini-embeddings.js.map +1 -1
  110. package/dist/gemini-interactions.cjs +288 -52
  111. package/dist/gemini-interactions.cjs.map +1 -1
  112. package/dist/gemini-interactions.d.cts.map +1 -1
  113. package/dist/gemini-interactions.d.ts.map +1 -1
  114. package/dist/gemini-interactions.js +289 -53
  115. package/dist/gemini-interactions.js.map +1 -1
  116. package/dist/gemini.cjs +234 -38
  117. package/dist/gemini.cjs.map +1 -1
  118. package/dist/gemini.d.cts.map +1 -1
  119. package/dist/gemini.d.ts.map +1 -1
  120. package/dist/gemini.js +235 -39
  121. package/dist/gemini.js.map +1 -1
  122. package/dist/helpers.cjs +1157 -12
  123. package/dist/helpers.cjs.map +1 -1
  124. package/dist/helpers.d.cts +85 -4
  125. package/dist/helpers.d.cts.map +1 -1
  126. package/dist/helpers.d.ts +85 -4
  127. package/dist/helpers.d.ts.map +1 -1
  128. package/dist/helpers.js +1113 -14
  129. package/dist/helpers.js.map +1 -1
  130. package/dist/images.cjs +3 -2
  131. package/dist/images.cjs.map +1 -1
  132. package/dist/images.js +3 -2
  133. package/dist/images.js.map +1 -1
  134. package/dist/index.cjs +39 -1
  135. package/dist/index.d.cts +11 -4
  136. package/dist/index.d.ts +11 -4
  137. package/dist/index.js +11 -4
  138. package/dist/jest.cjs +43 -14
  139. package/dist/jest.cjs.map +1 -1
  140. package/dist/jest.d.cts +47 -5
  141. package/dist/jest.d.cts.map +1 -1
  142. package/dist/jest.d.ts +47 -5
  143. package/dist/jest.d.ts.map +1 -1
  144. package/dist/jest.js +45 -16
  145. package/dist/jest.js.map +1 -1
  146. package/dist/journal.cjs +155 -13
  147. package/dist/journal.cjs.map +1 -1
  148. package/dist/journal.d.cts +54 -4
  149. package/dist/journal.d.cts.map +1 -1
  150. package/dist/journal.d.ts +54 -4
  151. package/dist/journal.d.ts.map +1 -1
  152. package/dist/journal.js +155 -13
  153. package/dist/journal.js.map +1 -1
  154. package/dist/live-sanitize.cjs +4 -32
  155. package/dist/live-sanitize.cjs.map +1 -1
  156. package/dist/live-sanitize.js +4 -32
  157. package/dist/live-sanitize.js.map +1 -1
  158. package/dist/llmock.cjs +204 -39
  159. package/dist/llmock.cjs.map +1 -1
  160. package/dist/llmock.d.cts +51 -1
  161. package/dist/llmock.d.cts.map +1 -1
  162. package/dist/llmock.d.ts +51 -1
  163. package/dist/llmock.d.ts.map +1 -1
  164. package/dist/llmock.js +206 -41
  165. package/dist/llmock.js.map +1 -1
  166. package/dist/mcp-fakes-mount.cjs +217 -0
  167. package/dist/mcp-fakes-mount.cjs.map +1 -0
  168. package/dist/mcp-fakes-mount.js +211 -0
  169. package/dist/mcp-fakes-mount.js.map +1 -0
  170. package/dist/mcp-fakes-report.cjs +111 -0
  171. package/dist/mcp-fakes-report.cjs.map +1 -0
  172. package/dist/mcp-fakes-report.d.cts +40 -0
  173. package/dist/mcp-fakes-report.d.cts.map +1 -0
  174. package/dist/mcp-fakes-report.d.ts +40 -0
  175. package/dist/mcp-fakes-report.d.ts.map +1 -0
  176. package/dist/mcp-fakes-report.js +107 -0
  177. package/dist/mcp-fakes-report.js.map +1 -0
  178. package/dist/mcp-fakes.cjs +1942 -0
  179. package/dist/mcp-fakes.cjs.map +1 -0
  180. package/dist/mcp-fakes.d.cts +504 -0
  181. package/dist/mcp-fakes.d.cts.map +1 -0
  182. package/dist/mcp-fakes.d.ts +504 -0
  183. package/dist/mcp-fakes.d.ts.map +1 -0
  184. package/dist/mcp-fakes.js +1937 -0
  185. package/dist/mcp-fakes.js.map +1 -0
  186. package/dist/mcp-handler.cjs +534 -27
  187. package/dist/mcp-handler.cjs.map +1 -1
  188. package/dist/mcp-handler.d.cts +49 -0
  189. package/dist/mcp-handler.d.cts.map +1 -0
  190. package/dist/mcp-handler.d.ts +49 -0
  191. package/dist/mcp-handler.d.ts.map +1 -0
  192. package/dist/mcp-handler.js +530 -28
  193. package/dist/mcp-handler.js.map +1 -1
  194. package/dist/mcp-mock.cjs +326 -47
  195. package/dist/mcp-mock.cjs.map +1 -1
  196. package/dist/mcp-mock.d.cts +97 -1
  197. package/dist/mcp-mock.d.cts.map +1 -1
  198. package/dist/mcp-mock.d.ts +97 -1
  199. package/dist/mcp-mock.d.ts.map +1 -1
  200. package/dist/mcp-mock.js +327 -48
  201. package/dist/mcp-mock.js.map +1 -1
  202. package/dist/mcp-recorder.cjs +1224 -0
  203. package/dist/mcp-recorder.cjs.map +1 -0
  204. package/dist/mcp-recorder.d.cts +108 -0
  205. package/dist/mcp-recorder.d.cts.map +1 -0
  206. package/dist/mcp-recorder.d.ts +108 -0
  207. package/dist/mcp-recorder.d.ts.map +1 -0
  208. package/dist/mcp-recorder.js +1215 -0
  209. package/dist/mcp-recorder.js.map +1 -0
  210. package/dist/mcp-stub.cjs +5 -1
  211. package/dist/mcp-stub.d.cts +3 -1
  212. package/dist/mcp-stub.d.ts +3 -1
  213. package/dist/mcp-stub.js +3 -1
  214. package/dist/mcp-types.d.cts +6 -0
  215. package/dist/mcp-types.d.ts +6 -0
  216. package/dist/message-text.cjs +192 -0
  217. package/dist/message-text.cjs.map +1 -0
  218. package/dist/message-text.d.cts +31 -0
  219. package/dist/message-text.d.cts.map +1 -0
  220. package/dist/message-text.d.ts +31 -0
  221. package/dist/message-text.d.ts.map +1 -0
  222. package/dist/message-text.js +184 -0
  223. package/dist/message-text.js.map +1 -0
  224. package/dist/messages.cjs +400 -56
  225. package/dist/messages.cjs.map +1 -1
  226. package/dist/messages.d.cts.map +1 -1
  227. package/dist/messages.d.ts.map +1 -1
  228. package/dist/messages.js +401 -58
  229. package/dist/messages.js.map +1 -1
  230. package/dist/metrics.cjs +46 -66
  231. package/dist/metrics.cjs.map +1 -1
  232. package/dist/metrics.d.cts +14 -6
  233. package/dist/metrics.d.cts.map +1 -1
  234. package/dist/metrics.d.ts +14 -6
  235. package/dist/metrics.d.ts.map +1 -1
  236. package/dist/metrics.js +32 -40
  237. package/dist/metrics.js.map +1 -1
  238. package/dist/misbehavior.cjs +1523 -0
  239. package/dist/misbehavior.cjs.map +1 -0
  240. package/dist/misbehavior.d.cts +43 -0
  241. package/dist/misbehavior.d.cts.map +1 -0
  242. package/dist/misbehavior.d.ts +43 -0
  243. package/dist/misbehavior.d.ts.map +1 -0
  244. package/dist/misbehavior.js +1511 -0
  245. package/dist/misbehavior.js.map +1 -0
  246. package/dist/ollama.cjs +315 -113
  247. package/dist/ollama.cjs.map +1 -1
  248. package/dist/ollama.d.cts.map +1 -1
  249. package/dist/ollama.d.ts.map +1 -1
  250. package/dist/ollama.js +316 -114
  251. package/dist/ollama.js.map +1 -1
  252. package/dist/openapi.cjs +3405 -0
  253. package/dist/openapi.cjs.map +1 -0
  254. package/dist/openapi.d.cts +30 -0
  255. package/dist/openapi.d.cts.map +1 -0
  256. package/dist/openapi.d.ts +30 -0
  257. package/dist/openapi.d.ts.map +1 -0
  258. package/dist/openapi.js +3404 -0
  259. package/dist/openapi.js.map +1 -0
  260. package/dist/openrouter-video.cjs +4 -4
  261. package/dist/openrouter-video.cjs.map +1 -1
  262. package/dist/openrouter-video.d.cts.map +1 -1
  263. package/dist/openrouter-video.d.ts.map +1 -1
  264. package/dist/openrouter-video.js +4 -4
  265. package/dist/openrouter-video.js.map +1 -1
  266. package/dist/record-sanitize.cjs +231 -0
  267. package/dist/record-sanitize.cjs.map +1 -0
  268. package/dist/record-sanitize.js +224 -0
  269. package/dist/record-sanitize.js.map +1 -0
  270. package/dist/recorder.cjs +115 -6
  271. package/dist/recorder.cjs.map +1 -1
  272. package/dist/recorder.d.cts +2 -1
  273. package/dist/recorder.d.cts.map +1 -1
  274. package/dist/recorder.d.ts +2 -1
  275. package/dist/recorder.d.ts.map +1 -1
  276. package/dist/recorder.js +116 -8
  277. package/dist/recorder.js.map +1 -1
  278. package/dist/responses.cjs +701 -166
  279. package/dist/responses.cjs.map +1 -1
  280. package/dist/responses.d.cts +5 -13
  281. package/dist/responses.d.cts.map +1 -1
  282. package/dist/responses.d.ts +5 -13
  283. package/dist/responses.d.ts.map +1 -1
  284. package/dist/responses.js +699 -169
  285. package/dist/responses.js.map +1 -1
  286. package/dist/route-registry.cjs +951 -0
  287. package/dist/route-registry.cjs.map +1 -0
  288. package/dist/route-registry.d.cts +33 -0
  289. package/dist/route-registry.d.cts.map +1 -0
  290. package/dist/route-registry.d.ts +33 -0
  291. package/dist/route-registry.d.ts.map +1 -0
  292. package/dist/route-registry.js +866 -0
  293. package/dist/route-registry.js.map +1 -0
  294. package/dist/router.cjs +24 -2
  295. package/dist/router.cjs.map +1 -1
  296. package/dist/router.d.cts.map +1 -1
  297. package/dist/router.d.ts.map +1 -1
  298. package/dist/router.js +25 -4
  299. package/dist/router.js.map +1 -1
  300. package/dist/server.cjs +1159 -264
  301. package/dist/server.cjs.map +1 -1
  302. package/dist/server.d.cts +4 -1
  303. package/dist/server.d.cts.map +1 -1
  304. package/dist/server.d.ts +4 -1
  305. package/dist/server.d.ts.map +1 -1
  306. package/dist/server.js +1067 -172
  307. package/dist/server.js.map +1 -1
  308. package/dist/speech.cjs +4 -2
  309. package/dist/speech.cjs.map +1 -1
  310. package/dist/speech.js +4 -2
  311. package/dist/speech.js.map +1 -1
  312. package/dist/stream-collapse.cjs +236 -34
  313. package/dist/stream-collapse.cjs.map +1 -1
  314. package/dist/stream-collapse.d.cts +39 -4
  315. package/dist/stream-collapse.d.cts.map +1 -1
  316. package/dist/stream-collapse.d.ts +39 -4
  317. package/dist/stream-collapse.d.ts.map +1 -1
  318. package/dist/stream-collapse.js +235 -35
  319. package/dist/stream-collapse.js.map +1 -1
  320. package/dist/suite.cjs +1 -1
  321. package/dist/suite.js +1 -1
  322. package/dist/transcription.cjs +2 -2
  323. package/dist/transcription.cjs.map +1 -1
  324. package/dist/transcription.d.cts.map +1 -1
  325. package/dist/transcription.d.ts.map +1 -1
  326. package/dist/transcription.js +2 -2
  327. package/dist/transcription.js.map +1 -1
  328. package/dist/types.cjs +18 -0
  329. package/dist/types.cjs.map +1 -0
  330. package/dist/types.d.cts +516 -5
  331. package/dist/types.d.cts.map +1 -1
  332. package/dist/types.d.ts +516 -5
  333. package/dist/types.d.ts.map +1 -1
  334. package/dist/types.js +17 -0
  335. package/dist/types.js.map +1 -0
  336. package/dist/validate-cli.cjs +123 -33
  337. package/dist/validate-cli.cjs.map +1 -1
  338. package/dist/validate-cli.js +125 -35
  339. package/dist/validate-cli.js.map +1 -1
  340. package/dist/vector-stores.cjs +1180 -0
  341. package/dist/vector-stores.cjs.map +1 -0
  342. package/dist/vector-stores.d.cts +106 -0
  343. package/dist/vector-stores.d.cts.map +1 -0
  344. package/dist/vector-stores.d.ts +106 -0
  345. package/dist/vector-stores.d.ts.map +1 -0
  346. package/dist/vector-stores.js +1164 -0
  347. package/dist/vector-stores.js.map +1 -0
  348. package/dist/vector-types.d.cts.map +1 -1
  349. package/dist/version.cjs +45 -0
  350. package/dist/version.cjs.map +1 -0
  351. package/dist/version.js +44 -0
  352. package/dist/version.js.map +1 -0
  353. package/dist/video.cjs +19 -0
  354. package/dist/video.cjs.map +1 -1
  355. package/dist/video.d.cts.map +1 -1
  356. package/dist/video.d.ts.map +1 -1
  357. package/dist/video.js +19 -0
  358. package/dist/video.js.map +1 -1
  359. package/dist/vitest.cjs +77 -16
  360. package/dist/vitest.cjs.map +1 -1
  361. package/dist/vitest.d.cts +38 -5
  362. package/dist/vitest.d.cts.map +1 -1
  363. package/dist/vitest.d.ts +38 -5
  364. package/dist/vitest.d.ts.map +1 -1
  365. package/dist/vitest.js +78 -17
  366. package/dist/vitest.js.map +1 -1
  367. package/dist/watcher.cjs +6 -2
  368. package/dist/watcher.cjs.map +1 -1
  369. package/dist/watcher.js +6 -2
  370. package/dist/watcher.js.map +1 -1
  371. package/dist/ws-gemini-live.cjs +210 -101
  372. package/dist/ws-gemini-live.cjs.map +1 -1
  373. package/dist/ws-gemini-live.d.cts +9 -3
  374. package/dist/ws-gemini-live.d.cts.map +1 -1
  375. package/dist/ws-gemini-live.d.ts +9 -3
  376. package/dist/ws-gemini-live.d.ts.map +1 -1
  377. package/dist/ws-gemini-live.js +211 -102
  378. package/dist/ws-gemini-live.js.map +1 -1
  379. package/dist/ws-realtime.cjs +175 -62
  380. package/dist/ws-realtime.cjs.map +1 -1
  381. package/dist/ws-realtime.d.cts +8 -3
  382. package/dist/ws-realtime.d.cts.map +1 -1
  383. package/dist/ws-realtime.d.ts +8 -3
  384. package/dist/ws-realtime.d.ts.map +1 -1
  385. package/dist/ws-realtime.js +176 -63
  386. package/dist/ws-realtime.js.map +1 -1
  387. package/dist/ws-responses.cjs +121 -16
  388. package/dist/ws-responses.cjs.map +1 -1
  389. package/dist/ws-responses.d.cts +8 -12
  390. package/dist/ws-responses.d.cts.map +1 -1
  391. package/dist/ws-responses.d.ts +8 -12
  392. package/dist/ws-responses.d.ts.map +1 -1
  393. package/dist/ws-responses.js +123 -18
  394. package/dist/ws-responses.js.map +1 -1
  395. package/package.json +13 -2
  396. package/skills/write-fixtures/SKILL.md +179 -21
package/dist/server.cjs CHANGED
@@ -1,10 +1,12 @@
1
1
  const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
2
2
  const require_constants = require('./constants.cjs');
3
+ const require_message_text = require('./message-text.cjs');
3
4
  const require_api_key_auth = require('./api-key-auth.cjs');
4
5
  const require_helpers = require('./helpers.cjs');
5
6
  const require_live_fixture = require('./live-fixture.cjs');
6
7
  const require_sse_writer = require('./sse-writer.cjs');
7
8
  const require_chaos = require('./chaos.cjs');
9
+ const require_misbehavior = require('./misbehavior.cjs');
8
10
  const require_fixture_loader = require('./fixture-loader.cjs');
9
11
  const require_router = require('./router.cjs');
10
12
  const require_recorder = require('./recorder.cjs');
@@ -38,6 +40,7 @@ const require_search = require('./search.cjs');
38
40
  const require_rerank = require('./rerank.cjs');
39
41
  const require_moderation = require('./moderation.cjs');
40
42
  const require_fine_tuning = require('./fine-tuning.cjs');
43
+ const require_vector_stores = require('./vector-stores.cjs');
41
44
  const require_files = require('./files.cjs');
42
45
  const require_batches = require('./batches.cjs');
43
46
  const require_ws_framing = require('./ws-framing.cjs');
@@ -45,42 +48,19 @@ const require_ws_live = require('./ws-live.cjs');
45
48
  const require_ws_responses = require('./ws-responses.cjs');
46
49
  const require_ws_realtime = require('./ws-realtime.cjs');
47
50
  const require_ws_gemini_live = require('./ws-gemini-live.cjs');
51
+ const require_route_registry = require('./route-registry.cjs');
52
+ const require_openapi = require('./openapi.cjs');
48
53
  const require_metrics = require('./metrics.cjs');
54
+ const require_mcp_fakes = require('./mcp-fakes.cjs');
55
+ const require_mcp_mock = require('./mcp-mock.cjs');
56
+ const require_mcp_fakes_mount = require('./mcp-fakes-mount.cjs');
57
+ const require_mcp_fakes_report = require('./mcp-fakes-report.cjs');
49
58
  let node_http = require("node:http");
50
59
  node_http = require_runtime.__toESM(node_http);
51
60
  let node_async_hooks = require("node:async_hooks");
52
61
 
53
62
  //#region src/server.ts
54
63
  const liveClosers = /* @__PURE__ */ new WeakMap();
55
- const COMPLETIONS_PATH = "/v1/chat/completions";
56
- const RESPONSES_PATH = "/v1/responses";
57
- const LIVE_PATH = "/v1/live/sessions";
58
- const REALTIME_PATH = "/v1/realtime";
59
- const GEMINI_LIVE_PATH = "/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent";
60
- const MESSAGES_PATH = "/v1/messages";
61
- const EMBEDDINGS_PATH = "/v1/embeddings";
62
- const COHERE_CHAT_PATH = "/v2/chat";
63
- const COHERE_EMBED_PATH = "/v2/embed";
64
- const SEARCH_PATH = "/search";
65
- const RERANK_PATH = "/v2/rerank";
66
- const MODERATIONS_PATH = "/v1/moderations";
67
- const IMAGES_PATH = "/v1/images/generations";
68
- const IMAGES_EDIT_PATH = "/v1/images/edits";
69
- const IMAGES_VARIATIONS_PATH = "/v1/images/variations";
70
- const SPEECH_PATH = "/v1/audio/speech";
71
- const TRANSCRIPTIONS_PATH = "/v1/audio/transcriptions";
72
- const TRANSLATIONS_PATH = "/v1/audio/translations";
73
- const VIDEOS_PATH = "/v1/videos";
74
- const GEMINI_PREDICT_RE = /^\/v1beta\/models\/([^:]+):predict$/;
75
- const ELEVENLABS_SOUND_GENERATION_PATH = "/v1/sound-generation";
76
- const ELEVENLABS_TTS_RE = /^\/v1\/text-to-speech\/([^/]+)$/;
77
- const ELEVENLABS_MUSIC_RE = /^\/v1\/music(?:\/(.+))?$/;
78
- const ELEVENLABS_VOICE_DESIGN_PATH = "/v1/text-to-voice/design";
79
- const ELEVENLABS_VOICE_CREATE_PATH = "/v1/text-to-voice";
80
- const ELEVENLABS_VOICE_RE = /^\/v1\/voices\/([^/]+)$/;
81
- const FAL_QUEUE_SUBMIT_RE = /^\/fal\/queue\/submit\/(.+)$/;
82
- const FAL_QUEUE_REQUESTS_RE = /^\/fal\/queue\/requests\/(.+)$/;
83
- const FAL_RUN_RE = /^\/fal\/run\/(.+)$/;
84
64
  const DEFAULT_CHUNK_SIZE = 20;
85
65
  const COMPAT_SUFFIXES = [
86
66
  "/chat/completions",
@@ -109,34 +89,6 @@ function normalizeCompatPath(pathname, logger) {
109
89
  }
110
90
  return pathname;
111
91
  }
112
- const GEMINI_INTERACTIONS_PATH = "/v1beta/interactions";
113
- const GEMINI_PATH_RE = /^\/v1beta\/models\/([^:]+):(generateContent|streamGenerateContent)$/;
114
- const GEMINI_EMBED_RE = /^\/v1beta\/models\/([^:]+):embedContent$/;
115
- const AZURE_DEPLOYMENT_RE = /^\/openai\/deployments\/([^/]+)\/(chat\/completions|embeddings)$/;
116
- const BEDROCK_INVOKE_RE = /^\/model\/([^/]+)\/invoke$/;
117
- const BEDROCK_STREAM_RE = /^\/model\/([^/]+)\/invoke-with-response-stream$/;
118
- const BEDROCK_CONVERSE_RE = /^\/model\/([^/]+)\/converse$/;
119
- const BEDROCK_CONVERSE_STREAM_RE = /^\/model\/([^/]+)\/converse-stream$/;
120
- const VERTEX_AI_RE = /^\/v1\/projects\/[^/]+\/locations\/[^/]+\/publishers\/google\/models\/([^/:]+):(generateContent|streamGenerateContent)$/;
121
- const OLLAMA_CHAT_PATH = "/api/chat";
122
- const OLLAMA_GENERATE_PATH = "/api/generate";
123
- const OLLAMA_EMBEDDINGS_PATH = "/api/embeddings";
124
- const OLLAMA_EMBED_PATH = "/api/embed";
125
- const OLLAMA_TAGS_PATH = "/api/tags";
126
- const OPENROUTER_VIDEOS_PATH = "/api/v1/videos";
127
- const OPENROUTER_VIDEO_MODELS_PATH = "/api/v1/videos/models";
128
- const HEALTH_PATH = "/health";
129
- const READY_PATH = "/ready";
130
- const MODELS_PATH = "/v1/models";
131
- const REQUESTS_PATH = "/v1/_requests";
132
- const BATCHES_PATH = "/v1/batches";
133
- const BATCHES_ID_RE = /^\/v1\/batches\/([^/]+)$/;
134
- const BATCHES_CANCEL_RE = /^\/v1\/batches\/([^/]+)\/cancel$/;
135
- const FILES_PATH = "/v1/files";
136
- const FINE_TUNING_JOBS_PATH = "/v1/fine_tuning/jobs";
137
- const FINE_TUNING_ID_RE = /^\/v1\/fine_tuning\/jobs\/([^/]+)$/;
138
- const FINE_TUNING_CANCEL_RE = /^\/v1\/fine_tuning\/jobs\/([^/]+)\/cancel$/;
139
- const FINE_TUNING_EVENTS_RE = /^\/v1\/fine_tuning\/jobs\/([^/]+)\/events$/;
140
92
  const DEFAULT_MODELS = [
141
93
  "gpt-4",
142
94
  "gpt-4o",
@@ -146,7 +98,7 @@ const DEFAULT_MODELS = [
146
98
  ];
147
99
  const CORS_HEADERS = {
148
100
  "Access-Control-Allow-Origin": "*",
149
- "Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS",
101
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
150
102
  "Access-Control-Allow-Headers": "*",
151
103
  "Access-Control-Expose-Headers": "X-Total-Count, X-Request-Id"
152
104
  };
@@ -165,7 +117,6 @@ function handleNotFound(res, message) {
165
117
  type: "not_found"
166
118
  } }));
167
119
  }
168
- const CONTROL_PREFIX = "/__aimock";
169
120
  /** The complete `GET /__aimock/fixtures` query-param vocabulary; anything else 400s. */
170
121
  const FIXTURES_PARAMS = new Set(["include"]);
171
122
  /** The complete `GET /__aimock/journal` query-param vocabulary; anything else 400s. */
@@ -204,6 +155,7 @@ function performFullReset(fixtures, targets) {
204
155
  require_elevenlabs_voice.clearElevenLabsVoices();
205
156
  require_files.clearFileStore();
206
157
  require_fine_tuning.clearFineTuningStore();
158
+ require_vector_stores.clearVectorStoreStore();
207
159
  require_gemini_interactions.resetInteractionCounter();
208
160
  require_gemini_interactions.resetEventIdCounter();
209
161
  if (!targets) return;
@@ -211,11 +163,13 @@ function performFullReset(fixtures, targets) {
211
163
  targets.journal.clear();
212
164
  require_chaos.resetChaosWarnings(targets.defaults.logger);
213
165
  targets.defaults.chaos = void 0;
166
+ targets.defaults.misbehavior?.byTestId.clear();
214
167
  targets.videoStates.clear();
215
168
  targets.openRouterVideoJobs.clear();
216
169
  targets.veoVideoJobs.clear();
217
170
  targets.grokVideoJobs.clear();
218
171
  targets.bytePlusVideoJobs.clear();
172
+ for (const { handler } of targets.mounts ?? []) handler.clearMcpFakes?.();
219
173
  if (targets.defaults.registry) targets.defaults.registry.setGauge("aimock_fixtures_loaded", {}, fixtures.length);
220
174
  }
221
175
  /**
@@ -255,7 +209,7 @@ function fixtureResponseKind(response) {
255
209
  if (require_helpers.isImageResponse(response)) return "image";
256
210
  if (require_helpers.isEmbeddingResponse(response)) return "embedding";
257
211
  if (require_helpers.isJSONResponse(response)) return "json";
258
- if (require_helpers.isContentWithToolCallsResponse(response)) return "contentWithToolCalls";
212
+ if (require_helpers.isCombinedFixtureResponse(response)) return "contentWithToolCalls";
259
213
  if (require_helpers.isToolCallResponse(response)) return "toolCalls";
260
214
  if (require_helpers.isTextResponse(response)) return "text";
261
215
  return "unknown";
@@ -270,9 +224,14 @@ function fixtureResponseKind(response) {
270
224
  * scoping path does not also do. (Splitting on "," additionally broke every
271
225
  * legitimately comma-bearing id.) A raw `path.includes("testId=t1")` both
272
226
  * prefix-collides with `t10` and matches unrelated params like `notTestId`.
227
+ *
228
+ * An MCP mount records the test id it resolved on the entry (I9, B3): a
229
+ * decoded header or query value, or the one bound to the session at
230
+ * `initialize`. That value wins; LLM entries carry none and are attributed as
231
+ * before.
273
232
  */
274
233
  function journalEntryTestId(entry) {
275
- return require_helpers.resolveTestId(entry.headers, entry.path);
234
+ return entry.testId ?? require_helpers.resolveTestId(entry.headers, entry.path);
276
235
  }
277
236
  /**
278
237
  * The testId a chaos override is stored under, and read back with — resolved by
@@ -311,19 +270,188 @@ function effectiveChaos(defaults, scopeId) {
311
270
  if (!current) return {};
312
271
  return require_chaos.isChaosScope(current) ? current.base ?? {} : current;
313
272
  }
273
+ /** The `GET /__aimock/mcp/fakes` query-param vocabulary; anything else 400s. */
274
+ const MCP_FAKES_PARAMS = new Set([
275
+ "testId",
276
+ "context",
277
+ "mount"
278
+ ]);
279
+ /** A block's `mount` path, read without running getters; the add validates it. */
280
+ function controlFakeMountOf(raw) {
281
+ if (typeof raw !== "object" || raw === null) return require_mcp_fakes.MCP_FAKES_DEFAULT_MOUNT;
282
+ const value = Object.getOwnPropertyDescriptor(raw, "mount")?.value;
283
+ return typeof value === "string" ? value : require_mcp_fakes.MCP_FAKES_DEFAULT_MOUNT;
284
+ }
285
+ /**
286
+ * Check one `POST /__aimock/fixtures` `mcpFakes` value against the live
287
+ * mounts (F10, W6) without changing anything. Returns every error in input
288
+ * order (an empty list when the value can be added), and `apply`, which adds
289
+ * the blocks (auto-mounting an MCPMock where no mount serves a block's path)
290
+ * and returns the number of blocks added.
291
+ *
292
+ * The whole value is checked before any mount is touched, and the check
293
+ * never adds to a real mount: each group is added to a throwaway store,
294
+ * whose errors are the ones reported (it numbers the add `control-api#1`, as
295
+ * a new mount would; for an existing MCPMock the rejected group is re-run on
296
+ * its atomic add, so the errors name that mount's next `<n>`, I7). A group
297
+ * whose path no request to it can reach (a mount that is not an MCPMock
298
+ * serves it, an MCPMock answers it as its root, or it is under the control
299
+ * prefix) is a mount conflict (one error per block).
300
+ */
301
+ function planControlApiFakes(raw, mounts) {
302
+ const items = Array.isArray(raw) ? raw.map((block, position) => ({
303
+ position,
304
+ source: {
305
+ source: "control-api",
306
+ blockIndex: position,
307
+ raw: block
308
+ }
309
+ })) : [{
310
+ position: 0,
311
+ source: {
312
+ source: "control-api",
313
+ blockIndex: null,
314
+ raw
315
+ }
316
+ }];
317
+ const groups = /* @__PURE__ */ new Map();
318
+ if (items.length === 0) groups.set(require_mcp_fakes.MCP_FAKES_DEFAULT_MOUNT, {
319
+ path: require_mcp_fakes.MCP_FAKES_DEFAULT_MOUNT,
320
+ positions: [],
321
+ sources: []
322
+ });
323
+ for (const { position, source } of items) {
324
+ const path = controlFakeMountOf(source.raw);
325
+ const group = groups.get(path) ?? {
326
+ path,
327
+ positions: [],
328
+ sources: []
329
+ };
330
+ group.positions.push(position);
331
+ group.sources.push(source);
332
+ groups.set(path, group);
333
+ }
334
+ const found = [];
335
+ /** The paths `apply` auto-mounts, in order. */
336
+ const pending = [];
337
+ for (const group of groups.values()) {
338
+ const target = require_mcp_fakes_mount.findFakeMount(mounts, group.path, pending);
339
+ if (target.kind === "conflict") {
340
+ group.positions.forEach((position) => {
341
+ const where = Array.isArray(raw) ? require_message_text.msg`mcpFakes[${position}]` : require_message_text.msg`mcpFakes`;
342
+ found.push({
343
+ position,
344
+ error: new require_fixture_loader.FixtureLoadError({
345
+ rule: "mcp-fakes/mount-conflict",
346
+ file: null,
347
+ blockId: null,
348
+ entryId: null,
349
+ detail: require_message_text.msg`${where}: ${require_mcp_fakes_mount.mountConflictDetail(group.path, target)}`
350
+ })
351
+ });
352
+ });
353
+ continue;
354
+ }
355
+ let failure = addFailure(() => new require_mcp_fakes.McpFakeStore().add(group.sources, { kind: "control-api" }));
356
+ if (target.kind === "none") pending.push(group.path);
357
+ if (!failure) continue;
358
+ if (target.kind === "mcp" && target.handler.addMcpFakes === require_mcp_mock.MCPMock.prototype.addMcpFakes) {
359
+ const handler = target.handler;
360
+ failure = addFailure(() => handler.addMcpFakes?.(group.sources, { kind: "control-api" })) ?? failure;
361
+ }
362
+ for (const error of failure.errors) found.push({
363
+ position: positionOf(error, group),
364
+ error
365
+ });
366
+ }
367
+ found.sort((a, b) => a.position - b.position);
368
+ return {
369
+ errors: found.map((f) => f.error),
370
+ apply(wiring) {
371
+ let added = 0;
372
+ for (const group of groups.values()) {
373
+ const target = require_mcp_fakes_mount.ensureFakeMount(mounts, group.path, {
374
+ journal: wiring.journal,
375
+ registry: wiring.defaults.registry,
376
+ logger: wiring.defaults.logger,
377
+ replaySpeed: wiring.defaults.replaySpeed
378
+ }, wiring.defaults.logger);
379
+ if ("conflict" in target) continue;
380
+ const result = target.handler.addMcpFakes?.(group.sources, { kind: "control-api" });
381
+ for (const warning of result?.warnings ?? []) wiring.defaults.logger.warn(warning.message);
382
+ added += group.sources.length;
383
+ }
384
+ return added;
385
+ }
386
+ };
387
+ }
388
+ /** The `McpFakesAddError` that `add` throws, or `null` when it adds. */
389
+ function addFailure(add) {
390
+ try {
391
+ add();
392
+ return null;
393
+ } catch (err) {
394
+ if (err instanceof require_mcp_fakes.McpFakesAddError) return err;
395
+ throw err;
396
+ }
397
+ }
398
+ /**
399
+ * The request position of the block an add error names. The add numbers a
400
+ * run-time group's blocks by their place in the group (`[<j>]`), or gives no
401
+ * index to a single-object value; an error tied to no block sorts with the
402
+ * group's first block.
403
+ */
404
+ function positionOf(error, group) {
405
+ const first = group.positions[0] ?? 0;
406
+ if (error.blockId == null || error.file === null) return first;
407
+ const at = group.positions.findIndex((_, j) => error.blockId === require_mcp_fakes.blockIdOf(error.file ?? "", "", j));
408
+ return at === -1 ? first : group.positions[at];
409
+ }
410
+ function hasFakesSnapshot(handler) {
411
+ return "fakesSnapshot" in handler && typeof handler.fakesSnapshot === "function";
412
+ }
413
+ /**
414
+ * `GET /__aimock/mcp/fakes` (spec 6.5, I9): for each MCP mount (or the one
415
+ * named by `mount`), the blocks that apply to the requested test id and
416
+ * context, with every entry id and its consumed state for that test id.
417
+ * A mount is listed when it takes fakes (it implements `addMcpFakes`, the
418
+ * check every other fakes path uses); one with no `fakesSnapshot` lists no
419
+ * blocks.
420
+ */
421
+ function listControlApiFakes(mounts, testId, context, mount) {
422
+ const listed = mounts.flatMap(({ path, handler }) => require_mcp_fakes_mount.isFakeMount(handler) && (mount === null || path === mount) ? [{
423
+ mount: path,
424
+ blocks: hasFakesSnapshot(handler) ? handler.fakesSnapshot(testId, context) : []
425
+ }] : []);
426
+ return mount !== null && listed.length === 0 ? null : listed;
427
+ }
428
+ const controlFixtureAdditions = /* @__PURE__ */ new WeakMap();
314
429
  /**
315
430
  * Handle requests under `/__aimock/`. Returns `true` if the request was
316
431
  * handled, `false` if the path doesn't match the control prefix.
317
432
  */
318
- async function handleControlAPI(req, res, pathname, searchParams, fixtures, journal, videoStates, openRouterVideoJobs, veoVideoJobs, grokVideoJobs, bytePlusVideoJobs, defaults) {
319
- if (!pathname.startsWith(CONTROL_PREFIX)) return false;
320
- const subPath = pathname.slice(9);
433
+ async function handleControlAPI(req, res, pathname, searchParams, fixtures, journal, videoStates, openRouterVideoJobs, veoVideoJobs, grokVideoJobs, bytePlusVideoJobs, defaults, mounts) {
434
+ if (!pathname.startsWith(require_route_registry.CONTROL_PREFIX)) return false;
435
+ const subPath = pathname.slice(require_route_registry.CONTROL_PREFIX.length);
321
436
  setCorsHeaders(res);
322
437
  if (subPath === "/health" && req.method === "GET") {
323
438
  res.writeHead(200, { "Content-Type": "application/json" });
324
439
  res.end(JSON.stringify({ status: "ok" }));
325
440
  return true;
326
441
  }
442
+ if (subPath === "/openapi.json" && req.method === "GET") {
443
+ res.writeHead(200, { "Content-Type": "application/json" });
444
+ res.end(JSON.stringify(require_openapi.buildOpenApiDocument()));
445
+ return true;
446
+ }
447
+ if (subPath === "/routes" && req.method === "GET") {
448
+ res.writeHead(200, { "Content-Type": "application/json" });
449
+ res.end(JSON.stringify({
450
+ count: require_openapi.CATALOG_ROUTES.length,
451
+ routes: require_openapi.CATALOG_ROUTES
452
+ }));
453
+ return true;
454
+ }
327
455
  if (subPath === "/journal" && req.method === "GET") {
328
456
  const bad = (message) => {
329
457
  res.writeHead(400, { "Content-Type": "application/json" });
@@ -369,7 +497,7 @@ async function handleControlAPI(req, res, pathname, searchParams, fixtures, jour
369
497
  "Content-Type": "application/json",
370
498
  "X-Total-Count": String(total)
371
499
  });
372
- res.end(JSON.stringify(entries));
500
+ res.end(journalJson(entries, journal));
373
501
  return true;
374
502
  }
375
503
  if (subPath === "/fixtures" && req.method === "GET") {
@@ -389,19 +517,70 @@ async function handleControlAPI(req, res, pathname, searchParams, fixtures, jour
389
517
  res.end(JSON.stringify({ error: "Invalid 'include': expected 'fixtures'" }));
390
518
  return true;
391
519
  }
520
+ const extendedTools = require_helpers.isExtendedResponsesToolsList(fixtures);
392
521
  res.writeHead(200, { "Content-Type": "application/json" });
393
522
  res.end(JSON.stringify({
394
523
  count: fixtures.length,
395
524
  fixtures: fixtures.map((fixture, index) => ({
396
525
  index,
397
526
  match: redactForInspection(fixture.match),
398
- responseKind: require_fixture_loader.isOneShotError(fixture) ? "error" : fixtureResponseKind(fixture.response),
527
+ responseKind: require_fixture_loader.isOneShotError(fixture) ? "error" : fixtureResponseKind(extendedTools || typeof fixture.response === "function" ? fixture.response : require_helpers.withoutResponsesToolKeys(fixture.response)),
399
528
  ...fixture.latency !== void 0 ? { latency: fixture.latency } : {},
400
529
  ...fixture.chaos !== void 0 ? { chaos: fixture.chaos } : {}
401
530
  }))
402
531
  }));
403
532
  return true;
404
533
  }
534
+ if (subPath === "/misbehavior/catalog" && req.method === "GET") {
535
+ res.writeHead(200, { "Content-Type": "application/json" });
536
+ res.end(JSON.stringify({
537
+ catalog: require_misbehavior.MISBEHAVIOR_CATALOG,
538
+ WIRE_SUPPORT: require_misbehavior.WIRE_SUPPORT
539
+ }));
540
+ return true;
541
+ }
542
+ if (subPath === "/misbehavior" && (req.method === "GET" || req.method === "POST" || req.method === "DELETE")) {
543
+ const scopeId = chaosScopeId(req);
544
+ if (scopeId === null) return writeBlankTestId(res);
545
+ const reply = (status, body) => {
546
+ res.writeHead(status, { "Content-Type": "application/json" });
547
+ res.end(JSON.stringify(body));
548
+ return true;
549
+ };
550
+ const scope = defaults.misbehavior;
551
+ if (!scope && req.method !== "GET") return reply(409, { error: "misbehavior is not enabled: start aimock with enableMisbehavior: true (CLI: --misbehavior)" });
552
+ if (req.method === "POST") {
553
+ let raw;
554
+ try {
555
+ raw = await require_helpers.readBody(req);
556
+ } catch (err) {
557
+ const msg = err instanceof Error ? err.message : String(err);
558
+ defaults.logger.error(`POST /__aimock/misbehavior: failed to read body: ${msg}`);
559
+ return reply(400, { error: `Failed to read request body: ${msg}` });
560
+ }
561
+ let input;
562
+ try {
563
+ input = JSON.parse(raw);
564
+ } catch (err) {
565
+ const msg = err instanceof Error ? err.message : String(err);
566
+ defaults.logger.error(`POST /__aimock/misbehavior: invalid JSON: ${msg}`);
567
+ return reply(400, { error: `Invalid JSON: ${msg}` });
568
+ }
569
+ if (require_helpers.isJsonObject(input) && Object.keys(input).length === 0) input = { faults: [] };
570
+ const parsed = require_misbehavior.parseMisbehavior(input);
571
+ if (!parsed.ok) return reply(400, {
572
+ error: "Validation failed",
573
+ rule: parsed.issue.rule,
574
+ message: parsed.issue.message
575
+ });
576
+ const config = parsed.config.seed === "random" ? {
577
+ ...parsed.config,
578
+ seed: require_misbehavior.resolveMisbehaviorSeed(parsed.config.seed, defaults.logger)
579
+ } : parsed.config;
580
+ scope?.byTestId.set(scopeId, config);
581
+ } else if (req.method === "DELETE") scope?.byTestId.delete(scopeId);
582
+ return reply(200, { misbehavior: scope?.byTestId.get(scopeId) ?? scope?.baseline ?? { faults: [] } });
583
+ }
405
584
  if (subPath === "/chaos" && req.method === "GET") {
406
585
  const scopeId = chaosScopeId(req);
407
586
  if (scopeId === null) return writeBlankTestId(res);
@@ -474,6 +653,25 @@ async function handleControlAPI(req, res, pathname, searchParams, fixtures, jour
474
653
  res.end(JSON.stringify({ chaos: effectiveChaos(defaults, scopeId) }));
475
654
  return true;
476
655
  }
656
+ if (subPath === "/mcp/fakes" && req.method === "GET") {
657
+ const reply = (status, body) => {
658
+ res.writeHead(status, { "Content-Type": "application/json" });
659
+ res.end(JSON.stringify(body));
660
+ return true;
661
+ };
662
+ for (const key of searchParams.keys()) if (!MCP_FAKES_PARAMS.has(key)) return reply(400, { error: `Unknown query parameter: '${key}'. Supported: ${[...MCP_FAKES_PARAMS].join(", ")}` });
663
+ const testId = searchParams.get("testId") || null;
664
+ const context = searchParams.get("context") || null;
665
+ const mount = searchParams.get("mount") || null;
666
+ const listed = listControlApiFakes(mounts, testId, context, mount);
667
+ if (listed === null) return reply(404, { error: require_message_text.build(require_message_text.msg`No MCP mount at ${require_message_text.quote(mount ?? "")}`) });
668
+ return reply(200, {
669
+ testId,
670
+ context,
671
+ mounts: listed
672
+ });
673
+ }
674
+ if (subPath === "/mcp/fakes/report" && req.method === "GET") return require_mcp_fakes_report.handleFakesReportRoute(res, searchParams, mounts);
477
675
  if (subPath === "/fixtures" && req.method === "POST") {
478
676
  let raw;
479
677
  try {
@@ -495,29 +693,82 @@ async function handleControlAPI(req, res, pathname, searchParams, fixtures, jour
495
693
  res.end(JSON.stringify({ error: `Invalid JSON: ${msg}` }));
496
694
  return true;
497
695
  }
498
- if (!Array.isArray(parsed.fixtures)) {
696
+ const withFakes = typeof parsed === "object" && parsed !== null && Object.hasOwn(parsed, "mcpFakes");
697
+ if (parsed === null || !Array.isArray(parsed.fixtures) && !(withFakes && parsed.fixtures === void 0)) {
499
698
  res.writeHead(400, { "Content-Type": "application/json" });
500
699
  res.end(JSON.stringify({ error: "Missing or invalid \"fixtures\" array" }));
501
700
  return true;
502
701
  }
503
- const converted = parsed.fixtures.map((e) => require_fixture_loader.entryToFixture(e));
504
- const errors = require_fixture_loader.validateFixtures(converted).filter((i) => i.severity === "error");
505
- if (errors.length > 0) {
702
+ const entries = Array.isArray(parsed.fixtures) ? parsed.fixtures : [];
703
+ const missingMatchIndex = entries.findIndex((entry) => entry !== null && typeof entry === "object" && !Array.isArray(entry) && entry.match == null);
704
+ if (missingMatchIndex !== -1) {
705
+ res.writeHead(400, { "Content-Type": "application/json" });
706
+ res.end(JSON.stringify({ error: `Fixture at index ${missingMatchIndex} is missing match` }));
707
+ return true;
708
+ }
709
+ const invalidMatchIndex = entries.findIndex((entry) => entry !== null && typeof entry === "object" && !Array.isArray(entry) && entry.match != null && (typeof entry.match !== "object" || Array.isArray(entry.match)));
710
+ if (invalidMatchIndex !== -1) {
711
+ res.writeHead(400, { "Content-Type": "application/json" });
712
+ res.end(JSON.stringify({ error: `Fixture at index ${invalidMatchIndex}: match must be an object` }));
713
+ return true;
714
+ }
715
+ const extendedResponsesTools = defaults.responsesTools === "extended";
716
+ const markInPlace = extendedResponsesTools && require_helpers.isServerOwnedFixtures(fixtures);
717
+ const addition = controlFixtureAdditions.get(defaults) ?? 0;
718
+ controlFixtureAdditions.set(defaults, addition + 1);
719
+ const converted = [];
720
+ const loadErrors = [];
721
+ for (const [index, entry] of entries.entries()) try {
722
+ const fixture = require_fixture_loader.entryToFixture(entry, void 0, void 0, {
723
+ file: `control-api#${addition}`,
724
+ index
725
+ });
726
+ if (defaults.misbehavior) require_fixture_loader.enableHeldFixtureMisbehavior(fixture);
727
+ if (markInPlace) require_fixture_loader.markFixtureResponsesToolsExtended(fixture);
728
+ converted.push(fixture);
729
+ } catch (error) {
730
+ if (!(error instanceof require_fixture_loader.FixtureLoadError || error instanceof require_fixture_loader.MisbehaviorConfigError)) throw error;
731
+ loadErrors.push(error);
732
+ }
733
+ const errors = (loadErrors.length === 0 ? require_fixture_loader.validateFixtures(extendedResponsesTools ? converted.map(require_fixture_loader.responsesToolsExtendedView) : converted) : []).filter((i) => i.severity === "error");
734
+ const fakes = withFakes ? planControlApiFakes(parsed.mcpFakes, mounts) : null;
735
+ const fakeErrors = fakes?.errors ?? [];
736
+ const validationFailed = (details) => {
506
737
  res.writeHead(400, { "Content-Type": "application/json" });
507
738
  res.end(JSON.stringify({
508
739
  error: "Validation failed",
509
- details: errors
740
+ details
510
741
  }));
511
742
  return true;
743
+ };
744
+ if (loadErrors.length > 0 || errors.length > 0 || fakeErrors.length > 0) return validationFailed([
745
+ ...loadErrors.map((e) => e.toJSON()),
746
+ ...errors,
747
+ ...fakeErrors.map((e) => e.toJSON())
748
+ ]);
749
+ let mcpFakesAdded = 0;
750
+ if (fakes) try {
751
+ mcpFakesAdded = fakes.apply({
752
+ journal,
753
+ defaults
754
+ });
755
+ } catch (err) {
756
+ if (!(err instanceof require_mcp_fakes.McpFakesAddError)) throw err;
757
+ return validationFailed(err.errors.map((e) => e.toJSON()));
512
758
  }
513
759
  fixtures.push(...converted);
514
760
  if (defaults.registry) defaults.registry.setGauge("aimock_fixtures_loaded", {}, fixtures.length);
515
761
  res.writeHead(200, { "Content-Type": "application/json" });
516
- res.end(JSON.stringify({ added: converted.length }));
762
+ res.end(JSON.stringify(withFakes ? {
763
+ added: converted.length,
764
+ mcpFakesAdded
765
+ } : { added: converted.length }));
517
766
  return true;
518
767
  }
519
768
  if (subPath === "/fixtures" && req.method === "DELETE") {
520
769
  require_fixture_loader.clearFixtureQueue(fixtures);
770
+ journal.clearMisbehaviorCounters();
771
+ for (const { handler } of mounts) handler.clearMcpFakes?.();
521
772
  if (defaults.registry) defaults.registry.setGauge("aimock_fixtures_loaded", {}, fixtures.length);
522
773
  res.writeHead(200, { "Content-Type": "application/json" });
523
774
  res.end(JSON.stringify({ cleared: true }));
@@ -530,7 +781,8 @@ async function handleControlAPI(req, res, pathname, searchParams, fixtures, jour
530
781
  veoVideoJobs,
531
782
  grokVideoJobs,
532
783
  bytePlusVideoJobs,
533
- defaults
784
+ defaults,
785
+ mounts
534
786
  });
535
787
  if (subPath === "/reset" && req.method === "POST") {
536
788
  performFullReset(fixtures, resetTargets());
@@ -632,15 +884,16 @@ function clientAbortedMidBody(req, res, err) {
632
884
  if (err instanceof require_helpers.RequestBodyTooLargeError) return false;
633
885
  return res.destroyed && !req.complete;
634
886
  }
635
- async function handleCompletions(req, res, fixtures, journal, defaults, modelFallback, providerKey, openRouter = false) {
887
+ async function handleCompletions(req, res, fixtures, journal, defaults, getRequestEntry, modelFallback, providerKey, openRouter = false, beforeFixtureSelection, bytePlusPath = false) {
636
888
  setCorsHeaders(res);
889
+ const wire = providerKey === "azure" ? "Azure OpenAI Chat Completions" : providerKey === "openrouter" ? "OpenRouter Chat Completions" : providerKey === "byteplus" || bytePlusPath ? "BytePlus ModelArk Chat Completions" : "OpenAI Chat Completions";
637
890
  let raw;
638
891
  try {
639
892
  raw = await require_helpers.readBody(req);
640
893
  } catch (err) {
641
894
  const msg = err instanceof Error ? err.message : "Failed to read request body";
642
895
  const clientFault = err instanceof require_helpers.RequestBodyTooLargeError;
643
- const route = `${req.method ?? "POST"} ${req.url ?? COMPLETIONS_PATH}`;
896
+ const route = `${req.method ?? "POST"} ${req.url ?? require_route_registry.COMPLETIONS_PATH}`;
644
897
  const clientAbort = clientAbortedMidBody(req, res, err);
645
898
  const bodyLimitDisconnect = clientFault && (req.destroyed || res.destroyed);
646
899
  if (clientAbort || bodyLimitDisconnect) {
@@ -648,7 +901,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
648
901
  defaults.logger.warn(bodyLimitDisconnect ? `${route}: ${msg}` : `${route}: client aborted mid-body (${msg})`);
649
902
  journal.add({
650
903
  method: req.method ?? "POST",
651
- path: req.url ?? COMPLETIONS_PATH,
904
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
652
905
  headers: require_helpers.flattenHeaders(req.headers),
653
906
  body: null,
654
907
  response: {
@@ -665,7 +918,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
665
918
  else defaults.logger.error(`${route}: ${msg}`);
666
919
  journal.add({
667
920
  method: req.method ?? "POST",
668
- path: req.url ?? COMPLETIONS_PATH,
921
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
669
922
  headers: require_helpers.flattenHeaders(req.headers),
670
923
  body: null,
671
924
  response: {
@@ -686,7 +939,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
686
939
  const detail = parseErr instanceof Error ? parseErr.message : "unknown parse error";
687
940
  journal.add({
688
941
  method: req.method ?? "POST",
689
- path: req.url ?? COMPLETIONS_PATH,
942
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
690
943
  headers: require_helpers.flattenHeaders(req.headers),
691
944
  body: null,
692
945
  response: {
@@ -705,7 +958,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
705
958
  if (!require_helpers.isJsonObject(body)) {
706
959
  journal.add({
707
960
  method: req.method ?? "POST",
708
- path: req.url ?? COMPLETIONS_PATH,
961
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
709
962
  headers: require_helpers.flattenHeaders(req.headers),
710
963
  body: null,
711
964
  response: {
@@ -723,7 +976,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
723
976
  if (!Array.isArray(body.messages)) {
724
977
  journal.add({
725
978
  method: req.method ?? "POST",
726
- path: req.url ?? COMPLETIONS_PATH,
979
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
727
980
  headers: require_helpers.flattenHeaders(req.headers),
728
981
  body: null,
729
982
  response: {
@@ -739,8 +992,53 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
739
992
  } }));
740
993
  return;
741
994
  }
995
+ const nullMessageIndex = body.messages.findIndex((message) => message === null);
996
+ if (nullMessageIndex !== -1) {
997
+ const message = `Invalid request: messages[${nullMessageIndex}] must be an object`;
998
+ journal.add({
999
+ method: req.method ?? "POST",
1000
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
1001
+ headers: require_helpers.flattenHeaders(req.headers),
1002
+ body: null,
1003
+ response: {
1004
+ status: 400,
1005
+ fixture: null
1006
+ }
1007
+ });
1008
+ require_sse_writer.writeErrorResponse(res, 400, openRouter ? require_openrouter_chat.serializeOpenRouterError(400, message) : JSON.stringify({ error: {
1009
+ message,
1010
+ type: "invalid_request_error",
1011
+ param: null,
1012
+ code: null
1013
+ } }));
1014
+ return;
1015
+ }
1016
+ if (new URL(req.url ?? require_route_registry.COMPLETIONS_PATH, "http://localhost").pathname === require_route_registry.COMPLETIONS_PATH) {
1017
+ let toolsError = require_helpers.validateToolsField(body.tools);
1018
+ if (!toolsError && Array.isArray(body.tools)) {
1019
+ const nullFunctionIndex = body.tools.findIndex((tool) => tool?.function === null);
1020
+ if (nullFunctionIndex !== -1) toolsError = `tools[${nullFunctionIndex}].function must not be null`;
1021
+ }
1022
+ if (toolsError) {
1023
+ journal.add({
1024
+ method: req.method ?? "POST",
1025
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
1026
+ headers: require_helpers.flattenHeaders(req.headers),
1027
+ body: null,
1028
+ response: {
1029
+ status: 400,
1030
+ fixture: null
1031
+ }
1032
+ });
1033
+ require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
1034
+ message: toolsError,
1035
+ type: "invalid_request_error"
1036
+ } }));
1037
+ return;
1038
+ }
1039
+ }
742
1040
  const method = req.method ?? "POST";
743
- const path = req.url ?? COMPLETIONS_PATH;
1041
+ const path = req.url ?? require_route_registry.COMPLETIONS_PATH;
744
1042
  const flatHeaders = require_helpers.flattenHeaders(req.headers);
745
1043
  body._endpointType = "chat";
746
1044
  body._context = require_helpers.getContext(req);
@@ -754,6 +1052,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
754
1052
  const openRouterFallback = openRouter && Array.isArray(body.models) && body.models.length > 0;
755
1053
  const selectFixture = (probe, counts) => {
756
1054
  for (;;) {
1055
+ beforeFixtureSelection?.();
757
1056
  const attempt = require_router.matchFixtureDiagnostic(fixtures, probe, counts, defaults.requestTransform, matchOptions);
758
1057
  if (attempt.fixture && require_fixture_loader.isOneShotError(attempt.fixture) && !require_fixture_loader.claimOneShotError(fixtures, attempt.fixture)) continue;
759
1058
  return attempt;
@@ -837,13 +1136,32 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
837
1136
  const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
838
1137
  const missWouldProxy = require_helpers.wouldProxyMiss(effectiveStrict, defaults.record, providerKey);
839
1138
  const noFixtureSource = missWouldProxy ? "proxy" : "internal";
1139
+ const recordBypass = (reason) => {
1140
+ const entry = getRequestEntry();
1141
+ if (!entry) return;
1142
+ require_misbehavior.recordMisbehaviorOutcome({
1143
+ entry,
1144
+ summary: require_misbehavior.resolveMisbehaviorShortCircuit({
1145
+ wire: "openai-chat",
1146
+ fixture: fixture ?? void 0,
1147
+ defaults,
1148
+ rawHeaders: req.headers,
1149
+ url: req.url,
1150
+ reason
1151
+ }),
1152
+ defaults,
1153
+ testId
1154
+ });
1155
+ };
840
1156
  if (chaosAction === "drop" || chaosAction === "disconnect" || chaosAction === "rateLimit") {
841
1157
  require_chaos.applyChaosAction(chaosAction, res, fixture, journal, chaosContext, fixture ? "fixture" : noFixtureSource, defaults.registry, defaults.logger);
1158
+ recordBypass("chaos-fired");
842
1159
  require_fixture_loader.releaseOneShotError(fixtures, fixture);
843
1160
  return;
844
1161
  }
845
1162
  if (chaosAction === "malformed" && (fixture || !missWouldProxy)) {
846
1163
  require_chaos.applyChaosAction(chaosAction, res, fixture, journal, chaosContext, fixture ? "fixture" : "internal", defaults.registry, defaults.logger);
1164
+ recordBypass("chaos-fired");
847
1165
  require_fixture_loader.releaseOneShotError(fixtures, fixture);
848
1166
  return;
849
1167
  }
@@ -851,10 +1169,10 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
851
1169
  if (effectiveStrict) {
852
1170
  const strictStatus = 503;
853
1171
  const strictMessage = require_helpers.strictNoMatchMessage(skippedBySequenceOrTurn);
854
- defaults.logger.error(require_helpers.strictNoMatchLogLine(req.method ?? "POST", req.url ?? COMPLETIONS_PATH, skippedBySequenceOrTurn));
1172
+ defaults.logger.error(require_helpers.strictNoMatchLogLine(req.method ?? "POST", req.url ?? require_route_registry.COMPLETIONS_PATH, skippedBySequenceOrTurn));
855
1173
  journal.add({
856
1174
  method: req.method ?? "POST",
857
- path: req.url ?? COMPLETIONS_PATH,
1175
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
858
1176
  headers: require_helpers.flattenHeaders(req.headers),
859
1177
  body,
860
1178
  response: {
@@ -875,6 +1193,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
875
1193
  const hookOptions = chaosAction === "malformed" ? {
876
1194
  beforeWriteResponse: () => {
877
1195
  require_chaos.applyChaosAction(chaosAction, res, null, journal, chaosContext, "proxy", defaults.registry, defaults.logger);
1196
+ recordBypass("chaos-fired");
878
1197
  return true;
879
1198
  },
880
1199
  onHookBypassed: (reason) => {
@@ -894,7 +1213,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
894
1213
  req.socket?.on("error", noteClientHangUp);
895
1214
  let outcome;
896
1215
  try {
897
- outcome = await require_recorder.proxyAndRecord(req, res, body, providerKey, req.url ?? COMPLETIONS_PATH, fixtures, defaults, raw, hookOptions);
1216
+ outcome = await require_recorder.proxyAndRecord(req, res, body, providerKey, req.url ?? require_route_registry.COMPLETIONS_PATH, fixtures, defaults, raw, hookOptions);
898
1217
  } finally {
899
1218
  req.socket?.off("end", noteClientHangUp);
900
1219
  req.socket?.off("error", noteClientHangUp);
@@ -904,7 +1223,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
904
1223
  const destroyedMidStream = res.destroyed && !res.writableEnded;
905
1224
  journal.add({
906
1225
  method: req.method ?? "POST",
907
- path: req.url ?? COMPLETIONS_PATH,
1226
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
908
1227
  headers: require_helpers.flattenHeaders(req.headers),
909
1228
  body,
910
1229
  response: {
@@ -917,16 +1236,18 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
917
1236
  } : {}
918
1237
  }
919
1238
  });
1239
+ recordBypass("proxied");
920
1240
  return;
921
1241
  }
922
1242
  if (chaosAction === "malformed") {
923
1243
  require_chaos.applyChaosAction(chaosAction, res, null, journal, chaosContext, "internal", defaults.registry, defaults.logger);
1244
+ recordBypass("chaos-fired");
924
1245
  return;
925
1246
  }
926
1247
  }
927
1248
  journal.add({
928
1249
  method: req.method ?? "POST",
929
- path: req.url ?? COMPLETIONS_PATH,
1250
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
930
1251
  headers: require_helpers.flattenHeaders(req.headers),
931
1252
  body,
932
1253
  response: {
@@ -943,13 +1264,71 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
943
1264
  } }));
944
1265
  return;
945
1266
  }
946
- const response = preResolvedResponse ?? await require_helpers.resolveResponse(fixture, body);
1267
+ const resolvedResponse = preResolvedResponse ?? await require_helpers.resolveResponse(fixture, body);
1268
+ const evaluation = require_misbehavior.planMisbehavior({
1269
+ wire: "openai-chat",
1270
+ fixture,
1271
+ response: resolvedResponse,
1272
+ request: body,
1273
+ stream: body.stream === true,
1274
+ defaults,
1275
+ rawHeaders: req.headers,
1276
+ url: req.url
1277
+ });
1278
+ if (evaluation.kind === "error") {
1279
+ require_misbehavior.recordMisbehaviorOutcome({
1280
+ entry: journal.add({
1281
+ method,
1282
+ path,
1283
+ headers: flatHeaders,
1284
+ body,
1285
+ response: {
1286
+ status: evaluation.status,
1287
+ fixture
1288
+ }
1289
+ }),
1290
+ summary: evaluation.summary,
1291
+ defaults,
1292
+ testId
1293
+ });
1294
+ if (!evaluation.summary?.evaluations.some((row) => row.outcome === "error")) defaults.logger.error(`${evaluation.code}: ${evaluation.message}`);
1295
+ require_sse_writer.writeErrorResponse(res, evaluation.status, openRouter ? require_openrouter_chat.serializeOpenRouterError(evaluation.status, `${evaluation.code}: ${evaluation.message}`) : JSON.stringify({ error: {
1296
+ message: evaluation.message,
1297
+ type: "invalid_request_error",
1298
+ param: null,
1299
+ code: evaluation.code
1300
+ } }));
1301
+ return;
1302
+ }
1303
+ const appliedPlan = evaluation.kind === "applied" ? require_helpers.prepareOpenAIChatMisbehavior(evaluation) : void 0;
1304
+ const response = appliedPlan?.response ?? resolvedResponse;
1305
+ const summary = appliedPlan?.summary ?? evaluation.summary;
1306
+ const recordOutcome = (entry) => {
1307
+ require_misbehavior.recordMisbehaviorOutcome({
1308
+ entry,
1309
+ summary,
1310
+ defaults,
1311
+ testId
1312
+ });
1313
+ };
1314
+ const appliedReasoning = appliedPlan && appliedPlan.reasoning === void 0 && (require_helpers.isTextResponse(response) || require_helpers.isToolCallResponse(response) || require_helpers.isCombinedFixtureResponse(response)) ? require_helpers.resolveReasoningForModel(response.reasoning, responseModel, require_helpers.resolveStrictMode(defaults.strict, req.headers), defaults.logger) : void 0;
1315
+ const appliedUsage = appliedPlan ? require_helpers.resolveOpenAIChatMisbehaviorUsage(appliedPlan, body, appliedPlan.reasoning === void 0 ? appliedReasoning !== void 0 : openRouter) : void 0;
947
1316
  const latency = fixture.latency ?? defaults.latency;
948
1317
  const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
949
1318
  const emitStreamingUsage = body.stream === true && body.stream_options?.include_usage === true || openRouter;
950
1319
  const streamingPromptText = body.messages.map((m) => typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.map((p) => p.text ?? "").join("") : "").join("");
951
- const resolveStreamingUsageTokens = (overrides, completionText) => require_helpers.resolveUsage(overrides, streamingPromptText, completionText);
1320
+ const resolveStreamingUsageTokens = (overrides, completionText) => appliedUsage ?? require_helpers.resolveUsage(overrides, streamingPromptText, completionText);
1321
+ const resolveRecordedTimings = (chunks) => {
1322
+ const timings = fixture.recordedTimings;
1323
+ if (!appliedPlan?.duplicateId || !timings) return timings;
1324
+ const gaps = timings.interChunkDelaysMs;
1325
+ return {
1326
+ ...timings,
1327
+ interChunkDelaysMs: Array.from({ length: Math.max(gaps.length, chunks.length - 1) }, (_, index) => gaps[index] ?? gaps.at(-1) ?? 0)
1328
+ };
1329
+ };
952
1330
  const shapeORCompletion = (completion, overrides) => {
1331
+ if (appliedUsage) completion.usage = appliedUsage;
953
1332
  if (!openRouter) return completion;
954
1333
  return require_openrouter_chat.shapeOpenRouterCompletion(completion, require_openrouter_chat.resolveOpenRouterShaping(overrides, overrides?.model ?? responseModel), overrides?.id !== void 0);
955
1334
  };
@@ -962,46 +1341,86 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
962
1341
  const openRouterProcessing = !!(openRouter && fixture.openRouterProcessing);
963
1342
  if (require_helpers.isErrorResponse(response)) {
964
1343
  const status = response.status ?? 500;
965
- journal.add({
1344
+ recordOutcome(journal.add({
966
1345
  method: req.method ?? "POST",
967
- path: req.url ?? COMPLETIONS_PATH,
1346
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
968
1347
  headers: require_helpers.flattenHeaders(req.headers),
969
1348
  body,
970
1349
  response: {
971
1350
  status,
972
1351
  fixture
973
1352
  }
974
- });
1353
+ }));
975
1354
  require_sse_writer.writeErrorResponse(res, status, openRouter ? require_openrouter_chat.serializeOpenRouterError(status, response.error.message, response.error.metadata) : require_helpers.serializeErrorResponse(response), { retryAfter: response.retryAfter });
976
1355
  return;
977
1356
  }
978
1357
  if (require_helpers.isAudioResponse(response)) {
979
- journal.add({
1358
+ recordOutcome(journal.add({
980
1359
  method: req.method ?? "POST",
981
- path: req.url ?? COMPLETIONS_PATH,
1360
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
982
1361
  headers: require_helpers.flattenHeaders(req.headers),
983
1362
  body,
984
1363
  response: {
985
1364
  status: 422,
986
1365
  fixture
987
1366
  }
988
- });
1367
+ }));
989
1368
  require_sse_writer.writeErrorResponse(res, 422, openRouter ? require_openrouter_chat.serializeOpenRouterError(422, "Audio responses are not supported on the chat completions endpoint. Use Gemini generateContent or a dedicated audio endpoint.") : JSON.stringify({ error: {
990
1369
  message: "Audio responses are not supported on the chat completions endpoint. Use Gemini generateContent or a dedicated audio endpoint.",
991
1370
  type: "invalid_request_error"
992
1371
  } }));
993
1372
  return;
994
1373
  }
995
- if (require_helpers.isContentWithToolCallsResponse(response)) {
1374
+ if (appliedPlan && require_helpers.isTextResponse(response) && (appliedPlan.stop === "refusal" || appliedPlan.stop === "content_filter" || appliedPlan.reasoning !== void 0)) {
1375
+ const overrides = require_helpers.extractOverrides(response);
1376
+ const entry = journal.add({
1377
+ method,
1378
+ path,
1379
+ headers: flatHeaders,
1380
+ body,
1381
+ response: {
1382
+ status: 200,
1383
+ fixture
1384
+ }
1385
+ });
1386
+ recordOutcome(entry);
1387
+ if (body.stream !== true) {
1388
+ const completion = appliedPlan.stop === "refusal" ? require_helpers.buildOpenAIRefusalCompletion(appliedPlan.refusal ?? "", responseModel, overrides, body.messages) : appliedPlan.stop === "content_filter" ? require_helpers.buildOpenAIContentFilterCompletion(responseModel, overrides, body.messages) : require_helpers.buildOpenAIReasoningCompletion(appliedPlan.reasoning ?? "", responseModel, openRouter, overrides, body.messages);
1389
+ res.writeHead(200, { "Content-Type": "application/json" });
1390
+ res.end(JSON.stringify(shapeORCompletion(completion, overrides)));
1391
+ } else {
1392
+ const chunks = appliedPlan.stop === "refusal" ? require_helpers.buildOpenAIRefusalChunks(appliedPlan.refusal ?? "", responseModel, chunkSize, overrides) : appliedPlan.stop === "content_filter" ? require_helpers.buildOpenAIContentFilterChunks(responseModel, overrides) : require_helpers.buildOpenAIReasoningChunks(appliedPlan.reasoning ?? "", responseModel, chunkSize, openRouter, overrides);
1393
+ const usageChunk = emitStreamingUsage ? require_helpers.buildUsageChunk(chunks[0].id, overrides?.model ?? responseModel, chunks[0].created, resolveStreamingUsageTokens(overrides, ""), overrides?.systemFingerprint) : void 0;
1394
+ shapeORChunks(chunks, usageChunk, overrides);
1395
+ const interruption = require_interruption.createInterruptionSignal(fixture);
1396
+ if (!await require_sse_writer.writeSSEStream(res, chunks, {
1397
+ latency,
1398
+ streamingProfile: fixture.streamingProfile,
1399
+ signal: interruption?.signal,
1400
+ onChunkSent: interruption?.tick,
1401
+ usageChunk,
1402
+ recordedTimings: resolveRecordedTimings(chunks),
1403
+ replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
1404
+ openRouterProcessing
1405
+ })) {
1406
+ if (!res.writableEnded) res.destroy();
1407
+ entry.response.interrupted = true;
1408
+ entry.response.interruptReason = interruption?.reason();
1409
+ }
1410
+ interruption?.cleanup();
1411
+ }
1412
+ return;
1413
+ }
1414
+ if (require_helpers.isCombinedFixtureResponse(response)) {
996
1415
  if (response.webSearches?.length) defaults.logger.warn("webSearches in fixture response are not supported for Chat Completions API — ignoring");
997
1416
  const overrides = require_helpers.extractOverrides(response);
998
1417
  const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
999
- const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, responseModel, effectiveStrict, defaults.logger);
1418
+ const effReasoning = appliedPlan ? appliedReasoning : require_helpers.resolveReasoningForModel(response.reasoning, responseModel, effectiveStrict, defaults.logger);
1000
1419
  const streaming = body.stream === true;
1001
1420
  const blockOutcome = response.blocks && response.blocks.length > 0 ? require_helpers.resolveFixtureBlockOutcome(response.blocks) : void 0;
1002
1421
  const journalEntry = journal.add({
1003
1422
  method: req.method ?? "POST",
1004
- path: req.url ?? COMPLETIONS_PATH,
1423
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
1005
1424
  headers: require_helpers.flattenHeaders(req.headers),
1006
1425
  body,
1007
1426
  response: {
@@ -1009,16 +1428,18 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
1009
1428
  fixture
1010
1429
  }
1011
1430
  });
1431
+ recordOutcome(journalEntry);
1432
+ const toolCalls = require_helpers.requireEmittedFunctionToolCalls(response, wire);
1012
1433
  if (!streaming) {
1013
- const completion = require_helpers.buildContentWithToolCallsCompletion(blockOutcome?.content ?? response.content ?? "", blockOutcome?.toolCalls ?? response.toolCalls ?? [], responseModel, effReasoning, blockOutcome ? {
1434
+ const completion = require_helpers.buildContentWithToolCallsCompletion(blockOutcome?.content ?? response.content ?? "", blockOutcome?.toolCalls ?? toolCalls, responseModel, effReasoning, blockOutcome ? {
1014
1435
  ...overrides,
1015
1436
  finishReason: overrides?.finishReason ?? (blockOutcome.hasToolCalls ? "tool_calls" : "stop")
1016
1437
  } : overrides, body.messages);
1017
1438
  res.writeHead(200, { "Content-Type": "application/json" });
1018
1439
  res.end(JSON.stringify(shapeORCompletion(completion, overrides)));
1019
1440
  } else {
1020
- const chunks = require_helpers.buildContentWithToolCallsChunks(blockOutcome?.content ?? response.content ?? "", blockOutcome?.toolCalls ?? response.toolCalls ?? [], responseModel, chunkSize, effReasoning, overrides, blockOutcome?.ordered);
1021
- const completionText = blockOutcome ? blockOutcome.content + blockOutcome.toolCalls.map((tc) => tc.name + tc.arguments).join("") : (response.content ?? "") + (response.toolCalls ?? []).map((tc) => tc.name + tc.arguments).join("");
1441
+ const chunks = require_helpers.buildContentWithToolCallsChunks(blockOutcome?.content ?? response.content ?? "", blockOutcome?.toolCalls ?? toolCalls, responseModel, chunkSize, effReasoning, overrides, blockOutcome?.ordered);
1442
+ const completionText = blockOutcome ? blockOutcome.content + blockOutcome.toolCalls.map((tc) => tc.name + tc.arguments).join("") : (response.content ?? "") + toolCalls.map((tc) => tc.name + tc.arguments).join("");
1022
1443
  const usageChunk = emitStreamingUsage ? require_helpers.buildUsageChunk(chunks[0]?.id ?? "chatcmpl-unknown", overrides?.model ?? responseModel, chunks[0]?.created ?? Math.floor(Date.now() / 1e3), resolveStreamingUsageTokens(overrides, completionText), overrides?.systemFingerprint) : void 0;
1023
1444
  shapeORChunks(chunks, usageChunk, overrides);
1024
1445
  const interruption = require_interruption.createInterruptionSignal(fixture);
@@ -1028,7 +1449,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
1028
1449
  signal: interruption?.signal,
1029
1450
  onChunkSent: interruption?.tick,
1030
1451
  usageChunk,
1031
- recordedTimings: fixture.recordedTimings,
1452
+ recordedTimings: resolveRecordedTimings(chunks),
1032
1453
  replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
1033
1454
  openRouterProcessing
1034
1455
  })) {
@@ -1044,10 +1465,10 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
1044
1465
  if (response.webSearches?.length) defaults.logger.warn("webSearches in fixture response are not supported for Chat Completions API — ignoring");
1045
1466
  const overrides = require_helpers.extractOverrides(response);
1046
1467
  const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
1047
- const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, responseModel, effectiveStrict, defaults.logger);
1468
+ const effReasoning = appliedPlan ? appliedReasoning : require_helpers.resolveReasoningForModel(response.reasoning, responseModel, effectiveStrict, defaults.logger);
1048
1469
  const journalEntry = journal.add({
1049
1470
  method: req.method ?? "POST",
1050
- path: req.url ?? COMPLETIONS_PATH,
1471
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
1051
1472
  headers: require_helpers.flattenHeaders(req.headers),
1052
1473
  body,
1053
1474
  response: {
@@ -1055,6 +1476,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
1055
1476
  fixture
1056
1477
  }
1057
1478
  });
1479
+ recordOutcome(journalEntry);
1058
1480
  if (body.stream !== true) {
1059
1481
  const completion = require_helpers.buildTextCompletion(response.content, responseModel, effReasoning, overrides, body.messages);
1060
1482
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -1070,7 +1492,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
1070
1492
  signal: interruption?.signal,
1071
1493
  onChunkSent: interruption?.tick,
1072
1494
  usageChunk,
1073
- recordedTimings: fixture.recordedTimings,
1495
+ recordedTimings: resolveRecordedTimings(chunks),
1074
1496
  replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
1075
1497
  openRouterProcessing
1076
1498
  })) {
@@ -1086,10 +1508,10 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
1086
1508
  if (response.webSearches?.length) defaults.logger.warn("webSearches in fixture response are not supported for Chat Completions API — ignoring");
1087
1509
  const overrides = require_helpers.extractOverrides(response);
1088
1510
  const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
1089
- const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, responseModel, effectiveStrict, defaults.logger);
1511
+ const effReasoning = appliedPlan ? appliedReasoning : require_helpers.resolveReasoningForModel(response.reasoning, responseModel, effectiveStrict, defaults.logger);
1090
1512
  const journalEntry = journal.add({
1091
1513
  method: req.method ?? "POST",
1092
- path: req.url ?? COMPLETIONS_PATH,
1514
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
1093
1515
  headers: require_helpers.flattenHeaders(req.headers),
1094
1516
  body,
1095
1517
  response: {
@@ -1097,13 +1519,15 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
1097
1519
  fixture
1098
1520
  }
1099
1521
  });
1522
+ recordOutcome(journalEntry);
1523
+ const toolCalls = require_helpers.requireServedFunctionToolCalls(response, wire);
1100
1524
  if (body.stream !== true) {
1101
- const completion = require_helpers.buildToolCallCompletion(response.toolCalls, responseModel, effReasoning, overrides, body.messages);
1525
+ const completion = require_helpers.buildToolCallCompletion(toolCalls, responseModel, effReasoning, overrides, body.messages);
1102
1526
  res.writeHead(200, { "Content-Type": "application/json" });
1103
1527
  res.end(JSON.stringify(shapeORCompletion(completion, overrides)));
1104
1528
  } else {
1105
- const chunks = require_helpers.buildToolCallChunks(response.toolCalls, responseModel, chunkSize, effReasoning, overrides);
1106
- const completionText = response.toolCalls.map((tc) => tc.name + tc.arguments).join("");
1529
+ const chunks = require_helpers.buildToolCallChunks(toolCalls, responseModel, chunkSize, effReasoning, overrides);
1530
+ const completionText = toolCalls.map((tc) => tc.name + tc.arguments).join("");
1107
1531
  const usageChunk = emitStreamingUsage ? require_helpers.buildUsageChunk(chunks[0]?.id ?? "chatcmpl-unknown", overrides?.model ?? responseModel, chunks[0]?.created ?? Math.floor(Date.now() / 1e3), resolveStreamingUsageTokens(overrides, completionText), overrides?.systemFingerprint) : void 0;
1108
1532
  shapeORChunks(chunks, usageChunk, overrides);
1109
1533
  const interruption = require_interruption.createInterruptionSignal(fixture);
@@ -1113,7 +1537,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
1113
1537
  signal: interruption?.signal,
1114
1538
  onChunkSent: interruption?.tick,
1115
1539
  usageChunk,
1116
- recordedTimings: fixture.recordedTimings,
1540
+ recordedTimings: resolveRecordedTimings(chunks),
1117
1541
  replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
1118
1542
  openRouterProcessing
1119
1543
  })) {
@@ -1125,16 +1549,16 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
1125
1549
  }
1126
1550
  return;
1127
1551
  }
1128
- journal.add({
1552
+ recordOutcome(journal.add({
1129
1553
  method: req.method ?? "POST",
1130
- path: req.url ?? COMPLETIONS_PATH,
1554
+ path: req.url ?? require_route_registry.COMPLETIONS_PATH,
1131
1555
  headers: require_helpers.flattenHeaders(req.headers),
1132
1556
  body,
1133
1557
  response: {
1134
1558
  status: 500,
1135
1559
  fixture
1136
1560
  }
1137
- });
1561
+ }));
1138
1562
  require_sse_writer.writeErrorResponse(res, 500, openRouter ? require_openrouter_chat.serializeOpenRouterError(500, "Fixture response did not match any known type") : JSON.stringify({ error: {
1139
1563
  message: "Fixture response did not match any known type",
1140
1564
  type: "server_error"
@@ -1148,18 +1572,101 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
1148
1572
  }
1149
1573
  /** @internal Config startup uses this to avoid parsing a selected auth source twice. */
1150
1574
  async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mounts, serviceFixtures) {
1575
+ const logger = new require_logger.Logger(options?.logLevel ?? "silent");
1576
+ const mountList = mounts ?? [];
1577
+ const handOff = serviceFixtures?.mcpFakes && serviceFixtures.mcpFakes.length > 0 ? require_mcp_fakes_mount.handOffMcpFakes(mountList, serviceFixtures.mcpFakes, logger) : null;
1578
+ try {
1579
+ return await startServer(fixtures, options, resolvedAuth, mountList, logger, serviceFixtures, () => handOff?.commit());
1580
+ } catch (err) {
1581
+ handOff?.undo();
1582
+ throw err;
1583
+ }
1584
+ }
1585
+ /**
1586
+ * The journal as JSON. An entry names the caller's fixture; the JSON shows
1587
+ * the fixture the request was served from (`Journal.servedFixture`): an
1588
+ * extended server's view, with the held keys applied, or LLMock's
1589
+ * per-addition copy with misbehavior enabled. The journal therefore reads as
1590
+ * it did when the entries held those objects.
1591
+ */
1592
+ function journalJson(entries, journal) {
1593
+ if (!entries.some((entry) => journal.servedFixture(entry) !== entry.response.fixture)) return JSON.stringify(entries);
1594
+ return JSON.stringify(entries.map((entry) => {
1595
+ const fixture = entry.response.fixture;
1596
+ let served = journal.servedFixture(entry);
1597
+ if (served === fixture || !served) return entry;
1598
+ const viewSource = require_fixture_loader.responsesToolsViewSource(served);
1599
+ if (viewSource !== served) served = require_fixture_loader.responsesToolsExtendedView(viewSource);
1600
+ return {
1601
+ ...entry,
1602
+ response: {
1603
+ ...entry.response,
1604
+ fixture: served
1605
+ }
1606
+ };
1607
+ }));
1608
+ }
1609
+ /**
1610
+ * The server of `createServerWithResolvedAuth`, after the MCP fakes hand-off.
1611
+ * `commitHandOff` runs once the server listens; if it throws, the server is
1612
+ * closed and start rejects.
1613
+ */
1614
+ async function startServer(fixtures, options, resolvedAuth, mountList, logger, serviceFixtures, commitHandOff) {
1615
+ const callerFixtures = fixtures;
1616
+ let rawFixtureAddition = 0;
1617
+ function ensureRawFixturePositions() {
1618
+ const existingPositions = new Set(callerFixtures.map(require_misbehavior.getFixtureMisbehaviorPosition).filter((position) => position !== void 0));
1619
+ for (const fixture of callerFixtures) {
1620
+ if (require_misbehavior.getFixtureMisbehaviorPosition(fixture) !== void 0) continue;
1621
+ let position;
1622
+ do
1623
+ position = `createServer#${rawFixtureAddition++}`;
1624
+ while (existingPositions.has(position));
1625
+ require_misbehavior.setFixtureMisbehaviorPosition(fixture, position);
1626
+ existingPositions.add(position);
1627
+ }
1628
+ }
1629
+ ensureRawFixturePositions();
1151
1630
  const host = options?.host ?? "127.0.0.1";
1152
1631
  const port = options?.port ?? 0;
1153
- const logger = new require_logger.Logger(options?.logLevel ?? "silent");
1154
1632
  const registry = options?.metrics ? require_metrics.createMetricsRegistry() : void 0;
1155
1633
  const serverOptions = options ?? {};
1634
+ const validResponsesTools = (mode) => mode === "legacy" || mode === "extended";
1635
+ if (serverOptions.responsesTools !== void 0 && !validResponsesTools(serverOptions.responsesTools)) new require_logger.Logger("warn").warn(`Ignoring responsesTools because it must be "legacy" or "extended", got ${JSON.stringify(serverOptions.responsesTools)}. Using "legacy".`);
1636
+ fixtures = require_helpers.createServerFixtureList(callerFixtures, () => serverOptions.responsesTools, require_fixture_loader.responsesToolsExtendedView);
1156
1637
  const chaosByTestId = /* @__PURE__ */ new Map();
1638
+ let misbehaviorBaseline;
1639
+ const misbehavior = {
1640
+ byTestId: /* @__PURE__ */ new Map(),
1641
+ get baseline() {
1642
+ return this.byTestId.get(require_constants.DEFAULT_TEST_ID) ?? misbehaviorBaseline;
1643
+ },
1644
+ set baseline(config) {
1645
+ misbehaviorBaseline = config;
1646
+ if (config === void 0) this.byTestId.delete(require_constants.DEFAULT_TEST_ID);
1647
+ else if (this.byTestId.has(require_constants.DEFAULT_TEST_ID)) this.byTestId.set(require_constants.DEFAULT_TEST_ID, config);
1648
+ }
1649
+ };
1650
+ const misbehaviorEnabled = serverOptions.enableMisbehavior === true;
1651
+ if (misbehaviorEnabled) callerFixtures.forEach(require_fixture_loader.enableHeldFixtureMisbehavior);
1652
+ if (misbehaviorEnabled && serverOptions.misbehavior !== void 0) {
1653
+ const parsed = require_misbehavior.parseMisbehavior(serverOptions.misbehavior);
1654
+ if (!parsed.ok) throw new TypeError(`${parsed.issue.rule}: ${parsed.issue.message}`);
1655
+ misbehavior.baseline = parsed.config.seed === "random" ? {
1656
+ ...parsed.config,
1657
+ seed: require_misbehavior.resolveMisbehaviorSeed(parsed.config.seed, logger)
1658
+ } : parsed.config;
1659
+ }
1157
1660
  const defaults = {
1158
1661
  latency: serverOptions.latency ?? 0,
1159
1662
  chunkSize: Math.max(1, serverOptions.chunkSize ?? DEFAULT_CHUNK_SIZE),
1160
1663
  replaySpeed: serverOptions.replaySpeed ?? 1,
1161
1664
  logger,
1162
1665
  chaosByTestId,
1666
+ misbehavior: misbehaviorEnabled ? misbehavior : void 0,
1667
+ get misbehaviorCounters() {
1668
+ return journal;
1669
+ },
1163
1670
  get chaos() {
1164
1671
  return {
1165
1672
  base: chaosByTestId.get(require_constants.DEFAULT_TEST_ID) ?? serverOptions.chaos,
@@ -1182,6 +1689,13 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1182
1689
  get strict() {
1183
1690
  return serverOptions.strict;
1184
1691
  },
1692
+ get strictToolArguments() {
1693
+ return serverOptions.strictToolArguments;
1694
+ },
1695
+ get responsesTools() {
1696
+ const mode = serverOptions.responsesTools;
1697
+ return validResponsesTools(mode) ? mode : void 0;
1698
+ },
1185
1699
  get requestTransform() {
1186
1700
  return serverOptions.requestTransform;
1187
1701
  },
@@ -1272,6 +1786,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1272
1786
  if (req) ownJournalEntry.set(req, entry);
1273
1787
  }
1274
1788
  });
1789
+ if (serverOptions.responsesTools === "extended") journal.configureFixtureViewSource(require_fixture_loader.responsesToolsViewSource);
1275
1790
  const videoStates = new require_video.VideoStateMap();
1276
1791
  const openRouterVideoJobs = new require_openrouter_video.OpenRouterVideoJobMap();
1277
1792
  const veoVideoJobs = new require_veo_video.VeoVideoJobMap();
@@ -1286,6 +1801,85 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1286
1801
  return status >= 400 && status < 500 ? "invalid_request_error" : "server_error";
1287
1802
  }
1288
1803
  /**
1804
+ * Envelope for a fixture tool-call error (see isFixtureToolCallError: invalid
1805
+ * JSON arguments on an object wire, a custom tool call on a non-Responses
1806
+ * wire, or a malformed fixture tool call). It is the provider envelope aimock
1807
+ * emits for that route, with the aimock `code` in it: Google's
1808
+ * `google.rpc.ErrorInfo` detail on Gemini and Vertex AI, a string
1809
+ * `error.code` on Gemini Interactions and Anthropic Messages, a `reason`
1810
+ * member on Bedrock (a `code` member would replace `__type` as the AWS SDK's
1811
+ * error name), and a sibling `code` on Ollama's bare string error. Every
1812
+ * other route, Cohere included, gets the OpenAI-style
1813
+ * `{error: {message, type, code}}`. OpenRouter routes pass their own
1814
+ * `toolCallEnvelope` instead of using this one.
1815
+ */
1816
+ function invalidToolArgumentsEnvelope(pathname, message, code) {
1817
+ if (pathname === require_route_registry.OLLAMA_CHAT_PATH) return JSON.stringify({
1818
+ error: message,
1819
+ code
1820
+ });
1821
+ if (pathname === require_route_registry.GEMINI_INTERACTIONS_PATH) return JSON.stringify({ error: {
1822
+ code,
1823
+ message
1824
+ } });
1825
+ if (require_route_registry.GEMINI_PATH_RE.test(pathname) || require_route_registry.VERTEX_AI_RE.test(pathname)) return JSON.stringify({ error: {
1826
+ code: 500,
1827
+ message,
1828
+ status: "INTERNAL",
1829
+ details: require_helpers.googleFixtureToolCallErrorDetails(code)
1830
+ } });
1831
+ if (pathname === require_route_registry.MESSAGES_PATH) return JSON.stringify({
1832
+ type: "error",
1833
+ error: {
1834
+ type: "api_error",
1835
+ code,
1836
+ message
1837
+ }
1838
+ });
1839
+ if (require_route_registry.BEDROCK_INVOKE_RE.test(pathname) || require_route_registry.BEDROCK_STREAM_RE.test(pathname) || require_route_registry.BEDROCK_CONVERSE_RE.test(pathname) || require_route_registry.BEDROCK_CONVERSE_STREAM_RE.test(pathname)) return JSON.stringify({
1840
+ __type: "InternalServerException",
1841
+ message,
1842
+ reason: code
1843
+ });
1844
+ return JSON.stringify({ error: {
1845
+ message,
1846
+ type: "server_error",
1847
+ code
1848
+ } });
1849
+ }
1850
+ function invalidMisbehaviorHeaderEnvelope(pathname, detail) {
1851
+ const code = "aimock_misbehavior_invalid";
1852
+ const message = `${code}: ${detail}`;
1853
+ if (pathname === require_route_registry.OLLAMA_CHAT_PATH || pathname === require_route_registry.OLLAMA_GENERATE_PATH) return JSON.stringify({ error: message });
1854
+ if (pathname === require_route_registry.COHERE_CHAT_PATH) return JSON.stringify({ message });
1855
+ if (pathname === require_route_registry.GEMINI_INTERACTIONS_PATH) return JSON.stringify({ error: {
1856
+ code,
1857
+ message
1858
+ } });
1859
+ if (require_route_registry.GEMINI_PATH_RE.test(pathname) || require_route_registry.VERTEX_AI_RE.test(pathname)) return JSON.stringify({ error: {
1860
+ code: 400,
1861
+ message,
1862
+ status: "INVALID_ARGUMENT"
1863
+ } });
1864
+ if (pathname === require_route_registry.MESSAGES_PATH) return JSON.stringify({
1865
+ type: "error",
1866
+ error: {
1867
+ type: "invalid_request_error",
1868
+ code,
1869
+ message
1870
+ }
1871
+ });
1872
+ if (require_route_registry.BEDROCK_INVOKE_RE.test(pathname) || require_route_registry.BEDROCK_STREAM_RE.test(pathname) || require_route_registry.BEDROCK_CONVERSE_RE.test(pathname) || require_route_registry.BEDROCK_CONVERSE_STREAM_RE.test(pathname)) return JSON.stringify({
1873
+ __type: "ValidationException",
1874
+ message
1875
+ });
1876
+ return JSON.stringify({ error: {
1877
+ message,
1878
+ type: "invalid_request_error",
1879
+ code
1880
+ } });
1881
+ }
1882
+ /**
1289
1883
  * The newest journal entry this request already produced, or null.
1290
1884
  *
1291
1885
  * Attribution is by the identity of the `IncomingMessage` the entry was
@@ -1336,6 +1930,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1336
1930
  function routeError(req, res, err, pathname, opts) {
1337
1931
  const route = `${req.method ?? "?"} ${pathname}`;
1338
1932
  const msg = err instanceof Error ? err.message : "Internal error";
1933
+ const invalidToolArguments = require_helpers.isFixtureToolCallError(err);
1339
1934
  const clientFault = err instanceof require_helpers.RequestBodyTooLargeError;
1340
1935
  const clientAbort = clientAbortedMidBody(req, res, err);
1341
1936
  const status = clientFault ? 400 : 500;
@@ -1376,8 +1971,10 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1376
1971
  return;
1377
1972
  }
1378
1973
  if (!res.headersSent) {
1379
- if (existing) existing.response.status = status;
1380
- else try {
1974
+ if (existing) {
1975
+ existing.response.status = status;
1976
+ if (invalidToolArguments) existing.response.error = msg;
1977
+ } else try {
1381
1978
  journal.add({
1382
1979
  method: req.method ?? "?",
1383
1980
  path: req.url ?? "?",
@@ -1387,14 +1984,15 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1387
1984
  response: {
1388
1985
  status,
1389
1986
  fixture: null,
1390
- source: "internal"
1987
+ source: "internal",
1988
+ ...invalidToolArguments ? { error: msg } : {}
1391
1989
  }
1392
1990
  });
1393
1991
  } catch (jErr) {
1394
1992
  logger.warn(`${route}: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
1395
1993
  }
1396
1994
  setCorsHeaders(res);
1397
- require_sse_writer.writeErrorResponse(res, status, opts?.envelope ? opts.envelope(msg, status) : JSON.stringify({ error: {
1995
+ require_sse_writer.writeErrorResponse(res, status, invalidToolArguments ? (opts?.toolCallEnvelope ?? ((m, c) => invalidToolArgumentsEnvelope(pathname, m, c)))(msg, require_helpers.fixtureToolCallErrorCode(err)) : opts?.envelope ? opts.envelope(msg, status) : JSON.stringify({ error: {
1398
1996
  message: msg,
1399
1997
  type: errorTypeForStatus(status)
1400
1998
  } }));
@@ -1439,16 +2037,21 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1439
2037
  else res.destroy();
1440
2038
  }
1441
2039
  }
1442
- if (mounts) for (const { handler } of mounts) {
2040
+ for (const { handler } of mountList) {
1443
2041
  if (handler.setJournal) handler.setJournal(journal);
1444
2042
  if (registry && handler.setRegistry) handler.setRegistry(registry);
2043
+ if (handler.setLogger) handler.setLogger(logger);
2044
+ if (handler instanceof require_mcp_mock.MCPMock) handler.setReplaySpeed(defaults.replaySpeed);
1445
2045
  }
1446
2046
  if (registry) registry.setGauge("aimock_fixtures_loaded", {}, fixtures.length);
1447
2047
  const server = node_http.createServer((req, res) => {
1448
2048
  requestScope.run(req, () => {
1449
- handleHttpRequest(req, res).catch((err) => {
2049
+ require_helpers.runWithToolArgumentsScope({
2050
+ strict: defaults.strictToolArguments === true,
2051
+ logger
2052
+ }, () => handleHttpRequest(req, res).catch((err) => {
1450
2053
  routeError(req, res, err, req.url ?? "?");
1451
- });
2054
+ }));
1452
2055
  });
1453
2056
  });
1454
2057
  async function handleHttpRequest(req, res) {
@@ -1464,7 +2067,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1464
2067
  if (recorded) return;
1465
2068
  recorded = true;
1466
2069
  try {
1467
- const normalizedPath = require_metrics.normalizePathLabel(pathname, mounts ? mounts.map((m) => m.path) : []);
2070
+ const normalizedPath = require_metrics.normalizePathLabel(pathname, mountList.map((m) => m.path));
1468
2071
  const method = req.method ?? "UNKNOWN";
1469
2072
  registry.incrementCounter("aimock_requests_total", {
1470
2073
  method,
@@ -1485,7 +2088,36 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1485
2088
  if (!res.writableFinished) recordOutcome(require_metrics.DESTROYED_STATUS_LABEL);
1486
2089
  });
1487
2090
  }
1488
- const parsedUrl = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
2091
+ let parsedUrl;
2092
+ try {
2093
+ parsedUrl = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
2094
+ } catch (err) {
2095
+ const route = `${req.method ?? "?"} ${req.url ?? "?"}`;
2096
+ const msg = err instanceof Error ? err.message : "Internal error";
2097
+ logger.error(`${route}: ${msg}`);
2098
+ if (err instanceof Error && err.stack) logger.debug(err.stack);
2099
+ try {
2100
+ journal.add({
2101
+ method: req.method ?? "?",
2102
+ path: req.url ?? "?",
2103
+ headers: require_helpers.flattenHeaders(req.headers),
2104
+ body: null,
2105
+ response: {
2106
+ status: 400,
2107
+ fixture: null,
2108
+ source: "internal"
2109
+ }
2110
+ });
2111
+ } catch (jErr) {
2112
+ logger.warn(`${route}: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
2113
+ }
2114
+ setCorsHeaders(res);
2115
+ require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
2116
+ message: "Invalid request target",
2117
+ type: "invalid_request_error"
2118
+ } }));
2119
+ return;
2120
+ }
1489
2121
  pathname = parsedUrl.pathname;
1490
2122
  const originalPathname = pathname;
1491
2123
  const isOpenRouter = require_openrouter_chat.isOpenRouterPath(originalPathname);
@@ -1494,48 +2126,74 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1494
2126
  handleOptions(res);
1495
2127
  return;
1496
2128
  }
1497
- if (!(req.method === "GET" && (pathname === HEALTH_PATH || pathname === READY_PATH || pathname === "/metrics"))) {
2129
+ if (!(req.method === "GET" && (pathname === require_route_registry.HEALTH_PATH || pathname === require_route_registry.READY_PATH || pathname === require_route_registry.METRICS_PATH))) {
1498
2130
  if (!require_api_key_auth.validateRequestApiKey(req, resolvedAuth.policy).ok) {
1499
2131
  require_api_key_auth.writeApiKeyHttpRejection(res, setCorsHeaders);
1500
2132
  return;
1501
2133
  }
1502
2134
  require_api_key_auth.markAuthenticatedRequest(req, resolvedAuth.policy);
1503
2135
  }
1504
- if (pathname.startsWith(CONTROL_PREFIX)) {
1505
- await handleControlAPI(req, res, pathname, parsedUrl.searchParams, fixtures, journal, videoStates, openRouterVideoJobs, veoVideoJobs, grokVideoJobs, bytePlusVideoJobs, defaults);
2136
+ if (pathname.startsWith(require_route_registry.CONTROL_PREFIX)) {
2137
+ ensureRawFixturePositions();
2138
+ await handleControlAPI(req, res, pathname, parsedUrl.searchParams, fixtures, journal, videoStates, openRouterVideoJobs, veoVideoJobs, grokVideoJobs, bytePlusVideoJobs, defaults, mountList);
1506
2139
  return;
1507
2140
  }
1508
- if (mounts) {
1509
- for (const { path: mountPath, handler } of mounts) if (pathname === mountPath || pathname.startsWith(mountPath + "/")) {
1510
- const subPath = pathname.slice(mountPath.length) || "/";
1511
- if (await handler.handleRequest(req, res, subPath)) return;
1512
- }
2141
+ const misbehaviorHeader = defaults.misbehavior ? require_misbehavior.parseMisbehaviorHeader(req.headers["x-aimock-misbehavior"]) : void 0;
2142
+ if (misbehaviorHeader && !misbehaviorHeader.ok) {
2143
+ const detail = misbehaviorHeader.issue.message;
2144
+ const message = `aimock_misbehavior_invalid: ${detail}`;
2145
+ logger.error(`${req.method ?? "?"} ${pathname}: ${message}`);
2146
+ journal.add({
2147
+ method: req.method ?? "?",
2148
+ path: req.url ?? pathname,
2149
+ headers: require_helpers.flattenHeaders(req.headers),
2150
+ body: null,
2151
+ response: {
2152
+ status: 400,
2153
+ fixture: null,
2154
+ source: "internal",
2155
+ error: message
2156
+ }
2157
+ });
2158
+ setCorsHeaders(res);
2159
+ require_sse_writer.writeErrorResponse(res, 400, invalidMisbehaviorHeaderEnvelope(normalizeCompatPath(pathname), detail));
2160
+ return;
1513
2161
  }
1514
- if (pathname === OLLAMA_CHAT_PATH && req.method === "POST") {
2162
+ for (const { path: mountPath, handler } of mountList) if (pathname === mountPath || pathname.startsWith(mountPath + "/")) {
2163
+ const subPath = pathname.slice(mountPath.length) || "/";
2164
+ if (await handler.handleRequest(req, res, subPath)) return;
2165
+ }
2166
+ if (pathname === require_route_registry.OLLAMA_CHAT_PATH && req.method === "POST") {
1515
2167
  try {
1516
- await require_ollama.handleOllama(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
2168
+ const raw = await require_helpers.readBody(req);
2169
+ ensureRawFixturePositions();
2170
+ await require_ollama.handleOllama(req, res, raw, fixtures, journal, defaults, setCorsHeaders);
1517
2171
  } catch (err) {
1518
2172
  routeError(req, res, err, pathname);
1519
2173
  }
1520
2174
  return;
1521
2175
  }
1522
- if (pathname === OLLAMA_GENERATE_PATH && req.method === "POST") {
2176
+ if (pathname === require_route_registry.OLLAMA_GENERATE_PATH && req.method === "POST") {
1523
2177
  try {
1524
- await require_ollama.handleOllamaGenerate(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
2178
+ const raw = await require_helpers.readBody(req);
2179
+ ensureRawFixturePositions();
2180
+ await require_ollama.handleOllamaGenerate(req, res, raw, fixtures, journal, defaults, setCorsHeaders);
1525
2181
  } catch (err) {
1526
2182
  routeError(req, res, err, pathname);
1527
2183
  }
1528
2184
  return;
1529
2185
  }
1530
- if ((pathname === OLLAMA_EMBEDDINGS_PATH || pathname === OLLAMA_EMBED_PATH) && req.method === "POST") {
2186
+ if ((pathname === require_route_registry.OLLAMA_EMBEDDINGS_PATH || pathname === require_route_registry.OLLAMA_EMBED_PATH) && req.method === "POST") {
1531
2187
  try {
1532
- await require_ollama.handleOllamaEmbeddings(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
2188
+ const raw = await require_helpers.readBody(req);
2189
+ ensureRawFixturePositions();
2190
+ await require_ollama.handleOllamaEmbeddings(req, res, raw, fixtures, journal, defaults, setCorsHeaders);
1533
2191
  } catch (err) {
1534
2192
  routeError(req, res, err, pathname);
1535
2193
  }
1536
2194
  return;
1537
2195
  }
1538
- if (pathname === OLLAMA_TAGS_PATH && req.method === "GET") {
2196
+ if (pathname === require_route_registry.OLLAMA_TAGS_PATH && req.method === "GET") {
1539
2197
  setCorsHeaders(res);
1540
2198
  const modelIds = /* @__PURE__ */ new Set();
1541
2199
  for (const f of fixtures) if (f.match.model && typeof f.match.model === "string") modelIds.add(f.match.model);
@@ -1551,7 +2209,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1551
2209
  res.end(JSON.stringify({ models }));
1552
2210
  return;
1553
2211
  }
1554
- const openRouterVideoContentMatch = pathname.match(require_metrics.OPENROUTER_VIDEO_CONTENT_RE);
2212
+ const openRouterVideoContentMatch = pathname.match(require_route_registry.OPENROUTER_VIDEO_CONTENT_RE);
1555
2213
  if (openRouterVideoContentMatch && req.method === "GET") {
1556
2214
  try {
1557
2215
  await require_openrouter_video.handleOpenRouterVideoContent(req, res, openRouterVideoContentMatch[1], journal, defaults, setCorsHeaders, openRouterVideoJobs);
@@ -1560,77 +2218,85 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1560
2218
  }
1561
2219
  return;
1562
2220
  }
1563
- if (pathname === OPENROUTER_VIDEO_MODELS_PATH && req.method === "GET") {
2221
+ if (pathname === require_route_registry.OPENROUTER_VIDEO_MODELS_PATH && req.method === "GET") {
1564
2222
  try {
2223
+ ensureRawFixturePositions();
1565
2224
  await require_openrouter_video.handleOpenRouterVideoModels(req, res, fixtures, journal, defaults, setCorsHeaders);
1566
2225
  } catch (err) {
1567
2226
  routeError(req, res, err, pathname);
1568
2227
  }
1569
2228
  return;
1570
2229
  }
1571
- const openRouterVideoStatusMatch = pathname.match(require_metrics.OPENROUTER_VIDEO_STATUS_RE);
2230
+ const openRouterVideoStatusMatch = pathname.match(require_route_registry.OPENROUTER_VIDEO_STATUS_RE);
1572
2231
  if (openRouterVideoStatusMatch && req.method === "GET") {
1573
2232
  try {
2233
+ ensureRawFixturePositions();
1574
2234
  await require_openrouter_video.handleOpenRouterVideoStatus(req, res, openRouterVideoStatusMatch[1], fixtures, journal, defaults, setCorsHeaders, openRouterVideoJobs);
1575
2235
  } catch (err) {
1576
2236
  routeError(req, res, err, pathname);
1577
2237
  }
1578
2238
  return;
1579
2239
  }
1580
- if (pathname === OPENROUTER_VIDEOS_PATH && req.method === "POST") {
2240
+ if (pathname === require_route_registry.OPENROUTER_VIDEOS_PATH && req.method === "POST") {
1581
2241
  setCorsHeaders(res);
1582
2242
  try {
1583
- await require_openrouter_video.handleOpenRouterVideoCreate(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, openRouterVideoJobs);
2243
+ const raw = await require_helpers.readBody(req);
2244
+ ensureRawFixturePositions();
2245
+ await require_openrouter_video.handleOpenRouterVideoCreate(req, res, raw, fixtures, journal, defaults, setCorsHeaders, openRouterVideoJobs);
1584
2246
  } catch (err) {
1585
2247
  routeError(req, res, err, pathname);
1586
2248
  }
1587
2249
  return;
1588
2250
  }
1589
- const bytePlusVideoStatusMatch = pathname.match(require_metrics.BYTEPLUS_VIDEO_STATUS_RE);
2251
+ const bytePlusVideoStatusMatch = pathname.match(require_route_registry.BYTEPLUS_VIDEO_STATUS_RE);
1590
2252
  if (bytePlusVideoStatusMatch && req.method === "GET") {
1591
2253
  try {
2254
+ ensureRawFixturePositions();
1592
2255
  await require_byteplus_video.handleBytePlusVideoStatus(req, res, bytePlusVideoStatusMatch[1], fixtures, journal, defaults, setCorsHeaders, bytePlusVideoJobs);
1593
2256
  } catch (err) {
1594
2257
  routeError(req, res, err, pathname);
1595
2258
  }
1596
2259
  return;
1597
2260
  }
1598
- if (require_metrics.BYTEPLUS_VIDEO_SUBMIT_RE.test(pathname) && req.method === "POST") {
2261
+ if (require_route_registry.BYTEPLUS_VIDEO_SUBMIT_RE.test(pathname) && req.method === "POST") {
1599
2262
  setCorsHeaders(res);
1600
2263
  try {
1601
- await require_byteplus_video.handleBytePlusVideoCreate(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, bytePlusVideoJobs);
2264
+ const raw = await require_helpers.readBody(req);
2265
+ ensureRawFixturePositions();
2266
+ await require_byteplus_video.handleBytePlusVideoCreate(req, res, raw, fixtures, journal, defaults, setCorsHeaders, bytePlusVideoJobs);
1602
2267
  } catch (err) {
1603
2268
  routeError(req, res, err, pathname);
1604
2269
  }
1605
2270
  return;
1606
2271
  }
1607
- if (pathname === "/api/v1/models" && req.method === "GET") {
2272
+ if (pathname === require_route_registry.OPENROUTER_MODELS_PATH && req.method === "GET") {
2273
+ ensureRawFixturePositions();
1608
2274
  require_openrouter_chat.handleOpenRouterModels(req, res, fixtures, journal, defaults, setCorsHeaders);
1609
2275
  return;
1610
2276
  }
1611
- if (pathname === "/api/v1/key" && req.method === "GET") {
2277
+ if (pathname === require_route_registry.OPENROUTER_KEY_PATH && req.method === "GET") {
1612
2278
  require_openrouter_chat.handleOpenRouterKey(req, res, journal, setCorsHeaders);
1613
2279
  return;
1614
2280
  }
1615
- if (pathname === "/api/v1/credits" && req.method === "GET") {
2281
+ if (pathname === require_route_registry.OPENROUTER_CREDITS_PATH && req.method === "GET") {
1616
2282
  require_openrouter_chat.handleOpenRouterCredits(req, res, journal, setCorsHeaders);
1617
2283
  return;
1618
2284
  }
1619
2285
  let azureDeploymentId;
1620
- const azureMatch = pathname.match(AZURE_DEPLOYMENT_RE);
2286
+ const azureMatch = pathname.match(require_route_registry.AZURE_DEPLOYMENT_RE);
1621
2287
  if (azureMatch && req.method === "POST") {
1622
2288
  azureDeploymentId = azureMatch[1];
1623
2289
  pathname = `/v1/${azureMatch[2]}`;
1624
2290
  }
1625
2291
  if (!azureDeploymentId) pathname = normalizeCompatPath(pathname, logger);
1626
- if (pathname === HEALTH_PATH && req.method === "GET") {
2292
+ if (pathname === require_route_registry.HEALTH_PATH && req.method === "GET") {
1627
2293
  setCorsHeaders(res);
1628
- if (mounts && mounts.length > 0) {
2294
+ if (mountList.length > 0) {
1629
2295
  const services = { llm: {
1630
2296
  status: "ok",
1631
2297
  fixtures: fixtures.length
1632
2298
  } };
1633
- for (const { path: mountPath, handler } of mounts) if (handler.health) {
2299
+ for (const { path: mountPath, handler } of mountList) if (handler.health) {
1634
2300
  const name = mountPath.replace(/^\//, "");
1635
2301
  services[name] = handler.health();
1636
2302
  }
@@ -1645,13 +2311,13 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1645
2311
  }
1646
2312
  return;
1647
2313
  }
1648
- if (pathname === READY_PATH && req.method === "GET") {
2314
+ if (pathname === require_route_registry.READY_PATH && req.method === "GET") {
1649
2315
  setCorsHeaders(res);
1650
2316
  res.writeHead(200, { "Content-Type": "application/json" });
1651
2317
  res.end(JSON.stringify({ status: "ready" }));
1652
2318
  return;
1653
2319
  }
1654
- if (pathname === "/metrics" && req.method === "GET") {
2320
+ if (pathname === require_route_registry.METRICS_PATH && req.method === "GET") {
1655
2321
  if (!registry) {
1656
2322
  handleNotFound(res, "Not found");
1657
2323
  return;
@@ -1661,7 +2327,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1661
2327
  res.end(registry.serialize());
1662
2328
  return;
1663
2329
  }
1664
- if (pathname === MODELS_PATH && req.method === "GET") {
2330
+ if (pathname === require_route_registry.MODELS_PATH && req.method === "GET") {
1665
2331
  setCorsHeaders(res);
1666
2332
  const modelIds = /* @__PURE__ */ new Set();
1667
2333
  for (const f of fixtures) if (f.match.model && typeof f.match.model === "string") modelIds.add(f.match.model);
@@ -1678,7 +2344,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1678
2344
  }));
1679
2345
  return;
1680
2346
  }
1681
- const batchesCancelMatch = pathname.match(BATCHES_CANCEL_RE);
2347
+ const batchesCancelMatch = pathname.match(require_route_registry.BATCHES_CANCEL_RE);
1682
2348
  if (batchesCancelMatch && req.method === "POST") {
1683
2349
  try {
1684
2350
  await require_helpers.readBody(req);
@@ -1688,7 +2354,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1688
2354
  }
1689
2355
  return;
1690
2356
  }
1691
- const batchesIdMatch = pathname.match(BATCHES_ID_RE);
2357
+ const batchesIdMatch = pathname.match(require_route_registry.BATCHES_ID_RE);
1692
2358
  if (batchesIdMatch && req.method === "GET") {
1693
2359
  try {
1694
2360
  await require_batches.handleBatchesRetrieve(req, res, batchesIdMatch[1], journal, defaults, setCorsHeaders);
@@ -1697,7 +2363,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1697
2363
  }
1698
2364
  return;
1699
2365
  }
1700
- if (pathname === BATCHES_PATH && req.method === "GET") {
2366
+ if (pathname === require_route_registry.BATCHES_PATH && req.method === "GET") {
1701
2367
  try {
1702
2368
  await require_batches.handleBatchesList(req, res, journal, defaults, setCorsHeaders);
1703
2369
  } catch (err) {
@@ -1705,7 +2371,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1705
2371
  }
1706
2372
  return;
1707
2373
  }
1708
- if (pathname === BATCHES_PATH && req.method === "POST") {
2374
+ if (pathname === require_route_registry.BATCHES_PATH && req.method === "POST") {
1709
2375
  try {
1710
2376
  await require_batches.handleBatchesCreate(req, res, await require_helpers.readBody(req), journal, defaults, setCorsHeaders);
1711
2377
  } catch (err) {
@@ -1713,7 +2379,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1713
2379
  }
1714
2380
  return;
1715
2381
  }
1716
- const filesContentMatch = pathname.match(require_metrics.FILES_CONTENT_RE);
2382
+ const filesContentMatch = pathname.match(require_route_registry.FILES_CONTENT_RE);
1717
2383
  if (filesContentMatch && req.method === "GET") {
1718
2384
  try {
1719
2385
  await require_files.handleFilesContent(req, res, filesContentMatch[1], journal, defaults, setCorsHeaders);
@@ -1722,7 +2388,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1722
2388
  }
1723
2389
  return;
1724
2390
  }
1725
- const filesIdMatch = pathname.match(require_metrics.FILES_ID_RE);
2391
+ const filesIdMatch = pathname.match(require_route_registry.FILES_ID_RE);
1726
2392
  if (filesIdMatch && req.method === "GET") {
1727
2393
  try {
1728
2394
  await require_files.handleFilesRetrieve(req, res, filesIdMatch[1], journal, defaults, setCorsHeaders);
@@ -1739,7 +2405,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1739
2405
  }
1740
2406
  return;
1741
2407
  }
1742
- if (pathname === FILES_PATH && req.method === "GET") {
2408
+ if (pathname === require_route_registry.FILES_PATH && req.method === "GET") {
1743
2409
  try {
1744
2410
  await require_files.handleFilesList(req, res, journal, defaults, setCorsHeaders);
1745
2411
  } catch (err) {
@@ -1747,7 +2413,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1747
2413
  }
1748
2414
  return;
1749
2415
  }
1750
- if (pathname === FILES_PATH && req.method === "POST") {
2416
+ if (pathname === require_route_registry.FILES_PATH && req.method === "POST") {
1751
2417
  try {
1752
2418
  await require_files.handleFilesCreate(req, res, (await require_helpers.readBodyBufferBounded(req, require_files.FILES_BODY_MAX_BYTES, require_files.FILES_BODY_DRAIN_MAX_BYTES)).buffer ?? require_files.FILES_BODY_OVERSIZED, journal, defaults, setCorsHeaders);
1753
2419
  } catch (err) {
@@ -1755,7 +2421,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1755
2421
  }
1756
2422
  return;
1757
2423
  }
1758
- const ftCancelMatch = pathname.match(FINE_TUNING_CANCEL_RE);
2424
+ const ftCancelMatch = pathname.match(require_route_registry.FINE_TUNING_CANCEL_RE);
1759
2425
  if (ftCancelMatch && req.method === "POST") {
1760
2426
  try {
1761
2427
  await require_helpers.readBody(req);
@@ -1765,7 +2431,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1765
2431
  }
1766
2432
  return;
1767
2433
  }
1768
- const ftEventsMatch = pathname.match(FINE_TUNING_EVENTS_RE);
2434
+ const ftEventsMatch = pathname.match(require_route_registry.FINE_TUNING_EVENTS_RE);
1769
2435
  if (ftEventsMatch && req.method === "GET") {
1770
2436
  try {
1771
2437
  await require_fine_tuning.handleFineTuningEvents(req, res, ftEventsMatch[1], journal, defaults, setCorsHeaders);
@@ -1774,7 +2440,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1774
2440
  }
1775
2441
  return;
1776
2442
  }
1777
- const ftIdMatch = pathname.match(FINE_TUNING_ID_RE);
2443
+ const ftIdMatch = pathname.match(require_route_registry.FINE_TUNING_ID_RE);
1778
2444
  if (ftIdMatch && req.method === "GET") {
1779
2445
  try {
1780
2446
  await require_fine_tuning.handleFineTuningRetrieve(req, res, ftIdMatch[1], journal, defaults, setCorsHeaders);
@@ -1783,7 +2449,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1783
2449
  }
1784
2450
  return;
1785
2451
  }
1786
- if (pathname === FINE_TUNING_JOBS_PATH && req.method === "GET") {
2452
+ if (pathname === require_route_registry.FINE_TUNING_JOBS_PATH && req.method === "GET") {
1787
2453
  try {
1788
2454
  await require_fine_tuning.handleFineTuningList(req, res, journal, defaults, setCorsHeaders);
1789
2455
  } catch (err) {
@@ -1791,7 +2457,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1791
2457
  }
1792
2458
  return;
1793
2459
  }
1794
- if (pathname === FINE_TUNING_JOBS_PATH && req.method === "POST") {
2460
+ if (pathname === require_route_registry.FINE_TUNING_JOBS_PATH && req.method === "POST") {
1795
2461
  try {
1796
2462
  await require_fine_tuning.handleFineTuningCreate(req, res, await require_helpers.readBody(req), journal, defaults, setCorsHeaders);
1797
2463
  } catch (err) {
@@ -1799,14 +2465,140 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1799
2465
  }
1800
2466
  return;
1801
2467
  }
1802
- if (pathname === REQUESTS_PATH) {
2468
+ const vsSearchMatch = pathname.match(require_route_registry.VECTOR_STORES_SEARCH_RE);
2469
+ if (vsSearchMatch && req.method === "POST") {
2470
+ try {
2471
+ const raw = await require_helpers.readBody(req);
2472
+ await require_vector_stores.handleVectorStoresSearch(req, res, vsSearchMatch[1], raw, journal, defaults, setCorsHeaders);
2473
+ } catch (err) {
2474
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2475
+ }
2476
+ return;
2477
+ }
2478
+ const vsBatchFilesMatch = pathname.match(require_route_registry.VECTOR_STORES_BATCH_FILES_RE);
2479
+ if (vsBatchFilesMatch && req.method === "GET") {
2480
+ try {
2481
+ await require_vector_stores.handleVectorFileBatchesFiles(req, res, vsBatchFilesMatch[1], vsBatchFilesMatch[2], journal, defaults, setCorsHeaders);
2482
+ } catch (err) {
2483
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2484
+ }
2485
+ return;
2486
+ }
2487
+ const vsBatchCancelMatch = pathname.match(require_route_registry.VECTOR_STORES_BATCH_CANCEL_RE);
2488
+ if (vsBatchCancelMatch && req.method === "POST") {
2489
+ try {
2490
+ await require_helpers.readBody(req);
2491
+ await require_vector_stores.handleVectorFileBatchesCancel(req, res, vsBatchCancelMatch[1], vsBatchCancelMatch[2], journal, defaults, setCorsHeaders);
2492
+ } catch (err) {
2493
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2494
+ }
2495
+ return;
2496
+ }
2497
+ const vsBatchMatch = pathname.match(require_route_registry.VECTOR_STORES_BATCH_RE);
2498
+ if (vsBatchMatch && req.method === "GET") {
2499
+ try {
2500
+ await require_vector_stores.handleVectorFileBatchesRetrieve(req, res, vsBatchMatch[1], vsBatchMatch[2], journal, defaults, setCorsHeaders);
2501
+ } catch (err) {
2502
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2503
+ }
2504
+ return;
2505
+ }
2506
+ const vsFileMatch = pathname.match(require_route_registry.VECTOR_STORES_FILE_RE);
2507
+ if (vsFileMatch && req.method === "GET") {
2508
+ try {
2509
+ await require_vector_stores.handleVectorStoreFilesRetrieve(req, res, vsFileMatch[1], vsFileMatch[2], journal, defaults, setCorsHeaders);
2510
+ } catch (err) {
2511
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2512
+ }
2513
+ return;
2514
+ }
2515
+ if (vsFileMatch && req.method === "DELETE") {
2516
+ try {
2517
+ await require_vector_stores.handleVectorStoreFilesDelete(req, res, vsFileMatch[1], vsFileMatch[2], journal, defaults, setCorsHeaders);
2518
+ } catch (err) {
2519
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2520
+ }
2521
+ return;
2522
+ }
2523
+ const vsIdMatch = pathname.match(require_route_registry.VECTOR_STORES_ID_RE);
2524
+ if (vsIdMatch && req.method === "GET") {
2525
+ try {
2526
+ await require_vector_stores.handleVectorStoresRetrieve(req, res, vsIdMatch[1], journal, defaults, setCorsHeaders);
2527
+ } catch (err) {
2528
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2529
+ }
2530
+ return;
2531
+ }
2532
+ if (vsIdMatch && req.method === "POST") {
2533
+ try {
2534
+ const raw = await require_helpers.readBody(req);
2535
+ await require_vector_stores.handleVectorStoresModify(req, res, vsIdMatch[1], raw, journal, defaults, setCorsHeaders);
2536
+ } catch (err) {
2537
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2538
+ }
2539
+ return;
2540
+ }
2541
+ if (vsIdMatch && req.method === "DELETE") {
2542
+ try {
2543
+ await require_vector_stores.handleVectorStoresDelete(req, res, vsIdMatch[1], journal, defaults, setCorsHeaders);
2544
+ } catch (err) {
2545
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2546
+ }
2547
+ return;
2548
+ }
2549
+ if (require_route_registry.VECTOR_STORES_FILES_RE.test(pathname) && req.method === "POST") {
2550
+ try {
2551
+ const raw = await require_helpers.readBody(req);
2552
+ const storeId = pathname.split("/")[3];
2553
+ await require_vector_stores.handleVectorStoreFilesCreate(req, res, storeId, raw, journal, defaults, setCorsHeaders);
2554
+ } catch (err) {
2555
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2556
+ }
2557
+ return;
2558
+ }
2559
+ if (require_route_registry.VECTOR_STORES_FILES_RE.test(pathname) && req.method === "GET") {
2560
+ try {
2561
+ const storeId = pathname.split("/")[3];
2562
+ await require_vector_stores.handleVectorStoreFilesList(req, res, storeId, journal, defaults, setCorsHeaders);
2563
+ } catch (err) {
2564
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2565
+ }
2566
+ return;
2567
+ }
2568
+ if (require_route_registry.VECTOR_STORES_FILE_BATCHES_RE.test(pathname) && req.method === "POST") {
2569
+ try {
2570
+ const raw = await require_helpers.readBody(req);
2571
+ const storeId = pathname.split("/")[3];
2572
+ await require_vector_stores.handleVectorFileBatchesCreate(req, res, storeId, raw, journal, defaults, setCorsHeaders);
2573
+ } catch (err) {
2574
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2575
+ }
2576
+ return;
2577
+ }
2578
+ if (pathname === require_route_registry.VECTOR_STORES_PATH && req.method === "GET") {
2579
+ try {
2580
+ await require_vector_stores.handleVectorStoresList(req, res, journal, defaults, setCorsHeaders);
2581
+ } catch (err) {
2582
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2583
+ }
2584
+ return;
2585
+ }
2586
+ if (pathname === require_route_registry.VECTOR_STORES_PATH && req.method === "POST") {
2587
+ try {
2588
+ await require_vector_stores.handleVectorStoresCreate(req, res, await require_helpers.readBody(req), journal, defaults, setCorsHeaders);
2589
+ } catch (err) {
2590
+ routeError(req, res, err, pathname, { service: "vector-stores" });
2591
+ }
2592
+ return;
2593
+ }
2594
+ if (pathname === require_route_registry.REQUESTS_PATH) {
1803
2595
  setCorsHeaders(res);
1804
2596
  if (req.method === "GET") {
1805
2597
  const limitParam = parsedUrl.searchParams.get("limit");
1806
2598
  let opts;
1807
2599
  if (limitParam) {
1808
- const limit = parseInt(limitParam, 10);
1809
- if (Number.isNaN(limit) || limit <= 0) {
2600
+ const limit = Number(limitParam);
2601
+ if (!/^\+?\d+$/.test(limitParam.trim()) || !Number.isSafeInteger(limit) || limit <= 0) {
1810
2602
  require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
1811
2603
  message: `Invalid limit parameter: "${limitParam}"`,
1812
2604
  type: "invalid_request_error"
@@ -1817,7 +2609,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1817
2609
  }
1818
2610
  const entries = journal.getAll(opts);
1819
2611
  res.writeHead(200, { "Content-Type": "application/json" });
1820
- res.end(JSON.stringify(entries));
2612
+ res.end(journalJson(entries, journal));
1821
2613
  return;
1822
2614
  }
1823
2615
  if (req.method === "DELETE") {
@@ -1829,39 +2621,47 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1829
2621
  handleNotFound(res, "Not found");
1830
2622
  return;
1831
2623
  }
1832
- if (pathname === RESPONSES_PATH && req.method === "POST") {
2624
+ if (pathname === require_route_registry.RESPONSES_PATH && req.method === "POST") {
1833
2625
  try {
1834
- await require_responses.handleResponses(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
2626
+ const raw = await require_helpers.readBody(req);
2627
+ ensureRawFixturePositions();
2628
+ await require_responses.handleResponses(req, res, raw, fixtures, journal, defaults, setCorsHeaders);
1835
2629
  } catch (err) {
1836
2630
  routeError(req, res, err, pathname, { streamEvent: (m) => `event: error\ndata: ${JSON.stringify({ error: { message: m } })}\n\n` });
1837
2631
  }
1838
2632
  return;
1839
2633
  }
1840
- if (pathname === MESSAGES_PATH && req.method === "POST") {
2634
+ if (pathname === require_route_registry.MESSAGES_PATH && req.method === "POST") {
1841
2635
  try {
1842
- await require_messages.handleMessages(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
2636
+ const raw = await require_helpers.readBody(req);
2637
+ ensureRawFixturePositions();
2638
+ await require_messages.handleMessages(req, res, raw, fixtures, journal, defaults, setCorsHeaders);
1843
2639
  } catch (err) {
1844
2640
  routeError(req, res, err, pathname, { streamEvent: (m) => `event: error\ndata: ${JSON.stringify({ error: { message: m } })}\n\n` });
1845
2641
  }
1846
2642
  return;
1847
2643
  }
1848
- if (pathname === COHERE_CHAT_PATH && req.method === "POST") {
2644
+ if (pathname === require_route_registry.COHERE_CHAT_PATH && req.method === "POST") {
1849
2645
  try {
1850
- await require_cohere.handleCohere(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
2646
+ const raw = await require_helpers.readBody(req);
2647
+ ensureRawFixturePositions();
2648
+ await require_cohere.handleCohere(req, res, raw, fixtures, journal, defaults, setCorsHeaders);
1851
2649
  } catch (err) {
1852
2650
  routeError(req, res, err, pathname, { streamEvent: (m) => `event: error\ndata: ${JSON.stringify({ error: { message: m } })}\n\n` });
1853
2651
  }
1854
2652
  return;
1855
2653
  }
1856
- if (pathname === COHERE_EMBED_PATH && req.method === "POST") {
2654
+ if (pathname === require_route_registry.COHERE_EMBED_PATH && req.method === "POST") {
1857
2655
  try {
1858
- await require_cohere.handleCohereEmbed(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
2656
+ const raw = await require_helpers.readBody(req);
2657
+ ensureRawFixturePositions();
2658
+ await require_cohere.handleCohereEmbed(req, res, raw, fixtures, journal, defaults, setCorsHeaders);
1859
2659
  } catch (err) {
1860
2660
  routeError(req, res, err, pathname);
1861
2661
  }
1862
2662
  return;
1863
2663
  }
1864
- if (pathname === EMBEDDINGS_PATH && req.method === "POST") {
2664
+ if (pathname === require_route_registry.EMBEDDINGS_PATH && req.method === "POST") {
1865
2665
  try {
1866
2666
  const deploymentId = azureDeploymentId;
1867
2667
  const embeddingsProvider = azureDeploymentId ? "azure" : "openai";
@@ -1875,196 +2675,235 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
1875
2675
  } catch (err) {
1876
2676
  if (!(err instanceof SyntaxError)) defaults.logger.error(`Unexpected error in Azure model injection: ${err instanceof Error ? err.message : String(err)}`);
1877
2677
  }
1878
- await require_embeddings.handleEmbeddings(req, res, raw, fixtures, journal, defaults, setCorsHeaders, embeddingsProvider);
2678
+ ensureRawFixturePositions();
2679
+ await require_embeddings.handleEmbeddings(req, res, raw, fixtures, journal, defaults, setCorsHeaders, embeddingsProvider, originalPathname === require_route_registry.EMBEDDINGS_PATH);
1879
2680
  } catch (err) {
1880
2681
  routeError(req, res, err, pathname);
1881
2682
  }
1882
2683
  return;
1883
2684
  }
1884
- if (pathname === IMAGES_PATH && req.method === "POST") {
2685
+ if (pathname === require_route_registry.IMAGES_PATH && req.method === "POST") {
1885
2686
  try {
1886
- await require_images.handleImages(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, "openai", void 0, isBytePlusArk ? "byteplus" : void 0);
2687
+ const raw = await require_helpers.readBody(req);
2688
+ ensureRawFixturePositions();
2689
+ await require_images.handleImages(req, res, raw, fixtures, journal, defaults, setCorsHeaders, "openai", void 0, isBytePlusArk ? "byteplus" : void 0);
1887
2690
  } catch (err) {
1888
2691
  routeError(req, res, err, pathname);
1889
2692
  }
1890
2693
  return;
1891
2694
  }
1892
- if (pathname === IMAGES_EDIT_PATH && req.method === "POST") {
2695
+ if (pathname === require_route_registry.IMAGES_EDIT_PATH && req.method === "POST") {
1893
2696
  try {
1894
- await require_images.handleImageEdit(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
2697
+ const raw = await require_helpers.readBody(req);
2698
+ ensureRawFixturePositions();
2699
+ await require_images.handleImageEdit(req, res, raw, fixtures, journal, defaults, setCorsHeaders);
1895
2700
  } catch (err) {
1896
2701
  routeError(req, res, err, pathname);
1897
2702
  }
1898
2703
  return;
1899
2704
  }
1900
- if (pathname === IMAGES_VARIATIONS_PATH && req.method === "POST") {
2705
+ if (pathname === require_route_registry.IMAGES_VARIATIONS_PATH && req.method === "POST") {
1901
2706
  try {
1902
- await require_images.handleImageVariations(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
2707
+ const raw = await require_helpers.readBody(req);
2708
+ ensureRawFixturePositions();
2709
+ await require_images.handleImageVariations(req, res, raw, fixtures, journal, defaults, setCorsHeaders);
1903
2710
  } catch (err) {
1904
2711
  routeError(req, res, err, pathname);
1905
2712
  }
1906
2713
  return;
1907
2714
  }
1908
- if (pathname === SPEECH_PATH && req.method === "POST") {
2715
+ if (pathname === require_route_registry.SPEECH_PATH && req.method === "POST") {
1909
2716
  try {
1910
- await require_speech.handleSpeech(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
2717
+ const raw = await require_helpers.readBody(req);
2718
+ ensureRawFixturePositions();
2719
+ await require_speech.handleSpeech(req, res, raw, fixtures, journal, defaults, setCorsHeaders);
1911
2720
  } catch (err) {
1912
2721
  routeError(req, res, err, pathname);
1913
2722
  }
1914
2723
  return;
1915
2724
  }
1916
- if (pathname === TRANSCRIPTIONS_PATH && req.method === "POST") {
2725
+ if (pathname === require_route_registry.TRANSCRIPTIONS_PATH && req.method === "POST") {
1917
2726
  try {
1918
- await require_transcription.handleTranscription(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
2727
+ const raw = await require_helpers.readBody(req);
2728
+ ensureRawFixturePositions();
2729
+ await require_transcription.handleTranscription(req, res, raw, fixtures, journal, defaults, setCorsHeaders);
1919
2730
  } catch (err) {
1920
2731
  routeError(req, res, err, pathname);
1921
2732
  }
1922
2733
  return;
1923
2734
  }
1924
- if (pathname === TRANSLATIONS_PATH && req.method === "POST") {
2735
+ if (pathname === require_route_registry.TRANSLATIONS_PATH && req.method === "POST") {
1925
2736
  try {
1926
- await require_transcription.handleTranscription(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, "translation");
2737
+ const raw = await require_helpers.readBody(req);
2738
+ ensureRawFixturePositions();
2739
+ await require_transcription.handleTranscription(req, res, raw, fixtures, journal, defaults, setCorsHeaders, "translation");
1927
2740
  } catch (err) {
1928
2741
  routeError(req, res, err, pathname);
1929
2742
  }
1930
2743
  return;
1931
2744
  }
1932
- if (pathname === require_metrics.GROK_VIDEO_SUBMIT_PATH && req.method === "POST") {
2745
+ if (pathname === require_route_registry.GROK_VIDEO_SUBMIT_PATH && req.method === "POST") {
1933
2746
  setCorsHeaders(res);
1934
2747
  try {
1935
- await require_grok_video.handleGrokVideoCreate(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, grokVideoJobs);
2748
+ const raw = await require_helpers.readBody(req);
2749
+ ensureRawFixturePositions();
2750
+ await require_grok_video.handleGrokVideoCreate(req, res, raw, fixtures, journal, defaults, setCorsHeaders, grokVideoJobs);
1936
2751
  } catch (err) {
1937
2752
  routeError(req, res, err, pathname);
1938
2753
  }
1939
2754
  return;
1940
2755
  }
1941
- if (pathname === VIDEOS_PATH && req.method === "POST") {
2756
+ if (pathname === require_route_registry.VIDEOS_PATH && req.method === "POST") {
1942
2757
  try {
1943
- await require_video.handleVideoCreate(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, videoStates);
2758
+ const raw = await require_helpers.readBody(req);
2759
+ ensureRawFixturePositions();
2760
+ await require_video.handleVideoCreate(req, res, raw, fixtures, journal, defaults, setCorsHeaders, videoStates);
1944
2761
  } catch (err) {
1945
2762
  routeError(req, res, err, pathname);
1946
2763
  }
1947
2764
  return;
1948
2765
  }
1949
- const grokVideoStatusMatch = pathname.match(require_metrics.GROK_VIDEO_STATUS_RE);
2766
+ const grokVideoStatusMatch = pathname.match(require_route_registry.GROK_VIDEO_STATUS_RE);
1950
2767
  if (grokVideoStatusMatch && grokVideoStatusMatch[1] !== "generations" && req.method === "GET") {
1951
2768
  try {
2769
+ ensureRawFixturePositions();
1952
2770
  await require_grok_video.handleGrokVideoStatus(req, res, grokVideoStatusMatch[1], fixtures, journal, defaults, setCorsHeaders, grokVideoJobs, videoStates);
1953
2771
  } catch (err) {
1954
2772
  routeError(req, res, err, pathname);
1955
2773
  }
1956
2774
  return;
1957
2775
  }
1958
- const veoPredictMatch = pathname.match(require_metrics.VEO_PREDICT_LRO_RE);
2776
+ const veoPredictMatch = pathname.match(require_route_registry.VEO_PREDICT_LRO_RE);
1959
2777
  if (veoPredictMatch && req.method === "POST") {
1960
2778
  setCorsHeaders(res);
1961
2779
  try {
1962
- await require_veo_video.handleVeoVideoCreate(req, res, await require_helpers.readBody(req), veoPredictMatch[1], fixtures, journal, defaults, setCorsHeaders, veoVideoJobs);
2780
+ const raw = await require_helpers.readBody(req);
2781
+ ensureRawFixturePositions();
2782
+ await require_veo_video.handleVeoVideoCreate(req, res, raw, veoPredictMatch[1], fixtures, journal, defaults, setCorsHeaders, veoVideoJobs);
1963
2783
  } catch (err) {
1964
2784
  routeError(req, res, err, pathname);
1965
2785
  }
1966
2786
  return;
1967
2787
  }
1968
- const veoOperationMatch = pathname.match(require_metrics.VEO_OPERATION_RE);
2788
+ const veoOperationMatch = pathname.match(require_route_registry.VEO_OPERATION_RE);
1969
2789
  if (veoOperationMatch && req.method === "GET") {
1970
2790
  try {
2791
+ ensureRawFixturePositions();
1971
2792
  await require_veo_video.handleVeoVideoStatus(req, res, veoOperationMatch[1], fixtures, journal, defaults, setCorsHeaders, veoVideoJobs);
1972
2793
  } catch (err) {
1973
2794
  routeError(req, res, err, pathname);
1974
2795
  }
1975
2796
  return;
1976
2797
  }
1977
- const geminiPredictMatch = pathname.match(GEMINI_PREDICT_RE);
2798
+ const geminiPredictMatch = pathname.match(require_route_registry.GEMINI_PREDICT_RE);
1978
2799
  if (geminiPredictMatch && req.method === "POST") {
1979
2800
  const predictModel = geminiPredictMatch[1];
1980
2801
  try {
1981
- await require_images.handleImages(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, "gemini", predictModel);
2802
+ const raw = await require_helpers.readBody(req);
2803
+ ensureRawFixturePositions();
2804
+ await require_images.handleImages(req, res, raw, fixtures, journal, defaults, setCorsHeaders, "gemini", predictModel);
1982
2805
  } catch (err) {
1983
2806
  routeError(req, res, err, pathname);
1984
2807
  }
1985
2808
  return;
1986
2809
  }
1987
- if (pathname === GEMINI_INTERACTIONS_PATH && req.method === "POST") {
2810
+ if (pathname === require_route_registry.GEMINI_INTERACTIONS_PATH && req.method === "POST") {
1988
2811
  try {
1989
- await require_gemini_interactions.handleGeminiInteractions(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
2812
+ const raw = await require_helpers.readBody(req);
2813
+ ensureRawFixturePositions();
2814
+ await require_gemini_interactions.handleGeminiInteractions(req, res, raw, fixtures, journal, defaults, setCorsHeaders);
1990
2815
  } catch (err) {
1991
2816
  routeError(req, res, err, pathname, { streamEvent: (m) => `data: ${JSON.stringify({ error: { message: m } })}\n\n` });
1992
2817
  }
1993
2818
  return;
1994
2819
  }
1995
- const geminiEmbedMatch = pathname.match(GEMINI_EMBED_RE);
2820
+ const geminiEmbedMatch = pathname.match(require_route_registry.GEMINI_EMBED_RE);
1996
2821
  if (geminiEmbedMatch && req.method === "POST") {
1997
2822
  const embedModel = geminiEmbedMatch[1];
1998
2823
  try {
1999
- await require_gemini_embeddings.handleGeminiEmbedContent(req, res, await require_helpers.readBody(req), embedModel, fixtures, journal, defaults, setCorsHeaders);
2824
+ const raw = await require_helpers.readBody(req);
2825
+ ensureRawFixturePositions();
2826
+ await require_gemini_embeddings.handleGeminiEmbedContent(req, res, raw, embedModel, fixtures, journal, defaults, setCorsHeaders);
2000
2827
  } catch (err) {
2001
2828
  routeError(req, res, err, pathname);
2002
2829
  }
2003
2830
  return;
2004
2831
  }
2005
- const geminiMatch = pathname.match(GEMINI_PATH_RE);
2832
+ const geminiMatch = pathname.match(require_route_registry.GEMINI_PATH_RE);
2006
2833
  if (geminiMatch && req.method === "POST") {
2007
2834
  const geminiModel = geminiMatch[1];
2008
2835
  const streaming = geminiMatch[2] === "streamGenerateContent";
2009
2836
  try {
2010
- await require_gemini.handleGemini(req, res, await require_helpers.readBody(req), geminiModel, streaming, fixtures, journal, defaults, setCorsHeaders);
2837
+ const raw = await require_helpers.readBody(req);
2838
+ ensureRawFixturePositions();
2839
+ await require_gemini.handleGemini(req, res, raw, geminiModel, streaming, fixtures, journal, defaults, setCorsHeaders);
2011
2840
  } catch (err) {
2012
2841
  routeError(req, res, err, pathname, { streamEvent: (m) => `data: ${JSON.stringify({ error: { message: m } })}\n\n` });
2013
2842
  }
2014
2843
  return;
2015
2844
  }
2016
- const vertexMatch = pathname.match(VERTEX_AI_RE);
2845
+ const vertexMatch = pathname.match(require_route_registry.VERTEX_AI_RE);
2017
2846
  if (vertexMatch && req.method === "POST") {
2018
2847
  const vertexModel = vertexMatch[1];
2019
2848
  const streaming = vertexMatch[2] === "streamGenerateContent";
2020
2849
  try {
2021
- await require_gemini.handleGemini(req, res, await require_helpers.readBody(req), vertexModel, streaming, fixtures, journal, defaults, setCorsHeaders, "vertexai");
2850
+ const raw = await require_helpers.readBody(req);
2851
+ ensureRawFixturePositions();
2852
+ await require_gemini.handleGemini(req, res, raw, vertexModel, streaming, fixtures, journal, defaults, setCorsHeaders, "vertexai");
2022
2853
  } catch (err) {
2023
2854
  routeError(req, res, err, pathname, { streamEvent: (m) => `data: ${JSON.stringify({ error: { message: m } })}\n\n` });
2024
2855
  }
2025
2856
  return;
2026
2857
  }
2027
- const bedrockMatch = pathname.match(BEDROCK_INVOKE_RE);
2858
+ const bedrockMatch = pathname.match(require_route_registry.BEDROCK_INVOKE_RE);
2028
2859
  if (bedrockMatch && req.method === "POST") {
2029
2860
  const bedrockModelId = bedrockMatch[1];
2030
2861
  try {
2031
- await require_bedrock.handleBedrock(req, res, await require_helpers.readBody(req), bedrockModelId, fixtures, journal, defaults, setCorsHeaders);
2862
+ const raw = await require_helpers.readBody(req);
2863
+ ensureRawFixturePositions();
2864
+ await require_bedrock.handleBedrock(req, res, raw, bedrockModelId, fixtures, journal, defaults, setCorsHeaders);
2032
2865
  } catch (err) {
2033
2866
  routeError(req, res, err, pathname);
2034
2867
  }
2035
2868
  return;
2036
2869
  }
2037
- const bedrockStreamMatch = pathname.match(BEDROCK_STREAM_RE);
2870
+ const bedrockStreamMatch = pathname.match(require_route_registry.BEDROCK_STREAM_RE);
2038
2871
  if (bedrockStreamMatch && req.method === "POST") {
2039
2872
  const bedrockModelId = bedrockStreamMatch[1];
2040
2873
  try {
2041
- await require_bedrock.handleBedrockStream(req, res, await require_helpers.readBody(req), bedrockModelId, fixtures, journal, defaults, setCorsHeaders);
2874
+ const raw = await require_helpers.readBody(req);
2875
+ ensureRawFixturePositions();
2876
+ await require_bedrock.handleBedrockStream(req, res, raw, bedrockModelId, fixtures, journal, defaults, setCorsHeaders);
2042
2877
  } catch (err) {
2043
2878
  routeError(req, res, err, pathname);
2044
2879
  }
2045
2880
  return;
2046
2881
  }
2047
- const converseMatch = pathname.match(BEDROCK_CONVERSE_RE);
2882
+ const converseMatch = pathname.match(require_route_registry.BEDROCK_CONVERSE_RE);
2048
2883
  if (converseMatch && req.method === "POST") {
2049
2884
  const converseModelId = converseMatch[1];
2050
2885
  try {
2051
- await require_bedrock_converse.handleConverse(req, res, await require_helpers.readBody(req), converseModelId, fixtures, journal, defaults, setCorsHeaders);
2886
+ const raw = await require_helpers.readBody(req);
2887
+ ensureRawFixturePositions();
2888
+ await require_bedrock_converse.handleConverse(req, res, raw, converseModelId, fixtures, journal, defaults, setCorsHeaders);
2052
2889
  } catch (err) {
2053
2890
  routeError(req, res, err, pathname);
2054
2891
  }
2055
2892
  return;
2056
2893
  }
2057
- const converseStreamMatch = pathname.match(BEDROCK_CONVERSE_STREAM_RE);
2894
+ const converseStreamMatch = pathname.match(require_route_registry.BEDROCK_CONVERSE_STREAM_RE);
2058
2895
  if (converseStreamMatch && req.method === "POST") {
2059
2896
  const converseStreamModelId = converseStreamMatch[1];
2060
2897
  try {
2061
- await require_bedrock_converse.handleConverseStream(req, res, await require_helpers.readBody(req), converseStreamModelId, fixtures, journal, defaults, setCorsHeaders);
2898
+ const raw = await require_helpers.readBody(req);
2899
+ ensureRawFixturePositions();
2900
+ await require_bedrock_converse.handleConverseStream(req, res, raw, converseStreamModelId, fixtures, journal, defaults, setCorsHeaders);
2062
2901
  } catch (err) {
2063
2902
  routeError(req, res, err, pathname);
2064
2903
  }
2065
2904
  return;
2066
2905
  }
2067
- if (pathname === SEARCH_PATH && req.method === "POST") {
2906
+ if (pathname === require_route_registry.SEARCH_PATH && req.method === "POST") {
2068
2907
  try {
2069
2908
  await require_search.handleSearch(req, res, await require_helpers.readBody(req), serviceFixtures?.search ?? [], journal, defaults, setCorsHeaders);
2070
2909
  } catch (err) {
@@ -2072,7 +2911,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
2072
2911
  }
2073
2912
  return;
2074
2913
  }
2075
- if (pathname === RERANK_PATH && req.method === "POST") {
2914
+ if (pathname === require_route_registry.RERANK_PATH && req.method === "POST") {
2076
2915
  try {
2077
2916
  await require_rerank.handleRerank(req, res, await require_helpers.readBody(req), serviceFixtures?.rerank ?? [], journal, defaults, setCorsHeaders);
2078
2917
  } catch (err) {
@@ -2080,7 +2919,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
2080
2919
  }
2081
2920
  return;
2082
2921
  }
2083
- if (pathname === MODERATIONS_PATH && req.method === "POST") {
2922
+ if (pathname === require_route_registry.MODERATIONS_PATH && req.method === "POST") {
2084
2923
  try {
2085
2924
  await require_moderation.handleModeration(req, res, await require_helpers.readBody(req), serviceFixtures?.moderation ?? [], journal, defaults, setCorsHeaders);
2086
2925
  } catch (err) {
@@ -2088,34 +2927,40 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
2088
2927
  }
2089
2928
  return;
2090
2929
  }
2091
- if (pathname === ELEVENLABS_SOUND_GENERATION_PATH && req.method === "POST") {
2930
+ if (pathname === require_route_registry.ELEVENLABS_SOUND_GENERATION_PATH && req.method === "POST") {
2092
2931
  setCorsHeaders(res);
2093
2932
  try {
2094
- await require_elevenlabs_audio.handleElevenLabsAudio(req, res, await require_helpers.readBody(req), fixtures, defaults, journal, "sound-generation");
2933
+ const raw = await require_helpers.readBody(req);
2934
+ ensureRawFixturePositions();
2935
+ await require_elevenlabs_audio.handleElevenLabsAudio(req, res, raw, fixtures, defaults, journal, "sound-generation");
2095
2936
  } catch (err) {
2096
2937
  routeError(req, res, err, pathname);
2097
2938
  }
2098
2939
  return;
2099
2940
  }
2100
- if (pathname === ELEVENLABS_VOICE_DESIGN_PATH && req.method === "POST") {
2941
+ if (pathname === require_route_registry.ELEVENLABS_VOICE_DESIGN_PATH && req.method === "POST") {
2101
2942
  setCorsHeaders(res);
2102
2943
  try {
2103
- await require_elevenlabs_voice.handleElevenLabsVoiceDesign(req, res, await require_helpers.readBody(req), fixtures, defaults, journal);
2944
+ const raw = await require_helpers.readBody(req);
2945
+ ensureRawFixturePositions();
2946
+ await require_elevenlabs_voice.handleElevenLabsVoiceDesign(req, res, raw, fixtures, defaults, journal);
2104
2947
  } catch (err) {
2105
2948
  routeError(req, res, err, pathname, { service: "elevenlabs-voice" });
2106
2949
  }
2107
2950
  return;
2108
2951
  }
2109
- if (pathname === ELEVENLABS_VOICE_CREATE_PATH && req.method === "POST") {
2952
+ if (pathname === require_route_registry.ELEVENLABS_VOICE_CREATE_PATH && req.method === "POST") {
2110
2953
  setCorsHeaders(res);
2111
2954
  try {
2112
- await require_elevenlabs_voice.handleElevenLabsVoiceCreate(req, res, await require_helpers.readBody(req), fixtures, defaults, journal);
2955
+ const raw = await require_helpers.readBody(req);
2956
+ ensureRawFixturePositions();
2957
+ await require_elevenlabs_voice.handleElevenLabsVoiceCreate(req, res, raw, fixtures, defaults, journal);
2113
2958
  } catch (err) {
2114
2959
  routeError(req, res, err, pathname, { service: "elevenlabs-voice" });
2115
2960
  }
2116
2961
  return;
2117
2962
  }
2118
- const elevenLabsVoiceMatch = pathname.match(ELEVENLABS_VOICE_RE);
2963
+ const elevenLabsVoiceMatch = pathname.match(require_route_registry.ELEVENLABS_VOICE_RE);
2119
2964
  if (elevenLabsVoiceMatch && (req.method === "GET" || req.method === "DELETE")) {
2120
2965
  setCorsHeaders(res);
2121
2966
  let voiceId;
@@ -2140,37 +2985,46 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
2140
2985
  return;
2141
2986
  }
2142
2987
  try {
2143
- if (req.method === "GET") await require_elevenlabs_voice.handleElevenLabsVoiceGet(req, res, voiceId, fixtures, defaults, journal);
2144
- else await require_elevenlabs_voice.handleElevenLabsVoiceDelete(req, res, voiceId, fixtures, defaults, journal);
2988
+ if (req.method === "GET") {
2989
+ ensureRawFixturePositions();
2990
+ await require_elevenlabs_voice.handleElevenLabsVoiceGet(req, res, voiceId, fixtures, defaults, journal);
2991
+ } else {
2992
+ ensureRawFixturePositions();
2993
+ await require_elevenlabs_voice.handleElevenLabsVoiceDelete(req, res, voiceId, fixtures, defaults, journal);
2994
+ }
2145
2995
  } catch (err) {
2146
2996
  routeError(req, res, err, pathname, { service: "elevenlabs-voice" });
2147
2997
  }
2148
2998
  return;
2149
2999
  }
2150
- const elevenLabsTTSMatch = pathname.match(ELEVENLABS_TTS_RE);
3000
+ const elevenLabsTTSMatch = pathname.match(require_route_registry.ELEVENLABS_TTS_RE);
2151
3001
  if (elevenLabsTTSMatch && req.method === "POST") {
2152
3002
  setCorsHeaders(res);
2153
3003
  const voiceId = elevenLabsTTSMatch[1];
2154
3004
  try {
2155
- await require_elevenlabs_audio.handleElevenLabsTTS(req, res, await require_helpers.readBody(req), fixtures, defaults, journal, voiceId);
3005
+ const raw = await require_helpers.readBody(req);
3006
+ ensureRawFixturePositions();
3007
+ await require_elevenlabs_audio.handleElevenLabsTTS(req, res, raw, fixtures, defaults, journal, voiceId);
2156
3008
  } catch (err) {
2157
3009
  routeError(req, res, err, pathname);
2158
3010
  }
2159
3011
  return;
2160
3012
  }
2161
- const musicMatch = pathname.match(ELEVENLABS_MUSIC_RE);
3013
+ const musicMatch = pathname.match(require_route_registry.ELEVENLABS_MUSIC_RE);
2162
3014
  if (musicMatch && req.method === "POST") {
2163
3015
  setCorsHeaders(res);
2164
3016
  const musicSubType = musicMatch[1] ?? "music";
2165
3017
  try {
2166
- await require_elevenlabs_audio.handleElevenLabsAudio(req, res, await require_helpers.readBody(req), fixtures, defaults, journal, musicSubType);
3018
+ const raw = await require_helpers.readBody(req);
3019
+ ensureRawFixturePositions();
3020
+ await require_elevenlabs_audio.handleElevenLabsAudio(req, res, raw, fixtures, defaults, journal, musicSubType);
2167
3021
  } catch (err) {
2168
3022
  routeError(req, res, err, pathname);
2169
3023
  }
2170
3024
  return;
2171
3025
  }
2172
3026
  let falBody;
2173
- if (require_metrics.FAL_ROUTE_RE.test(pathname) && req.headers["x-fal-target-host"]) {
3027
+ if (require_route_registry.FAL_ROUTE_RE.test(pathname) && req.headers["x-fal-target-host"]) {
2174
3028
  setCorsHeaders(res);
2175
3029
  try {
2176
3030
  falBody = req.method === "POST" || req.method === "PUT" ? await require_helpers.readBody(req) : "";
@@ -2194,22 +3048,25 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
2194
3048
  return;
2195
3049
  }
2196
3050
  }
3051
+ ensureRawFixturePositions();
2197
3052
  if (await require_fal.handleFal(req, res, raw, pathname, fixtures, defaults, journal) === "handled") return;
2198
3053
  } catch (err) {
2199
3054
  routeError(req, res, err, pathname);
2200
3055
  return;
2201
3056
  }
2202
3057
  }
2203
- if (pathname.match(FAL_QUEUE_SUBMIT_RE) && req.method === "POST") {
3058
+ if (pathname.match(require_route_registry.FAL_QUEUE_SUBMIT_RE) && req.method === "POST") {
2204
3059
  setCorsHeaders(res);
2205
3060
  try {
2206
- await require_fal_audio.handleFalQueue(req, res, falBody ?? await require_helpers.readBody(req), pathname, fixtures, defaults, journal);
3061
+ const raw = falBody ?? await require_helpers.readBody(req);
3062
+ ensureRawFixturePositions();
3063
+ await require_fal_audio.handleFalQueue(req, res, raw, pathname, fixtures, defaults, journal);
2207
3064
  } catch (err) {
2208
3065
  routeError(req, res, err, pathname);
2209
3066
  }
2210
3067
  return;
2211
3068
  }
2212
- if (pathname.match(FAL_QUEUE_REQUESTS_RE) && (req.method === "GET" || req.method === "POST" || req.method === "PUT")) {
3069
+ if (pathname.match(require_route_registry.FAL_QUEUE_REQUESTS_RE) && (req.method === "GET" || req.method === "POST" || req.method === "PUT")) {
2213
3070
  setCorsHeaders(res);
2214
3071
  try {
2215
3072
  const raw = req.method === "POST" || req.method === "PUT" ? falBody ?? await require_helpers.readBody(req) : "{}";
@@ -2230,22 +3087,27 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
2230
3087
  }, "internal", defaults.registry, defaults.logger);
2231
3088
  return;
2232
3089
  }
3090
+ ensureRawFixturePositions();
2233
3091
  await require_fal_audio.handleFalQueue(req, res, raw, pathname, fixtures, defaults, journal);
2234
3092
  } catch (err) {
2235
3093
  routeError(req, res, err, pathname);
2236
3094
  }
2237
3095
  return;
2238
3096
  }
2239
- if (pathname.match(FAL_RUN_RE) && req.method === "POST") {
3097
+ if (pathname.match(require_route_registry.FAL_RUN_RE) && req.method === "POST") {
2240
3098
  setCorsHeaders(res);
2241
3099
  try {
2242
- await require_fal_audio.handleFalQueue(req, res, falBody ?? await require_helpers.readBody(req), pathname, fixtures, defaults, journal);
3100
+ const raw = falBody ?? await require_helpers.readBody(req);
3101
+ ensureRawFixturePositions();
3102
+ await require_fal_audio.handleFalQueue(req, res, raw, pathname, fixtures, defaults, journal);
2243
3103
  } catch (err) {
2244
3104
  routeError(req, res, err, pathname);
2245
3105
  }
2246
3106
  return;
2247
3107
  }
2248
- if (pathname !== COMPLETIONS_PATH) {
3108
+ if (pathname !== require_route_registry.COMPLETIONS_PATH) {
3109
+ const catalogMatch = require_route_registry.matchRouteDefinition(req.method ?? "", pathname);
3110
+ if (catalogMatch && !(pathname === require_route_registry.METRICS_PATH && !registry)) defaults.logger.warn(`Route drift: ${req.method ?? "?"} ${pathname} matches the route catalog (${catalogMatch.method} ${catalogMatch.path} — ${catalogMatch.description}) but no dispatcher branch served it. The catalog entry or the dispatcher is stale — see route-registry.ts.`);
2249
3111
  handleNotFound(res, "Not found");
2250
3112
  return;
2251
3113
  }
@@ -2255,13 +3117,14 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
2255
3117
  }
2256
3118
  const completionsProvider = azureDeploymentId ? "azure" : isOpenRouter ? "openrouter" : isBytePlusArk ? "byteplus" : "openai";
2257
3119
  try {
2258
- await handleCompletions(req, res, fixtures, journal, defaults, azureDeploymentId, completionsProvider, isOpenRouter);
3120
+ await handleCompletions(req, res, fixtures, journal, defaults, () => lastJournalEntryFor(req), azureDeploymentId, completionsProvider, isOpenRouter, ensureRawFixturePositions, originalPathname.startsWith("/api/v3/"));
2259
3121
  } catch (err) {
2260
3122
  routeError(req, res, err, pathname, {
2261
3123
  envelope: (m, status) => isOpenRouter ? require_openrouter_chat.serializeOpenRouterError(status, m) : JSON.stringify({ error: {
2262
3124
  message: m,
2263
3125
  type: errorTypeForStatus(status)
2264
3126
  } }),
3127
+ ...isOpenRouter ? { toolCallEnvelope: (m, code) => require_openrouter_chat.serializeOpenRouterError(500, m, { reason: code }) } : {},
2265
3128
  streamEvent: (m, status) => `data: ${isOpenRouter ? require_openrouter_chat.serializeOpenRouterError(status, m) : JSON.stringify({ error: {
2266
3129
  message: m,
2267
3130
  type: errorTypeForStatus(status)
@@ -2325,26 +3188,51 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
2325
3188
  server.emit("connection", socket);
2326
3189
  return;
2327
3190
  }
2328
- const parsedUrl = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
3191
+ let parsedUrl;
3192
+ try {
3193
+ parsedUrl = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
3194
+ } catch (err) {
3195
+ const msg = err instanceof Error ? err.message : "Internal error";
3196
+ defaults.logger.warn(`Unhandled upgrade error: ${msg}`);
3197
+ socket.end("HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n");
3198
+ return;
3199
+ }
2329
3200
  let pathname = parsedUrl.pathname;
2330
3201
  if (!require_api_key_auth.validateRequestApiKey(req, resolvedAuth.policy).ok) {
2331
3202
  require_api_key_auth.writeApiKeyUpgradeRejection(socket);
2332
3203
  return;
2333
3204
  }
2334
- if (mounts) {
2335
- for (const { path: mountPath, handler } of mounts) if ((pathname === mountPath || pathname.startsWith(mountPath + "/")) && handler.handleUpgrade) {
2336
- const subPath = pathname.slice(mountPath.length) || "/";
2337
- if (await handler.handleUpgrade(socket, head, subPath)) return;
2338
- }
3205
+ for (const { path: mountPath, handler } of mountList) if ((pathname === mountPath || pathname.startsWith(mountPath + "/")) && handler.handleUpgrade) {
3206
+ const subPath = pathname.slice(mountPath.length) || "/";
3207
+ if (await handler.handleUpgrade(socket, head, subPath)) return;
2339
3208
  }
2340
- if (!pathname.match(AZURE_DEPLOYMENT_RE)) pathname = normalizeCompatPath(pathname, logger);
2341
- if (pathname !== RESPONSES_PATH && pathname !== REALTIME_PATH && pathname !== GEMINI_LIVE_PATH && pathname !== LIVE_PATH) {
3209
+ if (!pathname.match(require_route_registry.AZURE_DEPLOYMENT_RE)) pathname = normalizeCompatPath(pathname, logger);
3210
+ if (pathname !== require_route_registry.RESPONSES_PATH && pathname !== require_route_registry.REALTIME_PATH && pathname !== require_route_registry.GEMINI_LIVE_PATH && pathname !== require_route_registry.LIVE_PATH) {
2342
3211
  socket.write("HTTP/1.1 404 Not Found\r\n\r\n");
2343
3212
  socket.destroy();
2344
3213
  return;
2345
3214
  }
3215
+ if (defaults.misbehavior && pathname !== require_route_registry.LIVE_PATH && req.headers["x-aimock-misbehavior"] !== void 0) {
3216
+ const code = "aimock_misbehavior_invalid";
3217
+ const message = "use the runtime scope: POST /__aimock/misbehavior with X-Test-Id";
3218
+ const body = JSON.stringify({ error: pathname === require_route_registry.GEMINI_LIVE_PATH ? {
3219
+ code: 400,
3220
+ status: "INVALID_ARGUMENT",
3221
+ message: `${code}: ${message}`
3222
+ } : {
3223
+ type: "invalid_request_error",
3224
+ code,
3225
+ message
3226
+ } });
3227
+ socket.end(`HTTP/1.1 400 Bad Request\r
3228
+ Content-Type: application/json\r
3229
+ Content-Length: ${Buffer.byteLength(body)}\r\nConnection: close\r
3230
+ \r
3231
+ ` + body);
3232
+ return;
3233
+ }
2346
3234
  let liveId;
2347
- if (pathname === LIVE_PATH) {
3235
+ if (pathname === require_route_registry.LIVE_PATH) {
2348
3236
  if (req.method !== "GET" || parsedUrl.searchParams.has("model")) {
2349
3237
  socket.end("HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n");
2350
3238
  return;
@@ -2366,7 +3254,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
2366
3254
  if (head.length > 0) socket.unshift(head);
2367
3255
  let ws;
2368
3256
  try {
2369
- ws = require_ws_framing.upgradeToWebSocket(req, socket, pathname === LIVE_PATH ? liveLimits : void 0);
3257
+ ws = require_ws_framing.upgradeToWebSocket(req, socket, pathname === require_route_registry.LIVE_PATH ? liveLimits : void 0);
2370
3258
  } catch (err) {
2371
3259
  const msg = err instanceof Error ? err.message : "WebSocket upgrade failed";
2372
3260
  if (liveId !== void 0) liveSessions.delete(liveId);
@@ -2383,7 +3271,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
2383
3271
  activeConnections.delete(ws);
2384
3272
  });
2385
3273
  const wsTestId = require_helpers.getTestId(req);
2386
- if (pathname === LIVE_PATH && liveId !== void 0) {
3274
+ if (pathname === require_route_registry.LIVE_PATH && liveId !== void 0) {
2387
3275
  const sessionId = liveId;
2388
3276
  const dispose = require_ws_live.handleLiveSession(ws, fixtures, journal, {
2389
3277
  defaults,
@@ -2400,13 +3288,14 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
2400
3288
  testId: wsTestId,
2401
3289
  dispose
2402
3290
  });
2403
- } else if (pathname === RESPONSES_PATH) require_ws_responses.handleWebSocketResponses(ws, fixtures, journal, {
3291
+ } else if (pathname === require_route_registry.RESPONSES_PATH) require_ws_responses.handleWebSocketResponses(ws, fixtures, journal, {
2404
3292
  ...defaults,
2405
3293
  model: "gpt-4",
2406
3294
  testId: wsTestId,
2407
- upgradeHeaders: req.headers
3295
+ upgradeHeaders: req.headers,
3296
+ beforeProcessMessage: ensureRawFixturePositions
2408
3297
  });
2409
- else if (pathname === REALTIME_PATH) {
3298
+ else if (pathname === require_route_registry.REALTIME_PATH) {
2410
3299
  const transcriptionIntent = parsedUrl.searchParams.get("intent") === "transcription";
2411
3300
  const model = transcriptionIntent ? "gpt-transcribe" : parsedUrl.searchParams.get("model") ?? "gpt-realtime-2";
2412
3301
  require_ws_realtime.handleWebSocketRealtime(ws, fixtures, journal, {
@@ -2414,13 +3303,15 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
2414
3303
  model,
2415
3304
  transcriptionIntent,
2416
3305
  testId: wsTestId,
2417
- upgradeHeaders: req.headers
3306
+ upgradeHeaders: req.headers,
3307
+ beforeProcessMessage: ensureRawFixturePositions
2418
3308
  });
2419
- } else if (pathname === GEMINI_LIVE_PATH) require_ws_gemini_live.handleWebSocketGeminiLive(ws, fixtures, journal, {
3309
+ } else if (pathname === require_route_registry.GEMINI_LIVE_PATH) require_ws_gemini_live.handleWebSocketGeminiLive(ws, fixtures, journal, {
2420
3310
  ...defaults,
2421
3311
  model: "gemini-2.0-flash",
2422
3312
  testId: wsTestId,
2423
- upgradeHeaders: req.headers
3313
+ upgradeHeaders: req.headers,
3314
+ beforeProcessMessage: ensureRawFixturePositions
2424
3315
  });
2425
3316
  }
2426
3317
  const originalClose = server.close.bind(server);
@@ -2445,9 +3336,13 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
2445
3336
  return;
2446
3337
  }
2447
3338
  const url = `http://${addr.address}:${addr.port}`;
2448
- if (mounts) {
2449
- for (const { path: mountPath, handler } of mounts) if (handler.setBaseUrl) handler.setBaseUrl(url + mountPath);
3339
+ try {
3340
+ commitHandOff();
3341
+ } catch (err) {
3342
+ server.close(() => reject(err));
3343
+ return;
2450
3344
  }
3345
+ for (const { path: mountPath, handler } of mountList) if (handler.setBaseUrl) handler.setBaseUrl(url + mountPath);
2451
3346
  resolve({
2452
3347
  closeLiveSessions,
2453
3348
  server,