@copilotkit/aimock 1.45.0 → 1.46.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 (426) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +24 -0
  4. package/README.md +7 -1
  5. package/dist/agui-mock.cjs +25 -25
  6. package/dist/agui-mock.cjs.map +1 -1
  7. package/dist/agui-mock.d.cts.map +1 -1
  8. package/dist/agui-mock.d.ts.map +1 -1
  9. package/dist/agui-mock.js +25 -25
  10. package/dist/agui-mock.js.map +1 -1
  11. package/dist/agui-types.d.ts.map +1 -1
  12. package/dist/aimock-cli.cjs +15 -1
  13. package/dist/aimock-cli.cjs.map +1 -1
  14. package/dist/aimock-cli.d.cts.map +1 -1
  15. package/dist/aimock-cli.d.ts.map +1 -1
  16. package/dist/aimock-cli.js +16 -2
  17. package/dist/aimock-cli.js.map +1 -1
  18. package/dist/api-key-auth.cjs +10 -9
  19. package/dist/api-key-auth.cjs.map +1 -1
  20. package/dist/api-key-auth.d.cts.map +1 -1
  21. package/dist/api-key-auth.d.ts.map +1 -1
  22. package/dist/api-key-auth.js +11 -10
  23. package/dist/api-key-auth.js.map +1 -1
  24. package/dist/batches.cjs +2 -4
  25. package/dist/batches.cjs.map +1 -1
  26. package/dist/batches.d.cts.map +1 -1
  27. package/dist/batches.d.ts.map +1 -1
  28. package/dist/batches.js +2 -4
  29. package/dist/batches.js.map +1 -1
  30. package/dist/bedrock-converse.cjs +61 -80
  31. package/dist/bedrock-converse.cjs.map +1 -1
  32. package/dist/bedrock-converse.d.cts.map +1 -1
  33. package/dist/bedrock-converse.d.ts.map +1 -1
  34. package/dist/bedrock-converse.js +58 -77
  35. package/dist/bedrock-converse.js.map +1 -1
  36. package/dist/bedrock.cjs +65 -97
  37. package/dist/bedrock.cjs.map +1 -1
  38. package/dist/bedrock.d.cts.map +1 -1
  39. package/dist/bedrock.d.ts.map +1 -1
  40. package/dist/bedrock.js +62 -94
  41. package/dist/bedrock.js.map +1 -1
  42. package/dist/byteplus-video.cjs +11 -10
  43. package/dist/byteplus-video.cjs.map +1 -1
  44. package/dist/byteplus-video.d.cts.map +1 -1
  45. package/dist/byteplus-video.d.ts.map +1 -1
  46. package/dist/byteplus-video.js +5 -4
  47. package/dist/byteplus-video.js.map +1 -1
  48. package/dist/chaos.cjs +5 -4
  49. package/dist/chaos.cjs.map +1 -1
  50. package/dist/chaos.d.cts.map +1 -1
  51. package/dist/chaos.d.ts.map +1 -1
  52. package/dist/chaos.js +5 -4
  53. package/dist/chaos.js.map +1 -1
  54. package/dist/cli.cjs +15 -0
  55. package/dist/cli.cjs.map +1 -1
  56. package/dist/cli.js +15 -0
  57. package/dist/cli.js.map +1 -1
  58. package/dist/cohere.cjs +49 -74
  59. package/dist/cohere.cjs.map +1 -1
  60. package/dist/cohere.d.cts.map +1 -1
  61. package/dist/cohere.d.ts.map +1 -1
  62. package/dist/cohere.js +47 -72
  63. package/dist/cohere.js.map +1 -1
  64. package/dist/config-loader.cjs +29 -1
  65. package/dist/config-loader.cjs.map +1 -1
  66. package/dist/config-loader.d.cts +7 -1
  67. package/dist/config-loader.d.cts.map +1 -1
  68. package/dist/config-loader.d.ts +7 -1
  69. package/dist/config-loader.d.ts.map +1 -1
  70. package/dist/config-loader.js +29 -2
  71. package/dist/config-loader.js.map +1 -1
  72. package/dist/count-tokens.cjs +146 -0
  73. package/dist/count-tokens.cjs.map +1 -0
  74. package/dist/count-tokens.js +146 -0
  75. package/dist/count-tokens.js.map +1 -0
  76. package/dist/elevenlabs-audio.cjs +36 -34
  77. package/dist/elevenlabs-audio.cjs.map +1 -1
  78. package/dist/elevenlabs-audio.d.cts.map +1 -1
  79. package/dist/elevenlabs-audio.d.ts.map +1 -1
  80. package/dist/elevenlabs-audio.js +33 -31
  81. package/dist/elevenlabs-audio.js.map +1 -1
  82. package/dist/elevenlabs-voice.cjs +38 -37
  83. package/dist/elevenlabs-voice.cjs.map +1 -1
  84. package/dist/elevenlabs-voice.d.cts.map +1 -1
  85. package/dist/elevenlabs-voice.d.ts.map +1 -1
  86. package/dist/elevenlabs-voice.js +33 -32
  87. package/dist/elevenlabs-voice.js.map +1 -1
  88. package/dist/embedding-request.cjs +16 -0
  89. package/dist/embedding-request.cjs.map +1 -0
  90. package/dist/embedding-request.js +14 -0
  91. package/dist/embedding-request.js.map +1 -0
  92. package/dist/embeddings.cjs +30 -20
  93. package/dist/embeddings.cjs.map +1 -1
  94. package/dist/embeddings.d.cts.map +1 -1
  95. package/dist/embeddings.d.ts.map +1 -1
  96. package/dist/embeddings.js +30 -20
  97. package/dist/embeddings.js.map +1 -1
  98. package/dist/fal-audio.cjs +45 -43
  99. package/dist/fal-audio.cjs.map +1 -1
  100. package/dist/fal-audio.d.cts.map +1 -1
  101. package/dist/fal-audio.d.ts.map +1 -1
  102. package/dist/fal-audio.js +42 -40
  103. package/dist/fal-audio.js.map +1 -1
  104. package/dist/fal.cjs +17 -15
  105. package/dist/fal.cjs.map +1 -1
  106. package/dist/fal.js +16 -14
  107. package/dist/fal.js.map +1 -1
  108. package/dist/files.cjs +2 -4
  109. package/dist/files.cjs.map +1 -1
  110. package/dist/files.d.cts.map +1 -1
  111. package/dist/files.d.ts.map +1 -1
  112. package/dist/files.js +2 -4
  113. package/dist/files.js.map +1 -1
  114. package/dist/fine-tuning.cjs +2 -4
  115. package/dist/fine-tuning.cjs.map +1 -1
  116. package/dist/fine-tuning.d.cts.map +1 -1
  117. package/dist/fine-tuning.d.ts.map +1 -1
  118. package/dist/fine-tuning.js +2 -4
  119. package/dist/fine-tuning.js.map +1 -1
  120. package/dist/fixture-loader.cjs +37 -42
  121. package/dist/fixture-loader.cjs.map +1 -1
  122. package/dist/fixture-loader.d.cts.map +1 -1
  123. package/dist/fixture-loader.d.ts.map +1 -1
  124. package/dist/fixture-loader.js +37 -42
  125. package/dist/fixture-loader.js.map +1 -1
  126. package/dist/gemini-embeddings.cjs +26 -24
  127. package/dist/gemini-embeddings.cjs.map +1 -1
  128. package/dist/gemini-embeddings.js +26 -24
  129. package/dist/gemini-embeddings.js.map +1 -1
  130. package/dist/gemini-interactions.cjs +50 -35
  131. package/dist/gemini-interactions.cjs.map +1 -1
  132. package/dist/gemini-interactions.d.cts +0 -1
  133. package/dist/gemini-interactions.d.cts.map +1 -1
  134. package/dist/gemini-interactions.d.ts +0 -1
  135. package/dist/gemini-interactions.d.ts.map +1 -1
  136. package/dist/gemini-interactions.js +49 -34
  137. package/dist/gemini-interactions.js.map +1 -1
  138. package/dist/gemini.cjs +57 -67
  139. package/dist/gemini.cjs.map +1 -1
  140. package/dist/gemini.d.cts.map +1 -1
  141. package/dist/gemini.d.ts.map +1 -1
  142. package/dist/gemini.js +56 -67
  143. package/dist/gemini.js.map +1 -1
  144. package/dist/grok-video.cjs +14 -12
  145. package/dist/grok-video.cjs.map +1 -1
  146. package/dist/grok-video.d.cts.map +1 -1
  147. package/dist/grok-video.d.ts.map +1 -1
  148. package/dist/grok-video.js +8 -6
  149. package/dist/grok-video.js.map +1 -1
  150. package/dist/helpers.cjs +11 -68
  151. package/dist/helpers.cjs.map +1 -1
  152. package/dist/helpers.d.cts.map +1 -1
  153. package/dist/helpers.d.ts.map +1 -1
  154. package/dist/helpers.js +12 -67
  155. package/dist/helpers.js.map +1 -1
  156. package/dist/images.cjs +30 -28
  157. package/dist/images.cjs.map +1 -1
  158. package/dist/images.d.cts.map +1 -1
  159. package/dist/images.d.ts.map +1 -1
  160. package/dist/images.js +27 -25
  161. package/dist/images.js.map +1 -1
  162. package/dist/index.d.cts +2 -2
  163. package/dist/index.d.ts +2 -2
  164. package/dist/journal.cjs +3 -1
  165. package/dist/journal.cjs.map +1 -1
  166. package/dist/journal.d.cts.map +1 -1
  167. package/dist/journal.d.ts.map +1 -1
  168. package/dist/journal.js +2 -1
  169. package/dist/journal.js.map +1 -1
  170. package/dist/llmock.cjs +3 -0
  171. package/dist/llmock.cjs.map +1 -1
  172. package/dist/llmock.d.cts.map +1 -1
  173. package/dist/llmock.d.ts.map +1 -1
  174. package/dist/llmock.js +3 -0
  175. package/dist/llmock.js.map +1 -1
  176. package/dist/mcp-fakes.d.cts.map +1 -1
  177. package/dist/mcp-handler.cjs +14 -4
  178. package/dist/mcp-handler.cjs.map +1 -1
  179. package/dist/mcp-handler.js +14 -4
  180. package/dist/mcp-handler.js.map +1 -1
  181. package/dist/mcp-recorder.cjs +2 -1
  182. package/dist/mcp-recorder.cjs.map +1 -1
  183. package/dist/mcp-recorder.js +3 -2
  184. package/dist/mcp-recorder.js.map +1 -1
  185. package/dist/messages.cjs +111 -96
  186. package/dist/messages.cjs.map +1 -1
  187. package/dist/messages.d.cts.map +1 -1
  188. package/dist/messages.d.ts.map +1 -1
  189. package/dist/messages.js +109 -95
  190. package/dist/messages.js.map +1 -1
  191. package/dist/metrics.cjs +5 -2
  192. package/dist/metrics.cjs.map +1 -1
  193. package/dist/metrics.d.cts.map +1 -1
  194. package/dist/metrics.d.ts.map +1 -1
  195. package/dist/metrics.js +6 -3
  196. package/dist/metrics.js.map +1 -1
  197. package/dist/model-utils.cjs +1 -0
  198. package/dist/model-utils.cjs.map +1 -1
  199. package/dist/model-utils.js +1 -1
  200. package/dist/model-utils.js.map +1 -1
  201. package/dist/moderation.cjs +15 -12
  202. package/dist/moderation.cjs.map +1 -1
  203. package/dist/moderation.js +14 -11
  204. package/dist/moderation.js.map +1 -1
  205. package/dist/ollama.cjs +128 -68
  206. package/dist/ollama.cjs.map +1 -1
  207. package/dist/ollama.d.cts.map +1 -1
  208. package/dist/ollama.d.ts.map +1 -1
  209. package/dist/ollama.js +124 -64
  210. package/dist/ollama.js.map +1 -1
  211. package/dist/openapi.cjs +323 -3
  212. package/dist/openapi.cjs.map +1 -1
  213. package/dist/openapi.d.cts.map +1 -1
  214. package/dist/openapi.d.ts.map +1 -1
  215. package/dist/openapi.js +324 -4
  216. package/dist/openapi.js.map +1 -1
  217. package/dist/openrouter-chat.cjs +11 -155
  218. package/dist/openrouter-chat.cjs.map +1 -1
  219. package/dist/openrouter-chat.js +11 -155
  220. package/dist/openrouter-chat.js.map +1 -1
  221. package/dist/openrouter-video.cjs +76 -71
  222. package/dist/openrouter-video.cjs.map +1 -1
  223. package/dist/openrouter-video.d.cts.map +1 -1
  224. package/dist/openrouter-video.d.ts.map +1 -1
  225. package/dist/openrouter-video.js +63 -58
  226. package/dist/openrouter-video.js.map +1 -1
  227. package/dist/recorder.cjs +176 -95
  228. package/dist/recorder.cjs.map +1 -1
  229. package/dist/recorder.d.cts.map +1 -1
  230. package/dist/recorder.d.ts.map +1 -1
  231. package/dist/recorder.js +176 -95
  232. package/dist/recorder.js.map +1 -1
  233. package/dist/rerank.cjs +13 -11
  234. package/dist/rerank.cjs.map +1 -1
  235. package/dist/rerank.js +12 -10
  236. package/dist/rerank.js.map +1 -1
  237. package/dist/response/catalog/anthropic-page.cjs +39 -0
  238. package/dist/response/catalog/anthropic-page.cjs.map +1 -0
  239. package/dist/response/catalog/anthropic-page.js +38 -0
  240. package/dist/response/catalog/anthropic-page.js.map +1 -0
  241. package/dist/response/catalog/collect.cjs +61 -0
  242. package/dist/response/catalog/collect.cjs.map +1 -0
  243. package/dist/response/catalog/collect.js +59 -0
  244. package/dist/response/catalog/collect.js.map +1 -0
  245. package/dist/response/catalog/gemini-page.cjs +25 -0
  246. package/dist/response/catalog/gemini-page.cjs.map +1 -0
  247. package/dist/response/catalog/gemini-page.js +24 -0
  248. package/dist/response/catalog/gemini-page.js.map +1 -0
  249. package/dist/response/catalog/render.cjs +182 -0
  250. package/dist/response/catalog/render.cjs.map +1 -0
  251. package/dist/response/catalog/render.js +171 -0
  252. package/dist/response/catalog/render.js.map +1 -0
  253. package/dist/response/errors.cjs +225 -0
  254. package/dist/response/errors.cjs.map +1 -0
  255. package/dist/response/errors.js +224 -0
  256. package/dist/response/errors.js.map +1 -0
  257. package/dist/response/finish.cjs +39 -0
  258. package/dist/response/finish.cjs.map +1 -0
  259. package/dist/response/finish.js +35 -0
  260. package/dist/response/finish.js.map +1 -0
  261. package/dist/response/policy.cjs +126 -0
  262. package/dist/response/policy.cjs.map +1 -0
  263. package/dist/response/policy.js +120 -0
  264. package/dist/response/policy.js.map +1 -0
  265. package/dist/response/profiles.cjs +69 -0
  266. package/dist/response/profiles.cjs.map +1 -0
  267. package/dist/response/profiles.js +65 -0
  268. package/dist/response/profiles.js.map +1 -0
  269. package/dist/response/usage/codecs/anthropic.cjs +52 -0
  270. package/dist/response/usage/codecs/anthropic.cjs.map +1 -0
  271. package/dist/response/usage/codecs/anthropic.js +50 -0
  272. package/dist/response/usage/codecs/anthropic.js.map +1 -0
  273. package/dist/response/usage/codecs/cohere.cjs +36 -0
  274. package/dist/response/usage/codecs/cohere.cjs.map +1 -0
  275. package/dist/response/usage/codecs/cohere.js +35 -0
  276. package/dist/response/usage/codecs/cohere.js.map +1 -0
  277. package/dist/response/usage/codecs/converse.cjs +16 -0
  278. package/dist/response/usage/codecs/converse.cjs.map +1 -0
  279. package/dist/response/usage/codecs/converse.js +15 -0
  280. package/dist/response/usage/codecs/converse.js.map +1 -0
  281. package/dist/response/usage/codecs/gemini.cjs +31 -0
  282. package/dist/response/usage/codecs/gemini.cjs.map +1 -0
  283. package/dist/response/usage/codecs/gemini.js +31 -0
  284. package/dist/response/usage/codecs/gemini.js.map +1 -0
  285. package/dist/response/usage/codecs/interactions.cjs +22 -0
  286. package/dist/response/usage/codecs/interactions.cjs.map +1 -0
  287. package/dist/response/usage/codecs/interactions.js +21 -0
  288. package/dist/response/usage/codecs/interactions.js.map +1 -0
  289. package/dist/response/usage/codecs/ollama.cjs +17 -0
  290. package/dist/response/usage/codecs/ollama.cjs.map +1 -0
  291. package/dist/response/usage/codecs/ollama.js +17 -0
  292. package/dist/response/usage/codecs/ollama.js.map +1 -0
  293. package/dist/response/usage/codecs/openai.cjs +52 -0
  294. package/dist/response/usage/codecs/openai.cjs.map +1 -0
  295. package/dist/response/usage/codecs/openai.js +50 -0
  296. package/dist/response/usage/codecs/openai.js.map +1 -0
  297. package/dist/response/usage/codecs/openrouter.cjs +68 -0
  298. package/dist/response/usage/codecs/openrouter.cjs.map +1 -0
  299. package/dist/response/usage/codecs/openrouter.js +67 -0
  300. package/dist/response/usage/codecs/openrouter.js.map +1 -0
  301. package/dist/response/usage/codecs/realtime.cjs +19 -0
  302. package/dist/response/usage/codecs/realtime.cjs.map +1 -0
  303. package/dist/response/usage/codecs/realtime.js +18 -0
  304. package/dist/response/usage/codecs/realtime.js.map +1 -0
  305. package/dist/response/usage/codecs/responses.cjs +21 -0
  306. package/dist/response/usage/codecs/responses.cjs.map +1 -0
  307. package/dist/response/usage/codecs/responses.js +20 -0
  308. package/dist/response/usage/codecs/responses.js.map +1 -0
  309. package/dist/response/usage/estimate.cjs +23 -0
  310. package/dist/response/usage/estimate.cjs.map +1 -0
  311. package/dist/response/usage/estimate.js +21 -0
  312. package/dist/response/usage/estimate.js.map +1 -0
  313. package/dist/response/usage/fields.cjs +72 -0
  314. package/dist/response/usage/fields.cjs.map +1 -0
  315. package/dist/response/usage/fields.js +70 -0
  316. package/dist/response/usage/fields.js.map +1 -0
  317. package/dist/response/usage/recording.cjs +52 -0
  318. package/dist/response/usage/recording.cjs.map +1 -0
  319. package/dist/response/usage/recording.js +52 -0
  320. package/dist/response/usage/recording.js.map +1 -0
  321. package/dist/responses.cjs +45 -58
  322. package/dist/responses.cjs.map +1 -1
  323. package/dist/responses.d.cts.map +1 -1
  324. package/dist/responses.d.ts.map +1 -1
  325. package/dist/responses.js +44 -57
  326. package/dist/responses.js.map +1 -1
  327. package/dist/route-registry.cjs +45 -0
  328. package/dist/route-registry.cjs.map +1 -1
  329. package/dist/route-registry.d.cts.map +1 -1
  330. package/dist/route-registry.d.ts.map +1 -1
  331. package/dist/route-registry.js +41 -1
  332. package/dist/route-registry.js.map +1 -1
  333. package/dist/router.cjs +4 -0
  334. package/dist/router.cjs.map +1 -1
  335. package/dist/router.d.cts.map +1 -1
  336. package/dist/router.d.ts.map +1 -1
  337. package/dist/router.js +3 -0
  338. package/dist/router.js.map +1 -1
  339. package/dist/search.cjs +13 -11
  340. package/dist/search.cjs.map +1 -1
  341. package/dist/search.js +12 -10
  342. package/dist/search.js.map +1 -1
  343. package/dist/server.cjs +222 -146
  344. package/dist/server.cjs.map +1 -1
  345. package/dist/server.d.cts.map +1 -1
  346. package/dist/server.d.ts.map +1 -1
  347. package/dist/server.js +223 -147
  348. package/dist/server.js.map +1 -1
  349. package/dist/speech.cjs +20 -18
  350. package/dist/speech.cjs.map +1 -1
  351. package/dist/speech.d.cts.map +1 -1
  352. package/dist/speech.d.ts.map +1 -1
  353. package/dist/speech.js +19 -17
  354. package/dist/speech.js.map +1 -1
  355. package/dist/sse-writer.cjs +7 -0
  356. package/dist/sse-writer.cjs.map +1 -1
  357. package/dist/sse-writer.d.cts.map +1 -1
  358. package/dist/sse-writer.d.ts.map +1 -1
  359. package/dist/sse-writer.js +7 -1
  360. package/dist/sse-writer.js.map +1 -1
  361. package/dist/stream-collapse.cjs +118 -11
  362. package/dist/stream-collapse.cjs.map +1 -1
  363. package/dist/stream-collapse.d.cts +10 -9
  364. package/dist/stream-collapse.d.cts.map +1 -1
  365. package/dist/stream-collapse.d.ts +10 -9
  366. package/dist/stream-collapse.d.ts.map +1 -1
  367. package/dist/stream-collapse.js +118 -11
  368. package/dist/stream-collapse.js.map +1 -1
  369. package/dist/transcription.cjs +12 -10
  370. package/dist/transcription.cjs.map +1 -1
  371. package/dist/transcription.d.cts.map +1 -1
  372. package/dist/transcription.d.ts.map +1 -1
  373. package/dist/transcription.js +11 -9
  374. package/dist/transcription.js.map +1 -1
  375. package/dist/types.cjs.map +1 -1
  376. package/dist/types.d.cts +62 -3
  377. package/dist/types.d.cts.map +1 -1
  378. package/dist/types.d.ts +62 -3
  379. package/dist/types.d.ts.map +1 -1
  380. package/dist/types.js.map +1 -1
  381. package/dist/vector-mock.cjs +3 -8
  382. package/dist/vector-mock.cjs.map +1 -1
  383. package/dist/vector-mock.d.cts.map +1 -1
  384. package/dist/vector-mock.d.ts.map +1 -1
  385. package/dist/vector-mock.js +3 -8
  386. package/dist/vector-mock.js.map +1 -1
  387. package/dist/vector-stores.cjs +2 -4
  388. package/dist/vector-stores.cjs.map +1 -1
  389. package/dist/vector-stores.d.cts.map +1 -1
  390. package/dist/vector-stores.d.ts.map +1 -1
  391. package/dist/vector-stores.js +2 -4
  392. package/dist/vector-stores.js.map +1 -1
  393. package/dist/veo-video.cjs +16 -14
  394. package/dist/veo-video.cjs.map +1 -1
  395. package/dist/veo-video.js +10 -8
  396. package/dist/veo-video.js.map +1 -1
  397. package/dist/video.cjs +21 -19
  398. package/dist/video.cjs.map +1 -1
  399. package/dist/video.d.cts.map +1 -1
  400. package/dist/video.d.ts.map +1 -1
  401. package/dist/video.js +20 -18
  402. package/dist/video.js.map +1 -1
  403. package/dist/ws-gemini-live.cjs +11 -3
  404. package/dist/ws-gemini-live.cjs.map +1 -1
  405. package/dist/ws-gemini-live.d.cts +0 -1
  406. package/dist/ws-gemini-live.d.cts.map +1 -1
  407. package/dist/ws-gemini-live.d.ts +0 -1
  408. package/dist/ws-gemini-live.d.ts.map +1 -1
  409. package/dist/ws-gemini-live.js +10 -2
  410. package/dist/ws-gemini-live.js.map +1 -1
  411. package/dist/ws-live.cjs +6 -5
  412. package/dist/ws-live.cjs.map +1 -1
  413. package/dist/ws-live.js +5 -4
  414. package/dist/ws-live.js.map +1 -1
  415. package/dist/ws-realtime.cjs +28 -54
  416. package/dist/ws-realtime.cjs.map +1 -1
  417. package/dist/ws-realtime.d.cts.map +1 -1
  418. package/dist/ws-realtime.d.ts.map +1 -1
  419. package/dist/ws-realtime.js +25 -51
  420. package/dist/ws-realtime.js.map +1 -1
  421. package/dist/ws-responses.cjs +8 -6
  422. package/dist/ws-responses.cjs.map +1 -1
  423. package/dist/ws-responses.js +7 -5
  424. package/dist/ws-responses.js.map +1 -1
  425. package/package.json +4 -1
  426. package/skills/write-fixtures/SKILL.md +25 -16
package/dist/cli.js CHANGED
@@ -11,6 +11,7 @@ import { mcpRecordEnv, parseMcpRecordFlag } from "./mcp-recorder.js";
11
11
  import { MCPMock } from "./mcp-mock.js";
12
12
  import { createServer } from "./server.js";
13
13
  import { loadFixtureFileWithServices, loadFixturesFromDirWithServices } from "./fixture-loader-services.js";
14
+ import { parsePolicyFlags } from "./config-loader.js";
14
15
  import { watchFixtures } from "./watcher.js";
15
16
  import { resolveFixturesValue } from "./fixtures-remote.js";
16
17
  import { createHash } from "node:crypto";
@@ -43,6 +44,9 @@ Options:
43
44
  --strict-tool-arguments Reject fixture tool calls with invalid JSON arguments instead of serving {} (default: false)
44
45
  --responses-tools <mode> OpenAI Responses tool handling: legacy (default) or extended (namespaced and
45
46
  custom tools visible to matching, custom tool rounds counted, namespaces emitted and recorded)
47
+ --policy <key=value> Request policy (repeatable): requiredHeaders=off|enforce (default: off),
48
+ authErrors=legacy|native (default: legacy),
49
+ modelCatalog=legacy|native (default: legacy)
46
50
  --journal-max <n> Max request entries retained in memory (default: 1000, 0 = unbounded)
47
51
  --fixture-counts-max <n> Max unique testIds retained in fixture match-count map (default: 500, 0 = unbounded)
48
52
  --provider-openai <url> Upstream URL for OpenAI (used with --record)
@@ -142,6 +146,10 @@ const { values } = parseArgs({
142
146
  default: false
143
147
  },
144
148
  "responses-tools": { type: "string" },
149
+ policy: {
150
+ type: "string",
151
+ multiple: true
152
+ },
145
153
  "provider-openai": { type: "string" },
146
154
  "provider-anthropic": { type: "string" },
147
155
  "provider-gemini": { type: "string" },
@@ -242,6 +250,12 @@ if (responsesToolsFlag !== void 0 && responsesToolsFlag !== "legacy" && response
242
250
  process.exit(1);
243
251
  }
244
252
  const responsesTools = responsesToolsFlag;
253
+ const parsedPolicy = parsePolicyFlags(values.policy ?? []);
254
+ if (!parsedPolicy.ok) {
255
+ console.error(`${parsedPolicy.error}\n\n${HELP}`);
256
+ process.exit(1);
257
+ }
258
+ const policy = parsedPolicy.policy;
245
259
  const journalMax = Number(values["journal-max"]);
246
260
  if (Number.isNaN(journalMax) || !Number.isInteger(journalMax) || journalMax < 0) {
247
261
  console.error(`Invalid journal-max: ${values["journal-max"]} (must be a non-negative integer; 0 = unbounded)`);
@@ -645,6 +659,7 @@ async function main() {
645
659
  metrics: values.metrics,
646
660
  record,
647
661
  strict: values.strict,
662
+ policy,
648
663
  strictToolArguments: values["strict-tool-arguments"],
649
664
  enableMisbehavior: values.misbehavior,
650
665
  ...responsesTools !== void 0 ? { responsesTools } : {},
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { isDeepStrictEqual, parseArgs } from \"node:util\";\nimport { createHash } from \"node:crypto\";\nimport { readFileSync, statSync, type Stats } from \"node:fs\";\nimport { relative, resolve, sep } from \"node:path\";\nimport { createServer } from \"./server.js\";\nimport type { ResponsesToolsMode } from \"./types.js\";\nimport {\n FixtureLoadError,\n MisbehaviorConfigError,\n enableHeldFixtureMisbehavior,\n markFixtureResponsesToolsExtended,\n validateFixtures,\n} from \"./fixture-loader.js\";\nimport {\n loadFixtureFileWithServices,\n loadFixturesFromDirWithServices,\n type FixturesWithServices,\n} from \"./fixture-loader-services.js\";\nimport { McpFakesAddError } from \"./mcp-fakes.js\";\nimport { build, msg } from \"./message-text.js\";\nimport { Logger, type LogLevel } from \"./logger.js\";\nimport { watchFixtures } from \"./watcher.js\";\nimport { AGUIMock } from \"./agui-mock.js\";\nimport { MCPMock } from \"./mcp-mock.js\";\nimport { mcpRecordEnv, parseMcpRecordFlag } from \"./mcp-recorder.js\";\nimport { parseChaosField, CHAOS_FIELDS, type ChaosField } from \"./chaos.js\";\nimport { resolveFixturesValue } from \"./fixtures-remote.js\";\nimport { readProviderKeysFromEnv } from \"./provider-auth.js\";\nimport { resolveInboundAuth, selectInboundAuthSource } from \"./api-key-auth.js\";\nimport type { Fixture, ChaosConfig, RecordConfig, McpFakeSource, Mountable } from \"./types.js\";\n\nconst HELP = `\nUsage: aimock [options]\n\nOptions:\n -p, --port <number> Port to listen on (default: 4010)\n -h, --host <string> Host to bind to (default: 127.0.0.1)\n -f, --fixtures <value> Fixture source (repeatable). Accepts:\n - filesystem path to a directory or .json file (default: ./fixtures)\n - https:// or http:// URL to a .json fixture file\n -l, --latency <ms> Latency in ms between SSE chunks (default: 0)\n -c, --chunk-size <chars> Chunk size in characters (default: 20)\n -w, --watch Watch fixture path for changes and reload\n --log-level <level> Log verbosity: silent, warn, info, debug (default: info)\n --validate-on-load Validate fixture schemas at startup\n --misbehavior Enable model misbehavior: fixture misbehavior keys and the\n X-AIMock-Misbehavior header (ignored without this flag)\n --metrics Enable Prometheus metrics at GET /metrics\n --record Record mode: proxy unmatched requests and save fixtures\n --record-full-model-version Record exact model version without date stripping (default: false)\n --proxy-only Proxy mode: forward unmatched requests without saving\n --strict Strict mode: fail on unmatched requests (overridable per-request via X-AIMock-Strict header)\n --strict-tool-arguments Reject fixture tool calls with invalid JSON arguments instead of serving {} (default: false)\n --responses-tools <mode> OpenAI Responses tool handling: legacy (default) or extended (namespaced and\n custom tools visible to matching, custom tool rounds counted, namespaces emitted and recorded)\n --journal-max <n> Max request entries retained in memory (default: 1000, 0 = unbounded)\n --fixture-counts-max <n> Max unique testIds retained in fixture match-count map (default: 500, 0 = unbounded)\n --provider-openai <url> Upstream URL for OpenAI (used with --record)\n --provider-anthropic <url> Upstream URL for Anthropic\n --provider-gemini <url> Upstream URL for Gemini\n --provider-vertexai <url> Upstream URL for Vertex AI\n --provider-bedrock <url> Upstream URL for Bedrock\n --provider-azure <url> Upstream URL for Azure OpenAI\n --provider-ollama <url> Upstream URL for Ollama\n --provider-cohere <url> Upstream URL for Cohere\n --provider-openrouter <url> Upstream URL for OpenRouter (video record proxy)\n --provider-byteplus <url> Upstream ORIGIN for BytePlus Ark (e.g. https://ark.ap-southeast.bytepluses.com — origin only, no /api/v3)\n --upstream-timeout-ms <ms> Idle timeout (ms) on upstream socket before response (default: 30000)\n --body-timeout-ms <ms> Idle timeout (ms) on upstream response body between chunks (default: 30000)\n --max-proxy-buffer-bytes <n> Cap (bytes) on in-memory proxy-path buffer; full body still relayed (default: 67108864)\n --max-proxy-buffer-frames <n> Cap (frames) on in-memory proxy-path per-frame state; full body still relayed (default: 5000000)\n --agui-record Enable AG-UI recording (proxy unmatched AG-UI requests)\n --agui-upstream <url> Upstream AG-UI agent URL (used with --agui-record)\n --agui-proxy-only AG-UI proxy mode: forward without saving\n --mcp-record <mount>=<url> Record an upstream MCP server into mcpFakes (repeatable)\n --mcp-proxy-only <mount>=<url> Proxy an upstream MCP server without saving\n --replay-speed <n> Replay speed multiplier (default: 1.0, 2.0 = 2x faster)\n --chaos-drop <rate> Probability (0-1) of dropping requests with 500\n --chaos-malformed <rate> Probability (0-1) of returning malformed JSON\n --chaos-disconnect <rate> Probability (0-1) of destroying connection\n --chaos-ratelimit <rate> Probability (0-1) of 429 with Retry-After\n --chaos-latency <ms> Delay (0-${CHAOS_FIELDS.latencyMs.max}ms) injected before handling\n AIMOCK_API_KEYS Comma-separated inbound test API keys (environment only)\n --help Show this help message\n`.trim();\n\nconst { values } = parseArgs({\n options: {\n port: { type: \"string\", short: \"p\", default: \"4010\" },\n host: { type: \"string\", short: \"h\", default: \"127.0.0.1\" },\n fixtures: { type: \"string\", short: \"f\", multiple: true },\n latency: { type: \"string\", short: \"l\", default: \"0\" },\n \"chunk-size\": { type: \"string\", short: \"c\", default: \"20\" },\n watch: { type: \"boolean\", short: \"w\", default: false },\n \"log-level\": { type: \"string\", default: \"info\" },\n \"validate-on-load\": { type: \"boolean\", default: false },\n misbehavior: { type: \"boolean\", default: false },\n metrics: { type: \"boolean\", default: false },\n record: { type: \"boolean\", default: false },\n \"record-full-model-version\": { type: \"boolean\", default: false },\n \"proxy-only\": { type: \"boolean\", default: false },\n strict: { type: \"boolean\", default: false },\n \"strict-tool-arguments\": { type: \"boolean\", default: false },\n \"responses-tools\": { type: \"string\" },\n \"provider-openai\": { type: \"string\" },\n \"provider-anthropic\": { type: \"string\" },\n \"provider-gemini\": { type: \"string\" },\n \"provider-vertexai\": { type: \"string\" },\n \"provider-bedrock\": { type: \"string\" },\n \"provider-azure\": { type: \"string\" },\n \"provider-ollama\": { type: \"string\" },\n \"provider-cohere\": { type: \"string\" },\n \"provider-openrouter\": { type: \"string\" },\n \"provider-byteplus\": { type: \"string\" },\n \"upstream-timeout-ms\": { type: \"string\" },\n \"body-timeout-ms\": { type: \"string\" },\n \"max-proxy-buffer-bytes\": { type: \"string\" },\n \"max-proxy-buffer-frames\": { type: \"string\" },\n \"agui-record\": { type: \"boolean\", default: false },\n \"agui-upstream\": { type: \"string\" },\n \"agui-proxy-only\": { type: \"boolean\", default: false },\n \"mcp-record\": { type: \"string\", multiple: true },\n \"mcp-proxy-only\": { type: \"string\", multiple: true },\n \"replay-speed\": { type: \"string\", default: \"1.0\" },\n \"chaos-drop\": { type: \"string\" },\n \"chaos-malformed\": { type: \"string\" },\n \"chaos-disconnect\": { type: \"string\" },\n \"chaos-ratelimit\": { type: \"string\" },\n \"chaos-latency\": { type: \"string\" },\n \"journal-max\": { type: \"string\", default: \"1000\" },\n \"fixture-counts-max\": { type: \"string\", default: \"500\" },\n help: { type: \"boolean\", default: false },\n },\n strict: true,\n});\n\nif (values.help) {\n console.log(HELP);\n process.exit(0);\n}\n\nconst port = Number(values.port);\nconst host = values.host!;\nconst latency = Number(values.latency);\nconst chunkSize = Number(values[\"chunk-size\"]);\nconst fixtureValues: string[] =\n values.fixtures && values.fixtures.length > 0 ? values.fixtures : [\"./fixtures\"];\nconst watchMode = values.watch!;\nconst validateOnLoad = values[\"validate-on-load\"]!;\nconst logLevelStr = values[\"log-level\"]!;\n\nif (![\"silent\", \"warn\", \"info\", \"debug\"].includes(logLevelStr)) {\n console.error(`Invalid log-level: ${logLevelStr} (must be silent, warn, info, or debug)`);\n process.exit(1);\n}\nconst logLevel = logLevelStr as LogLevel;\n\nif (Number.isNaN(port) || port < 0 || port > 65535) {\n console.error(`Invalid port: ${values.port}`);\n process.exit(1);\n}\n\nif (Number.isNaN(latency) || latency < 0) {\n console.error(`Invalid latency: ${values.latency}`);\n process.exit(1);\n}\n\nif (Number.isNaN(chunkSize) || chunkSize < 1) {\n console.error(`Invalid chunk-size: ${values[\"chunk-size\"]}`);\n process.exit(1);\n}\n\nconst replaySpeed = Number(values[\"replay-speed\"]);\nif (Number.isNaN(replaySpeed) || replaySpeed <= 0) {\n console.error(\"--replay-speed must be a positive number\");\n process.exit(1);\n}\n\nconst responsesToolsFlag = values[\"responses-tools\"];\nif (\n responsesToolsFlag !== undefined &&\n responsesToolsFlag !== \"legacy\" &&\n responsesToolsFlag !== \"extended\"\n) {\n console.error(\n `Invalid --responses-tools: ${responsesToolsFlag} (expected \"legacy\" or \"extended\")`,\n );\n process.exit(1);\n}\nconst responsesTools: ResponsesToolsMode | undefined = responsesToolsFlag;\n\nconst journalMax = Number(values[\"journal-max\"]);\nif (Number.isNaN(journalMax) || !Number.isInteger(journalMax) || journalMax < 0) {\n console.error(\n `Invalid journal-max: ${values[\"journal-max\"]} (must be a non-negative integer; 0 = unbounded)`,\n );\n process.exit(1);\n}\n\nconst fixtureCountsMaxStr = values[\"fixture-counts-max\"];\nconst fixtureCountsMax = Number(fixtureCountsMaxStr);\nif (Number.isNaN(fixtureCountsMax) || !Number.isInteger(fixtureCountsMax) || fixtureCountsMax < 0) {\n console.error(\n `Invalid fixture-counts-max: ${fixtureCountsMaxStr} (must be a non-negative integer; 0 = unbounded)`,\n );\n process.exit(1);\n}\n\nconst upstreamTimeoutMsStr = values[\"upstream-timeout-ms\"];\nlet upstreamTimeoutMs: number | undefined;\nif (upstreamTimeoutMsStr !== undefined) {\n upstreamTimeoutMs = Number(upstreamTimeoutMsStr);\n if (!Number.isFinite(upstreamTimeoutMs) || upstreamTimeoutMs <= 0) {\n console.error(\n `Invalid upstream-timeout-ms: ${upstreamTimeoutMsStr} (must be a positive finite number)`,\n );\n process.exit(1);\n }\n}\n\nconst bodyTimeoutMsStr = values[\"body-timeout-ms\"];\nlet bodyTimeoutMs: number | undefined;\nif (bodyTimeoutMsStr !== undefined) {\n bodyTimeoutMs = Number(bodyTimeoutMsStr);\n if (!Number.isFinite(bodyTimeoutMs) || bodyTimeoutMs <= 0) {\n console.error(\n `Invalid body-timeout-ms: ${bodyTimeoutMsStr} (must be a positive finite number)`,\n );\n process.exit(1);\n }\n}\n\nconst maxProxyBufferBytesStr = values[\"max-proxy-buffer-bytes\"];\nlet maxProxyBufferBytes: number | undefined;\nif (maxProxyBufferBytesStr !== undefined) {\n maxProxyBufferBytes = Number(maxProxyBufferBytesStr);\n if (!Number.isFinite(maxProxyBufferBytes) || maxProxyBufferBytes <= 0) {\n console.error(\n `Invalid max-proxy-buffer-bytes: ${maxProxyBufferBytesStr} (must be a positive finite number)`,\n );\n process.exit(1);\n }\n}\n\nconst maxProxyBufferFramesStr = values[\"max-proxy-buffer-frames\"];\nlet maxProxyBufferFrames: number | undefined;\nif (maxProxyBufferFramesStr !== undefined) {\n maxProxyBufferFrames = Number(maxProxyBufferFramesStr);\n if (!Number.isFinite(maxProxyBufferFrames) || maxProxyBufferFrames <= 0) {\n console.error(\n `Invalid max-proxy-buffer-frames: ${maxProxyBufferFramesStr} (must be a positive finite number)`,\n );\n process.exit(1);\n }\n}\n\nconst logger = new Logger(logLevel);\n\n// Parse chaos config from CLI flags\nlet chaos: ChaosConfig | undefined;\n{\n const dropStr = values[\"chaos-drop\"];\n const malformedStr = values[\"chaos-malformed\"];\n const disconnectStr = values[\"chaos-disconnect\"];\n const ratelimitStr = values[\"chaos-ratelimit\"];\n const latencyStr = values[\"chaos-latency\"];\n\n if (\n dropStr !== undefined ||\n malformedStr !== undefined ||\n disconnectStr !== undefined ||\n ratelimitStr !== undefined ||\n latencyStr !== undefined\n ) {\n // Same parser, same TABLE, same reject-never-clamp policy as every other\n // chaos input (headers, fixture, server default, control API) — see\n // `ChaosConfig`. The bounds and the integer-vs-rate grammar are read out of\n // `CHAOS_FIELDS`, never re-typed here, so raising a cap in that one table\n // moves the flag with it instead of leaving `--chaos-latency` on the old\n // limit with no compile error.\n chaos = {};\n const flagFields: Array<{ flag: string; field: ChaosField; raw: string | undefined }> = [\n { flag: \"chaos-drop\", field: \"dropRate\", raw: dropStr },\n { flag: \"chaos-malformed\", field: \"malformedRate\", raw: malformedStr },\n { flag: \"chaos-disconnect\", field: \"disconnectRate\", raw: disconnectStr },\n { flag: \"chaos-ratelimit\", field: \"rateLimitRate\", raw: ratelimitStr },\n { flag: \"chaos-latency\", field: \"latencyMs\", raw: latencyStr },\n ];\n for (const { flag, field, raw } of flagFields) {\n if (raw === undefined) continue;\n const val = parseChaosField(field, raw);\n if (val === undefined) {\n console.error(`Invalid ${flag}: ${raw} (must be 0-${CHAOS_FIELDS[field].max})`);\n process.exit(1);\n }\n chaos[field] = val;\n }\n }\n}\n\n// Parse record/proxy config from CLI flags\nlet record: RecordConfig | undefined;\nif (values.record || values[\"proxy-only\"]) {\n const providers: RecordConfig[\"providers\"] = {};\n if (values[\"provider-openai\"]) providers.openai = values[\"provider-openai\"];\n if (values[\"provider-anthropic\"]) providers.anthropic = values[\"provider-anthropic\"];\n if (values[\"provider-gemini\"]) providers.gemini = values[\"provider-gemini\"];\n if (values[\"provider-vertexai\"]) providers.vertexai = values[\"provider-vertexai\"];\n if (values[\"provider-bedrock\"]) providers.bedrock = values[\"provider-bedrock\"];\n if (values[\"provider-azure\"]) providers.azure = values[\"provider-azure\"];\n if (values[\"provider-ollama\"]) providers.ollama = values[\"provider-ollama\"];\n if (values[\"provider-cohere\"]) providers.cohere = values[\"provider-cohere\"];\n if (values[\"provider-openrouter\"]) providers.openrouter = values[\"provider-openrouter\"];\n if (values[\"provider-byteplus\"]) providers.byteplus = values[\"provider-byteplus\"];\n\n if (Object.keys(providers).length === 0) {\n console.error(\n `Error: --${values[\"proxy-only\"] ? \"proxy-only\" : \"record\"} requires at least one --provider-* flag`,\n );\n process.exit(1);\n }\n\n // For --record, the first --fixtures value is the base path for the recording\n // destination and must be a local filesystem path — writing to a URL is not supported.\n // For --proxy-only, unmatched requests are forwarded without saving, so no writable\n // destination is required; URL-only --fixtures is valid in that mode.\n const recordBase = fixtureValues[0];\n const recordBaseIsUrl = /^https?:\\/\\//i.test(recordBase);\n if (values.record && recordBaseIsUrl) {\n console.error(\n `Error: --record requires a local --fixtures path for the recording destination; got URL ${recordBase}`,\n );\n process.exit(1);\n }\n record = {\n providers,\n // aimock's own upstream keys, sourced from AIMOCK_PROVIDER_*_KEY env vars\n // (not CLI flags — secrets must not appear in `ps`). Injected on a\n // fixture-miss passthrough when the caller sent no/dummy credential.\n providerKeys: readProviderKeysFromEnv(),\n // In proxy-only mode with only URL sources, fixturePath is never consumed\n // (recorder.ts skips disk writes when proxyOnly is set). Leave it undefined\n // rather than resolving a URL string as a filesystem path.\n fixturePath: recordBaseIsUrl ? undefined : resolve(recordBase, \"recorded\"),\n proxyOnly: values[\"proxy-only\"],\n recordFullModelVersion: values[\"record-full-model-version\"],\n upstreamTimeoutMs,\n bodyTimeoutMs,\n maxProxyBufferBytes,\n maxProxyBufferFrames,\n };\n} else {\n // These flags configure upstream proxying — without --record or\n // --proxy-only they would be parsed and then silently dropped. Routed\n // through the constructed logger so --log-level is respected.\n const droppedProviderFlags = (\n [\n \"provider-openai\",\n \"provider-anthropic\",\n \"provider-gemini\",\n \"provider-vertexai\",\n \"provider-bedrock\",\n \"provider-azure\",\n \"provider-ollama\",\n \"provider-cohere\",\n \"provider-openrouter\",\n \"provider-byteplus\",\n ] as const\n ).filter((flag) => values[flag] !== undefined);\n if (droppedProviderFlags.length > 0) {\n logger.warn(\n `--${droppedProviderFlags.join(\"/--\")} only apply to --record/--proxy-only upstream proxying — ignored without one of those flags.`,\n );\n }\n if (\n upstreamTimeoutMs !== undefined ||\n bodyTimeoutMs !== undefined ||\n maxProxyBufferBytes !== undefined ||\n maxProxyBufferFrames !== undefined\n ) {\n logger.warn(\n \"--upstream-timeout-ms/--body-timeout-ms/--max-proxy-buffer-bytes/--max-proxy-buffer-frames only apply to --record/--proxy-only upstream proxying — ignored without one of those flags.\",\n );\n }\n}\n\n// Parse AG-UI record/proxy config from CLI flags\nlet aguiMount: { path: string; handler: AGUIMock } | undefined;\nif (values[\"agui-record\"] || values[\"agui-proxy-only\"]) {\n if (!values[\"agui-upstream\"]) {\n console.error(\"Error: --agui-record/--agui-proxy-only requires --agui-upstream\");\n process.exit(1);\n }\n // --agui-record writes recorded AG-UI fixtures to disk, so a URL source is unsupported.\n // --agui-proxy-only forwards without saving, so URL-only --fixtures is valid.\n const aguiBase = fixtureValues[0];\n const aguiBaseIsUrl = /^https?:\\/\\//i.test(aguiBase);\n if (values[\"agui-record\"] && aguiBaseIsUrl) {\n console.error(\n `Error: --agui-record requires a local --fixtures path for the recording destination; got URL ${aguiBase}`,\n );\n process.exit(1);\n }\n const agui = new AGUIMock();\n agui.enableRecording({\n upstream: values[\"agui-upstream\"],\n // In proxy-only mode with a URL-only --fixtures, the AG-UI recorder never\n // writes to disk (see agui-recorder.ts). Leave fixturePath undefined rather\n // than resolving a URL as a filesystem path.\n fixturePath: aguiBaseIsUrl ? undefined : resolve(aguiBase, \"agui-recorded\"),\n proxyOnly: values[\"agui-proxy-only\"],\n });\n aguiMount = { path: \"/agui\", handler: agui };\n}\n\n// Parse MCP record/proxy mounts (MR1, AM6): --mcp-record / --mcp-proxy-only <mount>=<url>\nconst mcpRecordMounts: { path: string; handler: MCPMock }[] = [];\n{\n const recordValues = values[\"mcp-record\"] ?? [];\n const proxyValues = values[\"mcp-proxy-only\"] ?? [];\n if (recordValues.length > 0) {\n // C11: check the flag itself; fixtureValues defaults to ./fixtures.\n if (!(values.fixtures && values.fixtures.length > 0)) {\n console.error(\n \"Error: --mcp-record requires --fixtures <local path> for the recording destination\",\n );\n process.exit(1);\n }\n if (/^https?:\\/\\//i.test(values.fixtures[0])) {\n console.error(\n `Error: --mcp-record requires a local --fixtures path for the recording destination; got URL ${values.fixtures[0]}`,\n );\n process.exit(1);\n }\n }\n const flags = [\n ...recordValues.map((value) => ({ flag: \"--mcp-record\", value, proxyOnly: false })),\n ...proxyValues.map((value) => ({ flag: \"--mcp-proxy-only\", value, proxyOnly: true })),\n ];\n if (flags.length > 0) {\n let env: ReturnType<typeof mcpRecordEnv>;\n try {\n env = mcpRecordEnv(process.env);\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n for (const { flag, value, proxyOnly } of flags) {\n try {\n const { mount, upstream } = parseMcpRecordFlag(value, flag);\n if (aguiMount && mount === aguiMount.path) {\n throw new Error(`${flag} mount ${mount} is held by a mount that is not an MCP mock`);\n }\n if (mcpRecordMounts.some((m) => m.path === mount)) {\n throw new Error(`${flag} mount ${mount} is given more than once`);\n }\n const mcp = new MCPMock().enableRecording({\n upstream,\n fixturePath: proxyOnly ? undefined : resolve(values.fixtures![0], \"recorded\"),\n proxyOnly,\n secretValues: env.secretValues,\n upstreamAuth: env.upstreamAuth,\n strict: values.strict,\n });\n mcpRecordMounts.push({ path: mount, handler: mcp });\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n }\n }\n}\n\ninterface ResolvedFixtureSource {\n source: string;\n path: string;\n isDir: boolean;\n}\n\nasync function resolveAllFixtureSources(): Promise<ResolvedFixtureSource[]> {\n const resolved: ResolvedFixtureSource[] = [];\n for (const value of fixtureValues) {\n let local;\n try {\n local = await resolveFixturesValue(value, {\n validateOnLoad,\n logger,\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`Failed to resolve --fixtures value \"${value}\": ${msg}`);\n process.exit(1);\n }\n if (!local.path) {\n // Remote fetch failed without validate-on-load and no cache — already warned; skip.\n continue;\n }\n try {\n const stat = statSync(local.path);\n resolved.push({ source: local.source, path: local.path, isDir: stat.isDirectory() });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n console.error(`Fixtures path not found: ${local.path}`);\n } else {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`Failed to load fixtures from ${local.path}: ${msg}`);\n }\n process.exit(1);\n }\n }\n return resolved;\n}\n\n// F3: the loaders that carry `mcpFakes`. A file's entry-id source (I6) is the\n// --fixtures value as given: the path, or the URL of a remote file (whose\n// `path` is the on-disk cache).\nfunction loadSource(source: ResolvedFixtureSource): FixturesWithServices {\n const loaded = source.isDir\n ? loadFixturesFromDirWithServices(source.path, logger)\n : loadFixtureFileWithServices(source.path, logger, undefined, source.source);\n // --misbehavior: a bad fixture `misbehavior` key fails the load; without it the key is ignored.\n if (values.misbehavior) loaded.fixtures.forEach(enableHeldFixtureMisbehavior);\n return loaded;\n}\n\n/** Each source's `mcpFakes` blocks, in load order, for the --watch comparison. */\nfunction fakesBySource(blocks: McpFakeSource[]): Map<string, unknown[]> {\n const bySource = new Map<string, unknown[]>();\n for (const block of blocks) {\n const list = bySource.get(block.source) ?? [];\n list.push([block.blockIndex, block.raw]);\n bySource.set(block.source, list);\n }\n return bySource;\n}\n\n/**\n * R9/F11: fakes are not reloaded by --watch, so a reload whose `mcpFakes`\n * differ from the boot set is rejected. Returns the first changed source.\n * A source in `unreadable` could not be read or parsed: it is not compared,\n * because its blocks are unknown, not removed.\n */\nfunction changedFakesSource(\n boot: McpFakeSource[],\n reload: McpFakeSource[],\n unreadable: ReadonlySet<string>,\n): string | null {\n const before = fakesBySource(boot);\n const after = fakesBySource(reload);\n for (const source of new Set([...before.keys(), ...after.keys()])) {\n if (unreadable.has(source)) continue;\n if (!isDeepStrictEqual(before.get(source), after.get(source))) return source;\n }\n return null;\n}\n\n/**\n * L3: a load error on stderr, whatever the log level: every error of a\n * `McpFakesAddError`, one per line, then its L8 warnings.\n */\nfunction printLoadError(err: FixtureLoadError | MisbehaviorConfigError): void {\n const errors = err instanceof McpFakesAddError ? err.errors : [err];\n for (const e of errors) console.error(e.message);\n if (err instanceof McpFakesAddError) {\n for (const w of err.warnings) console.warn(w.message);\n }\n}\n\n/** A --watch reload that `loadFn` rejected and already printed (L3, L7). */\nclass ReloadRejected extends Error {}\n\n/**\n * The --watch logger: as `Logger`, except that the watcher's own report of a\n * {@link ReloadRejected} reload is dropped, so the error is printed once.\n */\nclass WatchLogger extends Logger {\n override error(...args: unknown[]): void {\n if (args.some((a) => a instanceof ReloadRejected)) return;\n super.error(...args);\n }\n}\n\n/**\n * MR13: --watch with record mounts. (a) An event for a recorder temp file, or\n * for a file whose bytes are exactly what a recorder last wrote there, does\n * not reload; everything else (a delete, a directory, a user edit) reloads as\n * on main. (b) Each recorder write moves the --watch baseline of that file,\n * so the next reload does not reject the recording as a changed `mcpFakes`.\n * Without record mounts (or for a file source), --watch is exactly as on main.\n */\nfunction recorderWatch(\n primary: ResolvedFixtureSource,\n moveBaseline: (moved: (boot: McpFakeSource[]) => McpFakeSource[]) => void,\n): { ignore?: (absPath: string) => boolean } {\n const events = mcpRecordMounts.map((m) => m.handler.recorderEvents()).filter((ev) => ev !== null);\n if (events.length === 0 || !primary.isDir) return {};\n for (const ev of events) {\n ev.onWrite((file, written) => {\n const source = relative(primary.path, file).split(sep).join(\"/\");\n const blocks: McpFakeSource[] = Array.isArray(written)\n ? written.map((raw, blockIndex) => ({ source, blockIndex, raw }))\n : [{ source, blockIndex: null, raw: written }];\n moveBaseline((boot) => {\n // Replace this source's blocks in place; a new source goes last.\n const others = boot.filter((b) => b.source !== source);\n const at = boot.findIndex((b) => b.source === source);\n const pos = at === -1 ? others.length : at;\n return [...others.slice(0, pos), ...blocks, ...others.slice(pos)];\n });\n });\n }\n return {\n ignore: (absPath: string): boolean => {\n // Recorder temp files only (persistServiceFakes writes `<file>.tmp.<uuid>`, then renames it).\n if (/\\.tmp\\.[0-9a-f-]+$/i.test(absPath)) return true;\n let st: Stats;\n try {\n st = statSync(absPath);\n } catch {\n return false; // gone: a user deleted a fixture — this MUST reload (r2 N2)\n }\n if (st.isDirectory()) return false; // directory events behave as on main\n let data: Buffer;\n try {\n data = readFileSync(absPath);\n } catch {\n return false;\n }\n const hash = createHash(\"sha256\").update(data).digest(\"hex\");\n return events.some((ev) => ev.lastWrittenHash(absPath) === hash);\n },\n };\n}\n\nasync function main() {\n const sources = await resolveAllFixtureSources();\n\n const fixtures: Fixture[] = [];\n const mcpFakes: McpFakeSource[] = [];\n // The primary source's blocks: what a --watch reload of it is compared with.\n let primaryFakes: McpFakeSource[] = [];\n for (const src of sources) {\n const loaded = loadSource(src);\n fixtures.push(...loaded.fixtures);\n mcpFakes.push(...loaded.mcpFakes);\n if (src === sources[0]) primaryFakes = loaded.mcpFakes;\n }\n\n if (fixtures.length === 0 && mcpFakes.length > 0) {\n // F5/L9: fake blocks count as loaded; only LLM requests have nothing to match.\n console.warn(build(msg`Warning: No LLM fixtures loaded; LLM requests will return 404`));\n } else if (fixtures.length === 0) {\n if (validateOnLoad || values.strict) {\n console.error(\"Error: No fixtures loaded and validation/strict mode is enabled — aborting.\");\n process.exit(1);\n }\n console.warn(\"Warning: No fixtures loaded. The server will return 404 for all requests.\");\n }\n\n const sourceLabel = sources.map((s) => s.source).join(\", \") || \"<none>\";\n logger.info(`Loaded ${fixtures.length} fixture(s) from ${sourceLabel}`);\n\n // Validate fixtures if requested\n if (validateOnLoad) {\n if (responsesTools === \"extended\") fixtures.forEach(markFixtureResponsesToolsExtended);\n const results = validateFixtures(fixtures);\n const errors = results.filter((r) => r.severity === \"error\");\n const warnings = results.filter((r) => r.severity === \"warning\");\n\n for (const w of warnings) {\n logger.warn(`Fixture ${w.fixtureIndex}: ${w.message}`);\n }\n // L8 (shadowed mcpFakes entries) is not printed here: the hand-off in\n // createServer prints it on every start.\n for (const e of errors) {\n logger.error(`Fixture ${e.fixtureIndex}: ${e.message}`);\n }\n\n if (errors.length > 0) {\n console.error(`Validation failed: ${errors.length} error(s), ${warnings.length} warning(s)`);\n process.exit(1);\n }\n }\n\n const allMounts: { path: string; handler: Mountable }[] = [\n ...(aguiMount ? [aguiMount] : []),\n ...mcpRecordMounts,\n ];\n const mounts = allMounts.length > 0 ? allMounts : undefined;\n\n const instance = await createServer(\n fixtures,\n {\n port,\n host,\n latency,\n chunkSize,\n replaySpeed,\n logLevel,\n chaos,\n metrics: values.metrics,\n record,\n strict: values.strict,\n strictToolArguments: values[\"strict-tool-arguments\"],\n enableMisbehavior: values.misbehavior,\n ...(responsesTools !== undefined ? { responsesTools } : {}),\n journalMaxEntries: journalMax,\n fixtureCountsMaxTestIds: fixtureCountsMax,\n auth: resolveInboundAuth(selectInboundAuthSource(undefined)).publicConfig,\n },\n mounts,\n { search: [], rerank: [], moderation: [], mcpFakes },\n );\n\n // Only the first local source is watched — remote URL sources are fetched once\n // at boot and are not monitored. Declared before the readiness announcement so\n // shutdown can close it whenever the signal arrives.\n let watcher: { close: () => void } | null = null;\n\n function shutdown() {\n logger.info(\"Shutting down...\");\n if (watcher) watcher.close();\n instance.server.close(() => {\n process.exit(0);\n });\n }\n\n // Register BEFORE announcing readiness. Writes to a pipe are synchronous on Linux\n // (and to a file on every POSIX platform), so a supervisor that reacts to the line\n // below can deliver SIGTERM while this process is still mid-statement. Announcing\n // first left a window in which SIGTERM hit Node's default disposition, which\n // re-raises: the process died with a null exit code instead of shutting down.\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n logger.info(`aimock server listening on ${instance.url}`);\n\n // Start file watcher if requested.\n if (watchMode) {\n const primary = sources[0];\n if (!primary) {\n logger.warn(\"--watch requested but no resolvable fixture sources; skipping watcher\");\n } else {\n // A rejected reload is printed here, whatever the log level, then\n // thrown as ReloadRejected: watchFixtures keeps the previous fixtures,\n // and its WatchLogger does not print the error a second time.\n const reject = (err: FixtureLoadError | MisbehaviorConfigError): never => {\n printLoadError(err);\n throw new ReloadRejected(build(msg`--watch reload rejected`));\n };\n const loadFn = (): Fixture[] => {\n let loaded: FixturesWithServices;\n try {\n loaded = loadSource(primary);\n } catch (err) {\n // L3: a bad block in the reloaded file.\n if (err instanceof FixtureLoadError || err instanceof MisbehaviorConfigError) {\n return reject(err);\n }\n throw err;\n }\n const changed = changedFakesSource(\n primaryFakes,\n loaded.mcpFakes,\n new Set(loaded.unreadable),\n );\n if (changed !== null) {\n // L7.\n return reject(\n new FixtureLoadError({\n rule: \"mcp-fakes/watch-reload-changed\",\n file: changed,\n detail: msg`mcpFakes changed on --watch reload; MCP fakes are not reloaded, so the whole reload is rejected and the previous fixtures stay loaded. Restart aimock to load the new fakes`,\n }),\n );\n }\n if (responsesTools === \"extended\") {\n loaded.fixtures.forEach(markFixtureResponsesToolsExtended);\n }\n return loaded.fixtures;\n };\n watcher = watchFixtures(primary.path, fixtures, loadFn, {\n logger: new WatchLogger(logLevel),\n validate: validateOnLoad,\n validateFn: validateFixtures,\n ...recorderWatch(primary, (moved) => (primaryFakes = moved(primaryFakes))),\n });\n logger.info(`Watching ${primary.path} for changes`);\n }\n }\n}\n\nmain().catch((err) => {\n if (err instanceof FixtureLoadError || err instanceof MisbehaviorConfigError) {\n printLoadError(err);\n } else {\n console.error(err);\n }\n process.exit(1);\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { isDeepStrictEqual, parseArgs } from \"node:util\";\nimport { createHash } from \"node:crypto\";\nimport { readFileSync, statSync, type Stats } from \"node:fs\";\nimport { relative, resolve, sep } from \"node:path\";\nimport { createServer } from \"./server.js\";\nimport { parsePolicyFlags } from \"./config-loader.js\";\nimport type { ResponsesToolsMode } from \"./types.js\";\nimport {\n FixtureLoadError,\n MisbehaviorConfigError,\n enableHeldFixtureMisbehavior,\n markFixtureResponsesToolsExtended,\n validateFixtures,\n} from \"./fixture-loader.js\";\nimport {\n loadFixtureFileWithServices,\n loadFixturesFromDirWithServices,\n type FixturesWithServices,\n} from \"./fixture-loader-services.js\";\nimport { McpFakesAddError } from \"./mcp-fakes.js\";\nimport { build, msg } from \"./message-text.js\";\nimport { Logger, type LogLevel } from \"./logger.js\";\nimport { watchFixtures } from \"./watcher.js\";\nimport { AGUIMock } from \"./agui-mock.js\";\nimport { MCPMock } from \"./mcp-mock.js\";\nimport { mcpRecordEnv, parseMcpRecordFlag } from \"./mcp-recorder.js\";\nimport { parseChaosField, CHAOS_FIELDS, type ChaosField } from \"./chaos.js\";\nimport { resolveFixturesValue } from \"./fixtures-remote.js\";\nimport { readProviderKeysFromEnv } from \"./provider-auth.js\";\nimport { resolveInboundAuth, selectInboundAuthSource } from \"./api-key-auth.js\";\nimport type { Fixture, ChaosConfig, RecordConfig, McpFakeSource, Mountable } from \"./types.js\";\n\nconst HELP = `\nUsage: aimock [options]\n\nOptions:\n -p, --port <number> Port to listen on (default: 4010)\n -h, --host <string> Host to bind to (default: 127.0.0.1)\n -f, --fixtures <value> Fixture source (repeatable). Accepts:\n - filesystem path to a directory or .json file (default: ./fixtures)\n - https:// or http:// URL to a .json fixture file\n -l, --latency <ms> Latency in ms between SSE chunks (default: 0)\n -c, --chunk-size <chars> Chunk size in characters (default: 20)\n -w, --watch Watch fixture path for changes and reload\n --log-level <level> Log verbosity: silent, warn, info, debug (default: info)\n --validate-on-load Validate fixture schemas at startup\n --misbehavior Enable model misbehavior: fixture misbehavior keys and the\n X-AIMock-Misbehavior header (ignored without this flag)\n --metrics Enable Prometheus metrics at GET /metrics\n --record Record mode: proxy unmatched requests and save fixtures\n --record-full-model-version Record exact model version without date stripping (default: false)\n --proxy-only Proxy mode: forward unmatched requests without saving\n --strict Strict mode: fail on unmatched requests (overridable per-request via X-AIMock-Strict header)\n --strict-tool-arguments Reject fixture tool calls with invalid JSON arguments instead of serving {} (default: false)\n --responses-tools <mode> OpenAI Responses tool handling: legacy (default) or extended (namespaced and\n custom tools visible to matching, custom tool rounds counted, namespaces emitted and recorded)\n --policy <key=value> Request policy (repeatable): requiredHeaders=off|enforce (default: off),\n authErrors=legacy|native (default: legacy),\n modelCatalog=legacy|native (default: legacy)\n --journal-max <n> Max request entries retained in memory (default: 1000, 0 = unbounded)\n --fixture-counts-max <n> Max unique testIds retained in fixture match-count map (default: 500, 0 = unbounded)\n --provider-openai <url> Upstream URL for OpenAI (used with --record)\n --provider-anthropic <url> Upstream URL for Anthropic\n --provider-gemini <url> Upstream URL for Gemini\n --provider-vertexai <url> Upstream URL for Vertex AI\n --provider-bedrock <url> Upstream URL for Bedrock\n --provider-azure <url> Upstream URL for Azure OpenAI\n --provider-ollama <url> Upstream URL for Ollama\n --provider-cohere <url> Upstream URL for Cohere\n --provider-openrouter <url> Upstream URL for OpenRouter (video record proxy)\n --provider-byteplus <url> Upstream ORIGIN for BytePlus Ark (e.g. https://ark.ap-southeast.bytepluses.com — origin only, no /api/v3)\n --upstream-timeout-ms <ms> Idle timeout (ms) on upstream socket before response (default: 30000)\n --body-timeout-ms <ms> Idle timeout (ms) on upstream response body between chunks (default: 30000)\n --max-proxy-buffer-bytes <n> Cap (bytes) on in-memory proxy-path buffer; full body still relayed (default: 67108864)\n --max-proxy-buffer-frames <n> Cap (frames) on in-memory proxy-path per-frame state; full body still relayed (default: 5000000)\n --agui-record Enable AG-UI recording (proxy unmatched AG-UI requests)\n --agui-upstream <url> Upstream AG-UI agent URL (used with --agui-record)\n --agui-proxy-only AG-UI proxy mode: forward without saving\n --mcp-record <mount>=<url> Record an upstream MCP server into mcpFakes (repeatable)\n --mcp-proxy-only <mount>=<url> Proxy an upstream MCP server without saving\n --replay-speed <n> Replay speed multiplier (default: 1.0, 2.0 = 2x faster)\n --chaos-drop <rate> Probability (0-1) of dropping requests with 500\n --chaos-malformed <rate> Probability (0-1) of returning malformed JSON\n --chaos-disconnect <rate> Probability (0-1) of destroying connection\n --chaos-ratelimit <rate> Probability (0-1) of 429 with Retry-After\n --chaos-latency <ms> Delay (0-${CHAOS_FIELDS.latencyMs.max}ms) injected before handling\n AIMOCK_API_KEYS Comma-separated inbound test API keys (environment only)\n --help Show this help message\n`.trim();\n\nconst { values } = parseArgs({\n options: {\n port: { type: \"string\", short: \"p\", default: \"4010\" },\n host: { type: \"string\", short: \"h\", default: \"127.0.0.1\" },\n fixtures: { type: \"string\", short: \"f\", multiple: true },\n latency: { type: \"string\", short: \"l\", default: \"0\" },\n \"chunk-size\": { type: \"string\", short: \"c\", default: \"20\" },\n watch: { type: \"boolean\", short: \"w\", default: false },\n \"log-level\": { type: \"string\", default: \"info\" },\n \"validate-on-load\": { type: \"boolean\", default: false },\n misbehavior: { type: \"boolean\", default: false },\n metrics: { type: \"boolean\", default: false },\n record: { type: \"boolean\", default: false },\n \"record-full-model-version\": { type: \"boolean\", default: false },\n \"proxy-only\": { type: \"boolean\", default: false },\n strict: { type: \"boolean\", default: false },\n \"strict-tool-arguments\": { type: \"boolean\", default: false },\n \"responses-tools\": { type: \"string\" },\n policy: { type: \"string\", multiple: true },\n \"provider-openai\": { type: \"string\" },\n \"provider-anthropic\": { type: \"string\" },\n \"provider-gemini\": { type: \"string\" },\n \"provider-vertexai\": { type: \"string\" },\n \"provider-bedrock\": { type: \"string\" },\n \"provider-azure\": { type: \"string\" },\n \"provider-ollama\": { type: \"string\" },\n \"provider-cohere\": { type: \"string\" },\n \"provider-openrouter\": { type: \"string\" },\n \"provider-byteplus\": { type: \"string\" },\n \"upstream-timeout-ms\": { type: \"string\" },\n \"body-timeout-ms\": { type: \"string\" },\n \"max-proxy-buffer-bytes\": { type: \"string\" },\n \"max-proxy-buffer-frames\": { type: \"string\" },\n \"agui-record\": { type: \"boolean\", default: false },\n \"agui-upstream\": { type: \"string\" },\n \"agui-proxy-only\": { type: \"boolean\", default: false },\n \"mcp-record\": { type: \"string\", multiple: true },\n \"mcp-proxy-only\": { type: \"string\", multiple: true },\n \"replay-speed\": { type: \"string\", default: \"1.0\" },\n \"chaos-drop\": { type: \"string\" },\n \"chaos-malformed\": { type: \"string\" },\n \"chaos-disconnect\": { type: \"string\" },\n \"chaos-ratelimit\": { type: \"string\" },\n \"chaos-latency\": { type: \"string\" },\n \"journal-max\": { type: \"string\", default: \"1000\" },\n \"fixture-counts-max\": { type: \"string\", default: \"500\" },\n help: { type: \"boolean\", default: false },\n },\n strict: true,\n});\n\nif (values.help) {\n console.log(HELP);\n process.exit(0);\n}\n\nconst port = Number(values.port);\nconst host = values.host!;\nconst latency = Number(values.latency);\nconst chunkSize = Number(values[\"chunk-size\"]);\nconst fixtureValues: string[] =\n values.fixtures && values.fixtures.length > 0 ? values.fixtures : [\"./fixtures\"];\nconst watchMode = values.watch!;\nconst validateOnLoad = values[\"validate-on-load\"]!;\nconst logLevelStr = values[\"log-level\"]!;\n\nif (![\"silent\", \"warn\", \"info\", \"debug\"].includes(logLevelStr)) {\n console.error(`Invalid log-level: ${logLevelStr} (must be silent, warn, info, or debug)`);\n process.exit(1);\n}\nconst logLevel = logLevelStr as LogLevel;\n\nif (Number.isNaN(port) || port < 0 || port > 65535) {\n console.error(`Invalid port: ${values.port}`);\n process.exit(1);\n}\n\nif (Number.isNaN(latency) || latency < 0) {\n console.error(`Invalid latency: ${values.latency}`);\n process.exit(1);\n}\n\nif (Number.isNaN(chunkSize) || chunkSize < 1) {\n console.error(`Invalid chunk-size: ${values[\"chunk-size\"]}`);\n process.exit(1);\n}\n\nconst replaySpeed = Number(values[\"replay-speed\"]);\nif (Number.isNaN(replaySpeed) || replaySpeed <= 0) {\n console.error(\"--replay-speed must be a positive number\");\n process.exit(1);\n}\n\nconst responsesToolsFlag = values[\"responses-tools\"];\nif (\n responsesToolsFlag !== undefined &&\n responsesToolsFlag !== \"legacy\" &&\n responsesToolsFlag !== \"extended\"\n) {\n console.error(\n `Invalid --responses-tools: ${responsesToolsFlag} (expected \"legacy\" or \"extended\")`,\n );\n process.exit(1);\n}\nconst responsesTools: ResponsesToolsMode | undefined = responsesToolsFlag;\n\nconst parsedPolicy = parsePolicyFlags(values.policy ?? []);\nif (!parsedPolicy.ok) {\n console.error(`${parsedPolicy.error}\\n\\n${HELP}`);\n process.exit(1);\n}\nconst policy = parsedPolicy.policy;\n\nconst journalMax = Number(values[\"journal-max\"]);\nif (Number.isNaN(journalMax) || !Number.isInteger(journalMax) || journalMax < 0) {\n console.error(\n `Invalid journal-max: ${values[\"journal-max\"]} (must be a non-negative integer; 0 = unbounded)`,\n );\n process.exit(1);\n}\n\nconst fixtureCountsMaxStr = values[\"fixture-counts-max\"];\nconst fixtureCountsMax = Number(fixtureCountsMaxStr);\nif (Number.isNaN(fixtureCountsMax) || !Number.isInteger(fixtureCountsMax) || fixtureCountsMax < 0) {\n console.error(\n `Invalid fixture-counts-max: ${fixtureCountsMaxStr} (must be a non-negative integer; 0 = unbounded)`,\n );\n process.exit(1);\n}\n\nconst upstreamTimeoutMsStr = values[\"upstream-timeout-ms\"];\nlet upstreamTimeoutMs: number | undefined;\nif (upstreamTimeoutMsStr !== undefined) {\n upstreamTimeoutMs = Number(upstreamTimeoutMsStr);\n if (!Number.isFinite(upstreamTimeoutMs) || upstreamTimeoutMs <= 0) {\n console.error(\n `Invalid upstream-timeout-ms: ${upstreamTimeoutMsStr} (must be a positive finite number)`,\n );\n process.exit(1);\n }\n}\n\nconst bodyTimeoutMsStr = values[\"body-timeout-ms\"];\nlet bodyTimeoutMs: number | undefined;\nif (bodyTimeoutMsStr !== undefined) {\n bodyTimeoutMs = Number(bodyTimeoutMsStr);\n if (!Number.isFinite(bodyTimeoutMs) || bodyTimeoutMs <= 0) {\n console.error(\n `Invalid body-timeout-ms: ${bodyTimeoutMsStr} (must be a positive finite number)`,\n );\n process.exit(1);\n }\n}\n\nconst maxProxyBufferBytesStr = values[\"max-proxy-buffer-bytes\"];\nlet maxProxyBufferBytes: number | undefined;\nif (maxProxyBufferBytesStr !== undefined) {\n maxProxyBufferBytes = Number(maxProxyBufferBytesStr);\n if (!Number.isFinite(maxProxyBufferBytes) || maxProxyBufferBytes <= 0) {\n console.error(\n `Invalid max-proxy-buffer-bytes: ${maxProxyBufferBytesStr} (must be a positive finite number)`,\n );\n process.exit(1);\n }\n}\n\nconst maxProxyBufferFramesStr = values[\"max-proxy-buffer-frames\"];\nlet maxProxyBufferFrames: number | undefined;\nif (maxProxyBufferFramesStr !== undefined) {\n maxProxyBufferFrames = Number(maxProxyBufferFramesStr);\n if (!Number.isFinite(maxProxyBufferFrames) || maxProxyBufferFrames <= 0) {\n console.error(\n `Invalid max-proxy-buffer-frames: ${maxProxyBufferFramesStr} (must be a positive finite number)`,\n );\n process.exit(1);\n }\n}\n\nconst logger = new Logger(logLevel);\n\n// Parse chaos config from CLI flags\nlet chaos: ChaosConfig | undefined;\n{\n const dropStr = values[\"chaos-drop\"];\n const malformedStr = values[\"chaos-malformed\"];\n const disconnectStr = values[\"chaos-disconnect\"];\n const ratelimitStr = values[\"chaos-ratelimit\"];\n const latencyStr = values[\"chaos-latency\"];\n\n if (\n dropStr !== undefined ||\n malformedStr !== undefined ||\n disconnectStr !== undefined ||\n ratelimitStr !== undefined ||\n latencyStr !== undefined\n ) {\n // Same parser, same TABLE, same reject-never-clamp policy as every other\n // chaos input (headers, fixture, server default, control API) — see\n // `ChaosConfig`. The bounds and the integer-vs-rate grammar are read out of\n // `CHAOS_FIELDS`, never re-typed here, so raising a cap in that one table\n // moves the flag with it instead of leaving `--chaos-latency` on the old\n // limit with no compile error.\n chaos = {};\n const flagFields: Array<{ flag: string; field: ChaosField; raw: string | undefined }> = [\n { flag: \"chaos-drop\", field: \"dropRate\", raw: dropStr },\n { flag: \"chaos-malformed\", field: \"malformedRate\", raw: malformedStr },\n { flag: \"chaos-disconnect\", field: \"disconnectRate\", raw: disconnectStr },\n { flag: \"chaos-ratelimit\", field: \"rateLimitRate\", raw: ratelimitStr },\n { flag: \"chaos-latency\", field: \"latencyMs\", raw: latencyStr },\n ];\n for (const { flag, field, raw } of flagFields) {\n if (raw === undefined) continue;\n const val = parseChaosField(field, raw);\n if (val === undefined) {\n console.error(`Invalid ${flag}: ${raw} (must be 0-${CHAOS_FIELDS[field].max})`);\n process.exit(1);\n }\n chaos[field] = val;\n }\n }\n}\n\n// Parse record/proxy config from CLI flags\nlet record: RecordConfig | undefined;\nif (values.record || values[\"proxy-only\"]) {\n const providers: RecordConfig[\"providers\"] = {};\n if (values[\"provider-openai\"]) providers.openai = values[\"provider-openai\"];\n if (values[\"provider-anthropic\"]) providers.anthropic = values[\"provider-anthropic\"];\n if (values[\"provider-gemini\"]) providers.gemini = values[\"provider-gemini\"];\n if (values[\"provider-vertexai\"]) providers.vertexai = values[\"provider-vertexai\"];\n if (values[\"provider-bedrock\"]) providers.bedrock = values[\"provider-bedrock\"];\n if (values[\"provider-azure\"]) providers.azure = values[\"provider-azure\"];\n if (values[\"provider-ollama\"]) providers.ollama = values[\"provider-ollama\"];\n if (values[\"provider-cohere\"]) providers.cohere = values[\"provider-cohere\"];\n if (values[\"provider-openrouter\"]) providers.openrouter = values[\"provider-openrouter\"];\n if (values[\"provider-byteplus\"]) providers.byteplus = values[\"provider-byteplus\"];\n\n if (Object.keys(providers).length === 0) {\n console.error(\n `Error: --${values[\"proxy-only\"] ? \"proxy-only\" : \"record\"} requires at least one --provider-* flag`,\n );\n process.exit(1);\n }\n\n // For --record, the first --fixtures value is the base path for the recording\n // destination and must be a local filesystem path — writing to a URL is not supported.\n // For --proxy-only, unmatched requests are forwarded without saving, so no writable\n // destination is required; URL-only --fixtures is valid in that mode.\n const recordBase = fixtureValues[0];\n const recordBaseIsUrl = /^https?:\\/\\//i.test(recordBase);\n if (values.record && recordBaseIsUrl) {\n console.error(\n `Error: --record requires a local --fixtures path for the recording destination; got URL ${recordBase}`,\n );\n process.exit(1);\n }\n record = {\n providers,\n // aimock's own upstream keys, sourced from AIMOCK_PROVIDER_*_KEY env vars\n // (not CLI flags — secrets must not appear in `ps`). Injected on a\n // fixture-miss passthrough when the caller sent no/dummy credential.\n providerKeys: readProviderKeysFromEnv(),\n // In proxy-only mode with only URL sources, fixturePath is never consumed\n // (recorder.ts skips disk writes when proxyOnly is set). Leave it undefined\n // rather than resolving a URL string as a filesystem path.\n fixturePath: recordBaseIsUrl ? undefined : resolve(recordBase, \"recorded\"),\n proxyOnly: values[\"proxy-only\"],\n recordFullModelVersion: values[\"record-full-model-version\"],\n upstreamTimeoutMs,\n bodyTimeoutMs,\n maxProxyBufferBytes,\n maxProxyBufferFrames,\n };\n} else {\n // These flags configure upstream proxying — without --record or\n // --proxy-only they would be parsed and then silently dropped. Routed\n // through the constructed logger so --log-level is respected.\n const droppedProviderFlags = (\n [\n \"provider-openai\",\n \"provider-anthropic\",\n \"provider-gemini\",\n \"provider-vertexai\",\n \"provider-bedrock\",\n \"provider-azure\",\n \"provider-ollama\",\n \"provider-cohere\",\n \"provider-openrouter\",\n \"provider-byteplus\",\n ] as const\n ).filter((flag) => values[flag] !== undefined);\n if (droppedProviderFlags.length > 0) {\n logger.warn(\n `--${droppedProviderFlags.join(\"/--\")} only apply to --record/--proxy-only upstream proxying — ignored without one of those flags.`,\n );\n }\n if (\n upstreamTimeoutMs !== undefined ||\n bodyTimeoutMs !== undefined ||\n maxProxyBufferBytes !== undefined ||\n maxProxyBufferFrames !== undefined\n ) {\n logger.warn(\n \"--upstream-timeout-ms/--body-timeout-ms/--max-proxy-buffer-bytes/--max-proxy-buffer-frames only apply to --record/--proxy-only upstream proxying — ignored without one of those flags.\",\n );\n }\n}\n\n// Parse AG-UI record/proxy config from CLI flags\nlet aguiMount: { path: string; handler: AGUIMock } | undefined;\nif (values[\"agui-record\"] || values[\"agui-proxy-only\"]) {\n if (!values[\"agui-upstream\"]) {\n console.error(\"Error: --agui-record/--agui-proxy-only requires --agui-upstream\");\n process.exit(1);\n }\n // --agui-record writes recorded AG-UI fixtures to disk, so a URL source is unsupported.\n // --agui-proxy-only forwards without saving, so URL-only --fixtures is valid.\n const aguiBase = fixtureValues[0];\n const aguiBaseIsUrl = /^https?:\\/\\//i.test(aguiBase);\n if (values[\"agui-record\"] && aguiBaseIsUrl) {\n console.error(\n `Error: --agui-record requires a local --fixtures path for the recording destination; got URL ${aguiBase}`,\n );\n process.exit(1);\n }\n const agui = new AGUIMock();\n agui.enableRecording({\n upstream: values[\"agui-upstream\"],\n // In proxy-only mode with a URL-only --fixtures, the AG-UI recorder never\n // writes to disk (see agui-recorder.ts). Leave fixturePath undefined rather\n // than resolving a URL as a filesystem path.\n fixturePath: aguiBaseIsUrl ? undefined : resolve(aguiBase, \"agui-recorded\"),\n proxyOnly: values[\"agui-proxy-only\"],\n });\n aguiMount = { path: \"/agui\", handler: agui };\n}\n\n// Parse MCP record/proxy mounts (MR1, AM6): --mcp-record / --mcp-proxy-only <mount>=<url>\nconst mcpRecordMounts: { path: string; handler: MCPMock }[] = [];\n{\n const recordValues = values[\"mcp-record\"] ?? [];\n const proxyValues = values[\"mcp-proxy-only\"] ?? [];\n if (recordValues.length > 0) {\n // C11: check the flag itself; fixtureValues defaults to ./fixtures.\n if (!(values.fixtures && values.fixtures.length > 0)) {\n console.error(\n \"Error: --mcp-record requires --fixtures <local path> for the recording destination\",\n );\n process.exit(1);\n }\n if (/^https?:\\/\\//i.test(values.fixtures[0])) {\n console.error(\n `Error: --mcp-record requires a local --fixtures path for the recording destination; got URL ${values.fixtures[0]}`,\n );\n process.exit(1);\n }\n }\n const flags = [\n ...recordValues.map((value) => ({ flag: \"--mcp-record\", value, proxyOnly: false })),\n ...proxyValues.map((value) => ({ flag: \"--mcp-proxy-only\", value, proxyOnly: true })),\n ];\n if (flags.length > 0) {\n let env: ReturnType<typeof mcpRecordEnv>;\n try {\n env = mcpRecordEnv(process.env);\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n for (const { flag, value, proxyOnly } of flags) {\n try {\n const { mount, upstream } = parseMcpRecordFlag(value, flag);\n if (aguiMount && mount === aguiMount.path) {\n throw new Error(`${flag} mount ${mount} is held by a mount that is not an MCP mock`);\n }\n if (mcpRecordMounts.some((m) => m.path === mount)) {\n throw new Error(`${flag} mount ${mount} is given more than once`);\n }\n const mcp = new MCPMock().enableRecording({\n upstream,\n fixturePath: proxyOnly ? undefined : resolve(values.fixtures![0], \"recorded\"),\n proxyOnly,\n secretValues: env.secretValues,\n upstreamAuth: env.upstreamAuth,\n strict: values.strict,\n });\n mcpRecordMounts.push({ path: mount, handler: mcp });\n } catch (err) {\n console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n }\n }\n}\n\ninterface ResolvedFixtureSource {\n source: string;\n path: string;\n isDir: boolean;\n}\n\nasync function resolveAllFixtureSources(): Promise<ResolvedFixtureSource[]> {\n const resolved: ResolvedFixtureSource[] = [];\n for (const value of fixtureValues) {\n let local;\n try {\n local = await resolveFixturesValue(value, {\n validateOnLoad,\n logger,\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`Failed to resolve --fixtures value \"${value}\": ${msg}`);\n process.exit(1);\n }\n if (!local.path) {\n // Remote fetch failed without validate-on-load and no cache — already warned; skip.\n continue;\n }\n try {\n const stat = statSync(local.path);\n resolved.push({ source: local.source, path: local.path, isDir: stat.isDirectory() });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n console.error(`Fixtures path not found: ${local.path}`);\n } else {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`Failed to load fixtures from ${local.path}: ${msg}`);\n }\n process.exit(1);\n }\n }\n return resolved;\n}\n\n// F3: the loaders that carry `mcpFakes`. A file's entry-id source (I6) is the\n// --fixtures value as given: the path, or the URL of a remote file (whose\n// `path` is the on-disk cache).\nfunction loadSource(source: ResolvedFixtureSource): FixturesWithServices {\n const loaded = source.isDir\n ? loadFixturesFromDirWithServices(source.path, logger)\n : loadFixtureFileWithServices(source.path, logger, undefined, source.source);\n // --misbehavior: a bad fixture `misbehavior` key fails the load; without it the key is ignored.\n if (values.misbehavior) loaded.fixtures.forEach(enableHeldFixtureMisbehavior);\n return loaded;\n}\n\n/** Each source's `mcpFakes` blocks, in load order, for the --watch comparison. */\nfunction fakesBySource(blocks: McpFakeSource[]): Map<string, unknown[]> {\n const bySource = new Map<string, unknown[]>();\n for (const block of blocks) {\n const list = bySource.get(block.source) ?? [];\n list.push([block.blockIndex, block.raw]);\n bySource.set(block.source, list);\n }\n return bySource;\n}\n\n/**\n * R9/F11: fakes are not reloaded by --watch, so a reload whose `mcpFakes`\n * differ from the boot set is rejected. Returns the first changed source.\n * A source in `unreadable` could not be read or parsed: it is not compared,\n * because its blocks are unknown, not removed.\n */\nfunction changedFakesSource(\n boot: McpFakeSource[],\n reload: McpFakeSource[],\n unreadable: ReadonlySet<string>,\n): string | null {\n const before = fakesBySource(boot);\n const after = fakesBySource(reload);\n for (const source of new Set([...before.keys(), ...after.keys()])) {\n if (unreadable.has(source)) continue;\n if (!isDeepStrictEqual(before.get(source), after.get(source))) return source;\n }\n return null;\n}\n\n/**\n * L3: a load error on stderr, whatever the log level: every error of a\n * `McpFakesAddError`, one per line, then its L8 warnings.\n */\nfunction printLoadError(err: FixtureLoadError | MisbehaviorConfigError): void {\n const errors = err instanceof McpFakesAddError ? err.errors : [err];\n for (const e of errors) console.error(e.message);\n if (err instanceof McpFakesAddError) {\n for (const w of err.warnings) console.warn(w.message);\n }\n}\n\n/** A --watch reload that `loadFn` rejected and already printed (L3, L7). */\nclass ReloadRejected extends Error {}\n\n/**\n * The --watch logger: as `Logger`, except that the watcher's own report of a\n * {@link ReloadRejected} reload is dropped, so the error is printed once.\n */\nclass WatchLogger extends Logger {\n override error(...args: unknown[]): void {\n if (args.some((a) => a instanceof ReloadRejected)) return;\n super.error(...args);\n }\n}\n\n/**\n * MR13: --watch with record mounts. (a) An event for a recorder temp file, or\n * for a file whose bytes are exactly what a recorder last wrote there, does\n * not reload; everything else (a delete, a directory, a user edit) reloads as\n * on main. (b) Each recorder write moves the --watch baseline of that file,\n * so the next reload does not reject the recording as a changed `mcpFakes`.\n * Without record mounts (or for a file source), --watch is exactly as on main.\n */\nfunction recorderWatch(\n primary: ResolvedFixtureSource,\n moveBaseline: (moved: (boot: McpFakeSource[]) => McpFakeSource[]) => void,\n): { ignore?: (absPath: string) => boolean } {\n const events = mcpRecordMounts.map((m) => m.handler.recorderEvents()).filter((ev) => ev !== null);\n if (events.length === 0 || !primary.isDir) return {};\n for (const ev of events) {\n ev.onWrite((file, written) => {\n const source = relative(primary.path, file).split(sep).join(\"/\");\n const blocks: McpFakeSource[] = Array.isArray(written)\n ? written.map((raw, blockIndex) => ({ source, blockIndex, raw }))\n : [{ source, blockIndex: null, raw: written }];\n moveBaseline((boot) => {\n // Replace this source's blocks in place; a new source goes last.\n const others = boot.filter((b) => b.source !== source);\n const at = boot.findIndex((b) => b.source === source);\n const pos = at === -1 ? others.length : at;\n return [...others.slice(0, pos), ...blocks, ...others.slice(pos)];\n });\n });\n }\n return {\n ignore: (absPath: string): boolean => {\n // Recorder temp files only (persistServiceFakes writes `<file>.tmp.<uuid>`, then renames it).\n if (/\\.tmp\\.[0-9a-f-]+$/i.test(absPath)) return true;\n let st: Stats;\n try {\n st = statSync(absPath);\n } catch {\n return false; // gone: a user deleted a fixture — this MUST reload (r2 N2)\n }\n if (st.isDirectory()) return false; // directory events behave as on main\n let data: Buffer;\n try {\n data = readFileSync(absPath);\n } catch {\n return false;\n }\n const hash = createHash(\"sha256\").update(data).digest(\"hex\");\n return events.some((ev) => ev.lastWrittenHash(absPath) === hash);\n },\n };\n}\n\nasync function main() {\n const sources = await resolveAllFixtureSources();\n\n const fixtures: Fixture[] = [];\n const mcpFakes: McpFakeSource[] = [];\n // The primary source's blocks: what a --watch reload of it is compared with.\n let primaryFakes: McpFakeSource[] = [];\n for (const src of sources) {\n const loaded = loadSource(src);\n fixtures.push(...loaded.fixtures);\n mcpFakes.push(...loaded.mcpFakes);\n if (src === sources[0]) primaryFakes = loaded.mcpFakes;\n }\n\n if (fixtures.length === 0 && mcpFakes.length > 0) {\n // F5/L9: fake blocks count as loaded; only LLM requests have nothing to match.\n console.warn(build(msg`Warning: No LLM fixtures loaded; LLM requests will return 404`));\n } else if (fixtures.length === 0) {\n if (validateOnLoad || values.strict) {\n console.error(\"Error: No fixtures loaded and validation/strict mode is enabled — aborting.\");\n process.exit(1);\n }\n console.warn(\"Warning: No fixtures loaded. The server will return 404 for all requests.\");\n }\n\n const sourceLabel = sources.map((s) => s.source).join(\", \") || \"<none>\";\n logger.info(`Loaded ${fixtures.length} fixture(s) from ${sourceLabel}`);\n\n // Validate fixtures if requested\n if (validateOnLoad) {\n if (responsesTools === \"extended\") fixtures.forEach(markFixtureResponsesToolsExtended);\n const results = validateFixtures(fixtures);\n const errors = results.filter((r) => r.severity === \"error\");\n const warnings = results.filter((r) => r.severity === \"warning\");\n\n for (const w of warnings) {\n logger.warn(`Fixture ${w.fixtureIndex}: ${w.message}`);\n }\n // L8 (shadowed mcpFakes entries) is not printed here: the hand-off in\n // createServer prints it on every start.\n for (const e of errors) {\n logger.error(`Fixture ${e.fixtureIndex}: ${e.message}`);\n }\n\n if (errors.length > 0) {\n console.error(`Validation failed: ${errors.length} error(s), ${warnings.length} warning(s)`);\n process.exit(1);\n }\n }\n\n const allMounts: { path: string; handler: Mountable }[] = [\n ...(aguiMount ? [aguiMount] : []),\n ...mcpRecordMounts,\n ];\n const mounts = allMounts.length > 0 ? allMounts : undefined;\n\n const instance = await createServer(\n fixtures,\n {\n port,\n host,\n latency,\n chunkSize,\n replaySpeed,\n logLevel,\n chaos,\n metrics: values.metrics,\n record,\n strict: values.strict,\n policy,\n strictToolArguments: values[\"strict-tool-arguments\"],\n enableMisbehavior: values.misbehavior,\n ...(responsesTools !== undefined ? { responsesTools } : {}),\n journalMaxEntries: journalMax,\n fixtureCountsMaxTestIds: fixtureCountsMax,\n auth: resolveInboundAuth(selectInboundAuthSource(undefined)).publicConfig,\n },\n mounts,\n { search: [], rerank: [], moderation: [], mcpFakes },\n );\n\n // Only the first local source is watched — remote URL sources are fetched once\n // at boot and are not monitored. Declared before the readiness announcement so\n // shutdown can close it whenever the signal arrives.\n let watcher: { close: () => void } | null = null;\n\n function shutdown() {\n logger.info(\"Shutting down...\");\n if (watcher) watcher.close();\n instance.server.close(() => {\n process.exit(0);\n });\n }\n\n // Register BEFORE announcing readiness. Writes to a pipe are synchronous on Linux\n // (and to a file on every POSIX platform), so a supervisor that reacts to the line\n // below can deliver SIGTERM while this process is still mid-statement. Announcing\n // first left a window in which SIGTERM hit Node's default disposition, which\n // re-raises: the process died with a null exit code instead of shutting down.\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n logger.info(`aimock server listening on ${instance.url}`);\n\n // Start file watcher if requested.\n if (watchMode) {\n const primary = sources[0];\n if (!primary) {\n logger.warn(\"--watch requested but no resolvable fixture sources; skipping watcher\");\n } else {\n // A rejected reload is printed here, whatever the log level, then\n // thrown as ReloadRejected: watchFixtures keeps the previous fixtures,\n // and its WatchLogger does not print the error a second time.\n const reject = (err: FixtureLoadError | MisbehaviorConfigError): never => {\n printLoadError(err);\n throw new ReloadRejected(build(msg`--watch reload rejected`));\n };\n const loadFn = (): Fixture[] => {\n let loaded: FixturesWithServices;\n try {\n loaded = loadSource(primary);\n } catch (err) {\n // L3: a bad block in the reloaded file.\n if (err instanceof FixtureLoadError || err instanceof MisbehaviorConfigError) {\n return reject(err);\n }\n throw err;\n }\n const changed = changedFakesSource(\n primaryFakes,\n loaded.mcpFakes,\n new Set(loaded.unreadable),\n );\n if (changed !== null) {\n // L7.\n return reject(\n new FixtureLoadError({\n rule: \"mcp-fakes/watch-reload-changed\",\n file: changed,\n detail: msg`mcpFakes changed on --watch reload; MCP fakes are not reloaded, so the whole reload is rejected and the previous fixtures stay loaded. Restart aimock to load the new fakes`,\n }),\n );\n }\n if (responsesTools === \"extended\") {\n loaded.fixtures.forEach(markFixtureResponsesToolsExtended);\n }\n return loaded.fixtures;\n };\n watcher = watchFixtures(primary.path, fixtures, loadFn, {\n logger: new WatchLogger(logLevel),\n validate: validateOnLoad,\n validateFn: validateFixtures,\n ...recorderWatch(primary, (moved) => (primaryFakes = moved(primaryFakes))),\n });\n logger.info(`Watching ${primary.path} for changes`);\n }\n }\n}\n\nmain().catch((err) => {\n if (err instanceof FixtureLoadError || err instanceof MisbehaviorConfigError) {\n printLoadError(err);\n } else {\n console.error(err);\n }\n process.exit(1);\n});\n"],"mappings":"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"}
package/dist/cohere.cjs CHANGED
@@ -1,3 +1,5 @@
1
+ const require_errors = require('./response/errors.cjs');
2
+ const require_policy = require('./response/policy.cjs');
1
3
  const require_helpers = require('./helpers.cjs');
2
4
  const require_sse_writer = require('./sse-writer.cjs');
3
5
  const require_chaos = require('./chaos.cjs');
@@ -5,43 +7,16 @@ const require_misbehavior = require('./misbehavior.cjs');
5
7
  const require_router = require('./router.cjs');
6
8
  const require_recorder = require('./recorder.cjs');
7
9
  const require_interruption = require('./interruption.cjs');
10
+ const require_finish = require('./response/finish.cjs');
11
+ const require_cohere = require('./response/usage/codecs/cohere.cjs');
8
12
 
9
13
  //#region src/cohere.ts
10
- const ZERO_USAGE = {
11
- billed_units: {
12
- input_tokens: 0,
13
- output_tokens: 0,
14
- search_units: 0,
15
- classifications: 0
16
- },
17
- tokens: {
18
- input_tokens: 0,
19
- output_tokens: 0
20
- }
21
- };
22
14
  function cohereFinishReason(overrideFinishReason, defaultReason) {
23
15
  if (!overrideFinishReason) return defaultReason;
24
- if (overrideFinishReason === "stop") return "COMPLETE";
25
- if (overrideFinishReason === "tool_calls") return "TOOL_CALL";
26
- if (overrideFinishReason === "length") return "MAX_TOKENS";
27
- return overrideFinishReason;
16
+ return require_finish.mapCohereFinish(overrideFinishReason);
28
17
  }
29
18
  function cohereUsage(overrides) {
30
- if (!overrides?.usage) return ZERO_USAGE;
31
- const inputTokens = overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? 0;
32
- const outputTokens = overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? 0;
33
- return {
34
- billed_units: {
35
- input_tokens: inputTokens,
36
- output_tokens: outputTokens,
37
- search_units: 0,
38
- classifications: 0
39
- },
40
- tokens: {
41
- input_tokens: inputTokens,
42
- output_tokens: outputTokens
43
- }
44
- };
19
+ return require_cohere.render(overrides);
45
20
  }
46
21
  /** Extract plain text from structured content (array of { type, text } parts) or passthrough string. */
47
22
  function extractTextContent(content) {
@@ -576,10 +551,10 @@ async function handleCohere(req, res, raw, fixtures, journal, defaults, setCorsH
576
551
  fixture: null
577
552
  }
578
553
  });
579
- require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
554
+ require_sse_writer.writeErrorResponse(res, 400, require_errors.renderError("cohere", "validation", {
580
555
  message: `Malformed JSON body: ${detail}`,
581
556
  type: "invalid_request_error"
582
- } }));
557
+ }).body);
583
558
  return;
584
559
  }
585
560
  if (!require_helpers.isJsonObject(cohereReq)) {
@@ -593,10 +568,10 @@ async function handleCohere(req, res, raw, fixtures, journal, defaults, setCorsH
593
568
  fixture: null
594
569
  }
595
570
  });
596
- require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
571
+ require_sse_writer.writeErrorResponse(res, 400, require_errors.renderError("cohere", "validation", {
597
572
  message: "Request body must be a JSON object",
598
573
  type: "invalid_request_error"
599
- } }));
574
+ }).body);
600
575
  return;
601
576
  }
602
577
  if (!cohereReq.model) {
@@ -610,10 +585,10 @@ async function handleCohere(req, res, raw, fixtures, journal, defaults, setCorsH
610
585
  fixture: null
611
586
  }
612
587
  });
613
- require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
588
+ require_sse_writer.writeErrorResponse(res, 400, require_errors.renderError("cohere", "validation", {
614
589
  message: "model is required",
615
590
  type: "invalid_request_error"
616
- } }));
591
+ }).body);
617
592
  return;
618
593
  }
619
594
  let shapeError = require_helpers.validateChatMessages(cohereReq.messages) ?? require_helpers.validateToolsField(cohereReq.tools);
@@ -632,10 +607,10 @@ async function handleCohere(req, res, raw, fixtures, journal, defaults, setCorsH
632
607
  fixture: null
633
608
  }
634
609
  });
635
- require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
610
+ require_sse_writer.writeErrorResponse(res, 400, require_errors.renderError("cohere", "validation", {
636
611
  message: `Invalid request: ${shapeError}`,
637
612
  type: "invalid_request_error"
638
- } }));
613
+ }).body);
639
614
  return;
640
615
  }
641
616
  const completionReq = cohereToCompletionRequest(cohereReq);
@@ -654,7 +629,7 @@ async function handleCohere(req, res, raw, fixtures, journal, defaults, setCorsH
654
629
  body: completionReq
655
630
  }, fixture ? "fixture" : "proxy", defaults.registry, defaults.logger)) return;
656
631
  if (!fixture) {
657
- if (require_helpers.resolveStrictMode(defaults.strict, req.headers)) {
632
+ if (require_policy.resolveRequestDecisions(defaults.strict, req.headers).fixtureMiss) {
658
633
  const strictStatus = 503;
659
634
  const strictMessage = require_helpers.strictNoMatchMessage(skippedBySequenceOrTurn);
660
635
  logger.error(require_helpers.strictNoMatchLogLine(req.method ?? "POST", req.url ?? "/v2/chat", skippedBySequenceOrTurn));
@@ -666,13 +641,13 @@ async function handleCohere(req, res, raw, fixtures, journal, defaults, setCorsH
666
641
  response: {
667
642
  status: strictStatus,
668
643
  fixture: null,
669
- ...require_helpers.strictOverrideField(defaults.strict, req.headers)
644
+ ...require_policy.strictOverrideField(defaults.strict, req.headers)
670
645
  }
671
646
  });
672
- require_sse_writer.writeErrorResponse(res, strictStatus, JSON.stringify({ error: {
647
+ require_sse_writer.writeErrorResponse(res, strictStatus, require_errors.renderError("cohere", "strict-miss", {
673
648
  message: strictMessage,
674
649
  type: "invalid_request_error"
675
- } }));
650
+ }).body);
676
651
  return;
677
652
  }
678
653
  if (defaults.record) {
@@ -701,13 +676,13 @@ async function handleCohere(req, res, raw, fixtures, journal, defaults, setCorsH
701
676
  response: {
702
677
  status: 404,
703
678
  fixture: null,
704
- ...require_helpers.strictOverrideField(defaults.strict, req.headers)
679
+ ...require_policy.strictOverrideField(defaults.strict, req.headers)
705
680
  }
706
681
  });
707
- require_sse_writer.writeErrorResponse(res, 404, JSON.stringify({ error: {
682
+ require_sse_writer.writeErrorResponse(res, 404, require_errors.renderError("cohere", "fixture-miss", {
708
683
  message: "No fixture matched",
709
684
  type: "invalid_request_error"
710
- } }));
685
+ }).body);
711
686
  return;
712
687
  }
713
688
  const resolvedResponse = await require_helpers.resolveResponse(fixture, completionReq);
@@ -739,15 +714,15 @@ async function handleCohere(req, res, raw, fixtures, journal, defaults, setCorsH
739
714
  testId
740
715
  });
741
716
  if (!misbehavior.summary?.evaluations.length) logger.error(misbehavior.message);
742
- require_sse_writer.writeErrorResponse(res, misbehavior.status, JSON.stringify({
717
+ require_sse_writer.writeErrorResponse(res, misbehavior.status, require_errors.renderError("cohere", "misbehavior", {
743
718
  message: misbehavior.message,
744
719
  code: misbehavior.code
745
- }));
720
+ }).body);
746
721
  return;
747
722
  }
748
723
  const prepared = misbehavior.kind === "applied" ? require_helpers.prepareOpenAIChatMisbehavior(misbehavior) : void 0;
749
724
  const observedK5Stream = cohereReq.stream === true && prepared?.summary.fault === "stop-length-mid-tool";
750
- const appliedReasoning = prepared && "reasoning" in prepared.response ? require_helpers.resolveReasoningForModel(prepared.response.reasoning, cohereReq.model, require_helpers.resolveStrictMode(defaults.strict, req.headers), logger) : void 0;
725
+ const appliedReasoning = prepared && "reasoning" in prepared.response ? require_helpers.resolveReasoningForModel(prepared.response.reasoning, cohereReq.model, require_policy.resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression, logger) : void 0;
751
726
  const usage = prepared ? require_helpers.resolveOpenAIChatMisbehaviorUsage(prepared, completionReq, appliedReasoning !== void 0) : void 0;
752
727
  const response = prepared && usage ? {
753
728
  ...prepared.response,
@@ -775,13 +750,13 @@ async function handleCohere(req, res, raw, fixtures, journal, defaults, setCorsH
775
750
  defaults,
776
751
  testId
777
752
  });
778
- require_sse_writer.writeErrorResponse(res, status, require_helpers.serializeErrorResponse(response), { retryAfter: response.retryAfter });
753
+ require_sse_writer.writeErrorResponse(res, status, require_errors.renderError("openai", "fixture", response.error).body, { retryAfter: response.retryAfter });
779
754
  return;
780
755
  }
781
756
  if (require_helpers.isCombinedFixtureResponse(response)) {
782
757
  if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Cohere v2 Chat API — ignoring");
783
758
  const overrides = require_helpers.extractOverrides(response);
784
- const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
759
+ const effectiveStrict = require_policy.resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression;
785
760
  const effReasoning = prepared ? appliedReasoning : require_helpers.resolveReasoningForModel(response.reasoning, cohereReq.model, effectiveStrict, logger);
786
761
  const journalEntry = journal.add({
787
762
  method: req.method ?? "POST",
@@ -827,7 +802,7 @@ async function handleCohere(req, res, raw, fixtures, journal, defaults, setCorsH
827
802
  if (require_helpers.isTextResponse(response)) {
828
803
  if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Cohere v2 Chat API — ignoring");
829
804
  const overrides = require_helpers.extractOverrides(response);
830
- const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
805
+ const effectiveStrict = require_policy.resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression;
831
806
  const effReasoning = prepared ? appliedReasoning : require_helpers.resolveReasoningForModel(response.reasoning, cohereReq.model, effectiveStrict, logger);
832
807
  const journalEntry = journal.add({
833
808
  method: req.method ?? "POST",
@@ -881,7 +856,7 @@ async function handleCohere(req, res, raw, fixtures, journal, defaults, setCorsH
881
856
  if (require_helpers.isToolCallResponse(response)) {
882
857
  if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Cohere v2 Chat API — ignoring");
883
858
  const overrides = require_helpers.extractOverrides(response);
884
- const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
859
+ const effectiveStrict = require_policy.resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression;
885
860
  const effReasoning = prepared ? appliedReasoning : require_helpers.resolveReasoningForModel(response.reasoning, cohereReq.model, effectiveStrict, logger);
886
861
  const journalEntry = journal.add({
887
862
  method: req.method ?? "POST",
@@ -939,10 +914,10 @@ async function handleCohere(req, res, raw, fixtures, journal, defaults, setCorsH
939
914
  defaults,
940
915
  testId
941
916
  });
942
- require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
917
+ require_sse_writer.writeErrorResponse(res, 500, require_errors.renderError("cohere", "unknown-response", {
943
918
  message: "Fixture response did not match any known type",
944
919
  type: "server_error"
945
- } }));
920
+ }).body);
946
921
  }
947
922
  async function handleCohereEmbed(req, res, raw, fixtures, journal, defaults, setCorsHeaders) {
948
923
  const { logger } = defaults;
@@ -962,10 +937,10 @@ async function handleCohereEmbed(req, res, raw, fixtures, journal, defaults, set
962
937
  fixture: null
963
938
  }
964
939
  });
965
- require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
940
+ require_sse_writer.writeErrorResponse(res, 400, require_errors.renderError("cohere", "validation", {
966
941
  message: `Malformed JSON body: ${detail}`,
967
942
  type: "invalid_request_error"
968
- } }));
943
+ }).body);
969
944
  return;
970
945
  }
971
946
  if (!require_helpers.isJsonObject(embedReq)) {
@@ -979,10 +954,10 @@ async function handleCohereEmbed(req, res, raw, fixtures, journal, defaults, set
979
954
  fixture: null
980
955
  }
981
956
  });
982
- require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
957
+ require_sse_writer.writeErrorResponse(res, 400, require_errors.renderError("cohere", "validation", {
983
958
  message: "Request body must be a JSON object",
984
959
  type: "invalid_request_error"
985
- } }));
960
+ }).body);
986
961
  return;
987
962
  }
988
963
  if (!embedReq.model) {
@@ -996,10 +971,10 @@ async function handleCohereEmbed(req, res, raw, fixtures, journal, defaults, set
996
971
  fixture: null
997
972
  }
998
973
  });
999
- require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
974
+ require_sse_writer.writeErrorResponse(res, 400, require_errors.renderError("cohere", "validation", {
1000
975
  message: "model is required",
1001
976
  type: "invalid_request_error"
1002
- } }));
977
+ }).body);
1003
978
  return;
1004
979
  }
1005
980
  if (!embedReq.texts || !Array.isArray(embedReq.texts)) {
@@ -1013,10 +988,10 @@ async function handleCohereEmbed(req, res, raw, fixtures, journal, defaults, set
1013
988
  fixture: null
1014
989
  }
1015
990
  });
1016
- require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
991
+ require_sse_writer.writeErrorResponse(res, 400, require_errors.renderError("cohere", "validation", {
1017
992
  message: "Invalid request: texts array is required",
1018
993
  type: "invalid_request_error"
1019
- } }));
994
+ }).body);
1020
995
  return;
1021
996
  }
1022
997
  if (!embedReq.texts.every((text) => typeof text === "string")) {
@@ -1030,10 +1005,10 @@ async function handleCohereEmbed(req, res, raw, fixtures, journal, defaults, set
1030
1005
  fixture: null
1031
1006
  }
1032
1007
  });
1033
- require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
1008
+ require_sse_writer.writeErrorResponse(res, 400, require_errors.renderError("cohere", "validation", {
1034
1009
  message: "Invalid request: texts must be an array of strings",
1035
1010
  type: "invalid_request_error"
1036
- } }));
1011
+ }).body);
1037
1012
  return;
1038
1013
  }
1039
1014
  const combinedInput = embedReq.texts.join(" ");
@@ -1071,10 +1046,10 @@ async function handleCohereEmbed(req, res, raw, fixtures, journal, defaults, set
1071
1046
  fixture: fixture ?? null
1072
1047
  }
1073
1048
  });
1074
- require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
1049
+ require_sse_writer.writeErrorResponse(res, 400, require_errors.renderError("cohere", "validation", {
1075
1050
  message: isArray ? "Invalid request: embedding_types must be an array of strings" : "Invalid request: embedding_types must be an array",
1076
1051
  type: "invalid_request_error"
1077
- } }));
1052
+ }).body);
1078
1053
  return true;
1079
1054
  }
1080
1055
  if (fixture) {
@@ -1091,7 +1066,7 @@ async function handleCohereEmbed(req, res, raw, fixtures, journal, defaults, set
1091
1066
  fixture
1092
1067
  }
1093
1068
  });
1094
- require_sse_writer.writeErrorResponse(res, status, require_helpers.serializeErrorResponse(response), { retryAfter: response.retryAfter });
1069
+ require_sse_writer.writeErrorResponse(res, status, require_errors.renderError("openai", "fixture", response.error).body, { retryAfter: response.retryAfter });
1095
1070
  return;
1096
1071
  }
1097
1072
  if (require_helpers.isEmbeddingResponse(response)) {
@@ -1129,13 +1104,13 @@ async function handleCohereEmbed(req, res, raw, fixtures, journal, defaults, set
1129
1104
  fixture
1130
1105
  }
1131
1106
  });
1132
- require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
1107
+ require_sse_writer.writeErrorResponse(res, 500, require_errors.renderError("cohere", "unknown-response", {
1133
1108
  message: "Fixture response did not match any known embedding type (must have embedding or error)",
1134
1109
  type: "server_error"
1135
- } }));
1110
+ }).body);
1136
1111
  return;
1137
1112
  }
1138
- if (require_helpers.resolveStrictMode(defaults.strict, req.headers)) {
1113
+ if (require_policy.resolveRequestDecisions(defaults.strict, req.headers).fixtureMiss) {
1139
1114
  const strictMessage = require_helpers.strictNoMatchMessage(skippedBySequenceOrTurn);
1140
1115
  logger.error(require_helpers.strictNoMatchLogLine(req.method ?? "POST", req.url ?? "/v2/embed", skippedBySequenceOrTurn));
1141
1116
  journal.add({
@@ -1146,13 +1121,13 @@ async function handleCohereEmbed(req, res, raw, fixtures, journal, defaults, set
1146
1121
  response: {
1147
1122
  status: 503,
1148
1123
  fixture: null,
1149
- ...require_helpers.strictOverrideField(defaults.strict, req.headers)
1124
+ ...require_policy.strictOverrideField(defaults.strict, req.headers)
1150
1125
  }
1151
1126
  });
1152
- require_sse_writer.writeErrorResponse(res, 503, JSON.stringify({ error: {
1127
+ require_sse_writer.writeErrorResponse(res, 503, require_errors.renderError("cohere", "strict-miss", {
1153
1128
  message: strictMessage,
1154
1129
  type: "invalid_request_error"
1155
- } }));
1130
+ }).body);
1156
1131
  return;
1157
1132
  }
1158
1133
  if (defaults.record) {