@copilotkit/aimock 1.42.1 → 1.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (338) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +50 -0
  4. package/README.md +102 -16
  5. package/dist/agui-mock.cjs +1 -1
  6. package/dist/agui-mock.cjs.map +1 -1
  7. package/dist/agui-mock.d.cts.map +1 -1
  8. package/dist/agui-mock.d.ts.map +1 -1
  9. package/dist/agui-mock.js +1 -1
  10. package/dist/agui-mock.js.map +1 -1
  11. package/dist/agui-recorder.cjs +33 -11
  12. package/dist/agui-recorder.cjs.map +1 -1
  13. package/dist/agui-recorder.d.cts +10 -1
  14. package/dist/agui-recorder.d.cts.map +1 -1
  15. package/dist/agui-recorder.d.ts +10 -1
  16. package/dist/agui-recorder.d.ts.map +1 -1
  17. package/dist/agui-recorder.js +33 -11
  18. package/dist/agui-recorder.js.map +1 -1
  19. package/dist/agui-types.d.cts +1 -0
  20. package/dist/agui-types.d.cts.map +1 -1
  21. package/dist/agui-types.d.ts +1 -0
  22. package/dist/agui-types.d.ts.map +1 -1
  23. package/dist/aimock-cli.cjs +38 -10
  24. package/dist/aimock-cli.cjs.map +1 -1
  25. package/dist/aimock-cli.d.cts +5 -0
  26. package/dist/aimock-cli.d.cts.map +1 -1
  27. package/dist/aimock-cli.d.ts +5 -0
  28. package/dist/aimock-cli.d.ts.map +1 -1
  29. package/dist/aimock-cli.js +38 -10
  30. package/dist/aimock-cli.js.map +1 -1
  31. package/dist/batches.cjs +458 -0
  32. package/dist/batches.cjs.map +1 -0
  33. package/dist/batches.d.cts +57 -0
  34. package/dist/batches.d.cts.map +1 -0
  35. package/dist/batches.d.ts +57 -0
  36. package/dist/batches.d.ts.map +1 -0
  37. package/dist/batches.js +453 -0
  38. package/dist/batches.js.map +1 -0
  39. package/dist/bedrock-converse.cjs +12 -8
  40. package/dist/bedrock-converse.cjs.map +1 -1
  41. package/dist/bedrock-converse.d.cts.map +1 -1
  42. package/dist/bedrock-converse.d.ts.map +1 -1
  43. package/dist/bedrock-converse.js +14 -10
  44. package/dist/bedrock-converse.js.map +1 -1
  45. package/dist/bedrock.cjs +10 -8
  46. package/dist/bedrock.cjs.map +1 -1
  47. package/dist/bedrock.d.cts.map +1 -1
  48. package/dist/bedrock.d.ts.map +1 -1
  49. package/dist/bedrock.js +12 -10
  50. package/dist/bedrock.js.map +1 -1
  51. package/dist/byteplus-video.cjs +3 -3
  52. package/dist/byteplus-video.cjs.map +1 -1
  53. package/dist/byteplus-video.js +4 -4
  54. package/dist/byteplus-video.js.map +1 -1
  55. package/dist/chaos.cjs +622 -72
  56. package/dist/chaos.cjs.map +1 -1
  57. package/dist/chaos.d.cts +164 -7
  58. package/dist/chaos.d.cts.map +1 -1
  59. package/dist/chaos.d.ts +164 -7
  60. package/dist/chaos.d.ts.map +1 -1
  61. package/dist/chaos.js +613 -74
  62. package/dist/chaos.js.map +1 -1
  63. package/dist/cli.cjs +42 -23
  64. package/dist/cli.cjs.map +1 -1
  65. package/dist/cli.js +42 -23
  66. package/dist/cli.js.map +1 -1
  67. package/dist/cohere.cjs +10 -8
  68. package/dist/cohere.cjs.map +1 -1
  69. package/dist/cohere.d.cts.map +1 -1
  70. package/dist/cohere.d.ts.map +1 -1
  71. package/dist/cohere.js +12 -10
  72. package/dist/cohere.js.map +1 -1
  73. package/dist/config-loader.d.ts.map +1 -1
  74. package/dist/convert.cjs +1 -1
  75. package/dist/convert.cjs.map +1 -1
  76. package/dist/convert.js +1 -1
  77. package/dist/convert.js.map +1 -1
  78. package/dist/elevenlabs-audio.cjs +3 -3
  79. package/dist/elevenlabs-audio.cjs.map +1 -1
  80. package/dist/elevenlabs-audio.js +4 -4
  81. package/dist/elevenlabs-audio.js.map +1 -1
  82. package/dist/elevenlabs-voice.cjs +1053 -0
  83. package/dist/elevenlabs-voice.cjs.map +1 -0
  84. package/dist/elevenlabs-voice.d.cts +72 -0
  85. package/dist/elevenlabs-voice.d.cts.map +1 -0
  86. package/dist/elevenlabs-voice.d.ts +72 -0
  87. package/dist/elevenlabs-voice.d.ts.map +1 -0
  88. package/dist/elevenlabs-voice.js +1048 -0
  89. package/dist/elevenlabs-voice.js.map +1 -0
  90. package/dist/embeddings.cjs +8 -4
  91. package/dist/embeddings.cjs.map +1 -1
  92. package/dist/embeddings.d.cts.map +1 -1
  93. package/dist/embeddings.d.ts.map +1 -1
  94. package/dist/embeddings.js +9 -5
  95. package/dist/embeddings.js.map +1 -1
  96. package/dist/fal-audio.cjs +3 -3
  97. package/dist/fal-audio.cjs.map +1 -1
  98. package/dist/fal-audio.js +4 -4
  99. package/dist/fal-audio.js.map +1 -1
  100. package/dist/fal.cjs +28 -4
  101. package/dist/fal.cjs.map +1 -1
  102. package/dist/fal.d.cts +16 -1
  103. package/dist/fal.d.cts.map +1 -1
  104. package/dist/fal.d.ts +16 -1
  105. package/dist/fal.d.ts.map +1 -1
  106. package/dist/fal.js +28 -5
  107. package/dist/fal.js.map +1 -1
  108. package/dist/files.cjs +1071 -0
  109. package/dist/files.cjs.map +1 -0
  110. package/dist/files.d.cts +68 -0
  111. package/dist/files.d.cts.map +1 -0
  112. package/dist/files.d.ts +68 -0
  113. package/dist/files.d.ts.map +1 -0
  114. package/dist/files.js +1059 -0
  115. package/dist/files.js.map +1 -0
  116. package/dist/fine-tuning.cjs +1051 -0
  117. package/dist/fine-tuning.cjs.map +1 -0
  118. package/dist/fine-tuning.d.cts +96 -0
  119. package/dist/fine-tuning.d.cts.map +1 -0
  120. package/dist/fine-tuning.d.ts +96 -0
  121. package/dist/fine-tuning.d.ts.map +1 -0
  122. package/dist/fine-tuning.js +1044 -0
  123. package/dist/fine-tuning.js.map +1 -0
  124. package/dist/fixture-loader.cjs +0 -0
  125. package/dist/fixture-loader.cjs.map +1 -1
  126. package/dist/fixture-loader.d.cts +37 -5
  127. package/dist/fixture-loader.d.cts.map +1 -1
  128. package/dist/fixture-loader.d.ts +37 -5
  129. package/dist/fixture-loader.d.ts.map +1 -1
  130. package/dist/fixture-loader.js +0 -0
  131. package/dist/fixture-loader.js.map +1 -1
  132. package/dist/gemini-embeddings.cjs +2 -2
  133. package/dist/gemini-embeddings.cjs.map +1 -1
  134. package/dist/gemini-embeddings.js +3 -3
  135. package/dist/gemini-embeddings.js.map +1 -1
  136. package/dist/gemini-interactions.cjs +13 -7
  137. package/dist/gemini-interactions.cjs.map +1 -1
  138. package/dist/gemini-interactions.d.cts.map +1 -1
  139. package/dist/gemini-interactions.d.ts.map +1 -1
  140. package/dist/gemini-interactions.js +15 -9
  141. package/dist/gemini-interactions.js.map +1 -1
  142. package/dist/gemini.cjs +11 -7
  143. package/dist/gemini.cjs.map +1 -1
  144. package/dist/gemini.d.cts.map +1 -1
  145. package/dist/gemini.d.ts.map +1 -1
  146. package/dist/gemini.js +13 -9
  147. package/dist/gemini.js.map +1 -1
  148. package/dist/grok-video.cjs +14 -14
  149. package/dist/grok-video.cjs.map +1 -1
  150. package/dist/grok-video.js +15 -15
  151. package/dist/grok-video.js.map +1 -1
  152. package/dist/helpers.cjs +221 -5
  153. package/dist/helpers.cjs.map +1 -1
  154. package/dist/helpers.d.cts +38 -2
  155. package/dist/helpers.d.cts.map +1 -1
  156. package/dist/helpers.d.ts +38 -2
  157. package/dist/helpers.d.ts.map +1 -1
  158. package/dist/helpers.js +213 -6
  159. package/dist/helpers.js.map +1 -1
  160. package/dist/images.cjs +54 -123
  161. package/dist/images.cjs.map +1 -1
  162. package/dist/images.d.cts.map +1 -1
  163. package/dist/images.d.ts.map +1 -1
  164. package/dist/images.js +55 -124
  165. package/dist/images.js.map +1 -1
  166. package/dist/index.cjs +41 -8
  167. package/dist/index.d.cts +12 -7
  168. package/dist/index.d.ts +12 -7
  169. package/dist/index.js +14 -10
  170. package/dist/jest.cjs +14 -7
  171. package/dist/jest.cjs.map +1 -1
  172. package/dist/jest.d.cts +3 -2
  173. package/dist/jest.d.cts.map +1 -1
  174. package/dist/jest.d.ts +3 -2
  175. package/dist/jest.d.ts.map +1 -1
  176. package/dist/jest.js +14 -7
  177. package/dist/jest.js.map +1 -1
  178. package/dist/journal.cjs +41 -4
  179. package/dist/journal.cjs.map +1 -1
  180. package/dist/journal.d.cts +44 -3
  181. package/dist/journal.d.cts.map +1 -1
  182. package/dist/journal.d.ts +44 -3
  183. package/dist/journal.d.ts.map +1 -1
  184. package/dist/journal.js +41 -5
  185. package/dist/journal.js.map +1 -1
  186. package/dist/live-fixture.cjs +1192 -0
  187. package/dist/live-fixture.cjs.map +1 -0
  188. package/dist/live-fixture.js +1187 -0
  189. package/dist/live-fixture.js.map +1 -0
  190. package/dist/live-recorder.cjs +256 -0
  191. package/dist/live-recorder.cjs.map +1 -0
  192. package/dist/live-recorder.js +254 -0
  193. package/dist/live-recorder.js.map +1 -0
  194. package/dist/live-replay.cjs +286 -0
  195. package/dist/live-replay.cjs.map +1 -0
  196. package/dist/live-replay.js +285 -0
  197. package/dist/live-replay.js.map +1 -0
  198. package/dist/live-sanitize.cjs +196 -0
  199. package/dist/live-sanitize.cjs.map +1 -0
  200. package/dist/live-sanitize.js +196 -0
  201. package/dist/live-sanitize.js.map +1 -0
  202. package/dist/live-types.d.cts +71 -0
  203. package/dist/live-types.d.cts.map +1 -0
  204. package/dist/live-types.d.ts +71 -0
  205. package/dist/live-types.d.ts.map +1 -0
  206. package/dist/llmock.cjs +52 -41
  207. package/dist/llmock.cjs.map +1 -1
  208. package/dist/llmock.d.cts +16 -5
  209. package/dist/llmock.d.cts.map +1 -1
  210. package/dist/llmock.d.ts +16 -5
  211. package/dist/llmock.d.ts.map +1 -1
  212. package/dist/llmock.js +53 -42
  213. package/dist/llmock.js.map +1 -1
  214. package/dist/messages.cjs +11 -7
  215. package/dist/messages.cjs.map +1 -1
  216. package/dist/messages.d.cts.map +1 -1
  217. package/dist/messages.d.ts.map +1 -1
  218. package/dist/messages.js +13 -9
  219. package/dist/messages.js.map +1 -1
  220. package/dist/metrics.cjs +258 -5
  221. package/dist/metrics.cjs.map +1 -1
  222. package/dist/metrics.d.cts +3 -1
  223. package/dist/metrics.d.cts.map +1 -1
  224. package/dist/metrics.d.ts +3 -1
  225. package/dist/metrics.d.ts.map +1 -1
  226. package/dist/metrics.js +255 -6
  227. package/dist/metrics.js.map +1 -1
  228. package/dist/moderation.cjs +10 -1
  229. package/dist/moderation.cjs.map +1 -1
  230. package/dist/moderation.d.cts.map +1 -1
  231. package/dist/moderation.d.ts.map +1 -1
  232. package/dist/moderation.js +10 -1
  233. package/dist/moderation.js.map +1 -1
  234. package/dist/ollama.cjs +5 -5
  235. package/dist/ollama.cjs.map +1 -1
  236. package/dist/ollama.js +6 -6
  237. package/dist/ollama.js.map +1 -1
  238. package/dist/openrouter-video.cjs +5 -5
  239. package/dist/openrouter-video.cjs.map +1 -1
  240. package/dist/openrouter-video.js +6 -6
  241. package/dist/openrouter-video.js.map +1 -1
  242. package/dist/recorder.cjs +45 -9
  243. package/dist/recorder.cjs.map +1 -1
  244. package/dist/recorder.d.cts.map +1 -1
  245. package/dist/recorder.d.ts.map +1 -1
  246. package/dist/recorder.js +43 -11
  247. package/dist/recorder.js.map +1 -1
  248. package/dist/responses.cjs +4 -3
  249. package/dist/responses.cjs.map +1 -1
  250. package/dist/responses.js +5 -5
  251. package/dist/responses.js.map +1 -1
  252. package/dist/router.cjs +20 -33
  253. package/dist/router.cjs.map +1 -1
  254. package/dist/router.d.cts +4 -1
  255. package/dist/router.d.cts.map +1 -1
  256. package/dist/router.d.ts +4 -1
  257. package/dist/router.d.ts.map +1 -1
  258. package/dist/router.js +20 -34
  259. package/dist/router.js.map +1 -1
  260. package/dist/server.cjs +701 -625
  261. package/dist/server.cjs.map +1 -1
  262. package/dist/server.d.cts +1 -0
  263. package/dist/server.d.cts.map +1 -1
  264. package/dist/server.d.ts +1 -0
  265. package/dist/server.d.ts.map +1 -1
  266. package/dist/server.js +704 -628
  267. package/dist/server.js.map +1 -1
  268. package/dist/speech.cjs +2 -2
  269. package/dist/speech.cjs.map +1 -1
  270. package/dist/speech.js +3 -3
  271. package/dist/speech.js.map +1 -1
  272. package/dist/transcription.cjs +4 -4
  273. package/dist/transcription.cjs.map +1 -1
  274. package/dist/transcription.js +5 -5
  275. package/dist/transcription.js.map +1 -1
  276. package/dist/types.d.cts +119 -16
  277. package/dist/types.d.cts.map +1 -1
  278. package/dist/types.d.ts +119 -16
  279. package/dist/types.d.ts.map +1 -1
  280. package/dist/validate-cli.cjs +925 -0
  281. package/dist/validate-cli.cjs.map +1 -0
  282. package/dist/validate-cli.js +924 -0
  283. package/dist/validate-cli.js.map +1 -0
  284. package/dist/veo-video.cjs +13 -13
  285. package/dist/veo-video.cjs.map +1 -1
  286. package/dist/veo-video.js +14 -14
  287. package/dist/veo-video.js.map +1 -1
  288. package/dist/video.cjs +4 -4
  289. package/dist/video.cjs.map +1 -1
  290. package/dist/video.d.cts +1 -1
  291. package/dist/video.d.cts.map +1 -1
  292. package/dist/video.d.ts +1 -1
  293. package/dist/video.d.ts.map +1 -1
  294. package/dist/video.js +5 -5
  295. package/dist/video.js.map +1 -1
  296. package/dist/vitest.cjs +13 -6
  297. package/dist/vitest.cjs.map +1 -1
  298. package/dist/vitest.d.cts +2 -1
  299. package/dist/vitest.d.cts.map +1 -1
  300. package/dist/vitest.d.ts +2 -1
  301. package/dist/vitest.d.ts.map +1 -1
  302. package/dist/vitest.js +14 -7
  303. package/dist/vitest.js.map +1 -1
  304. package/dist/watcher.cjs +2 -1
  305. package/dist/watcher.cjs.map +1 -1
  306. package/dist/watcher.js +2 -1
  307. package/dist/watcher.js.map +1 -1
  308. package/dist/ws-framing.cjs +150 -35
  309. package/dist/ws-framing.cjs.map +1 -1
  310. package/dist/ws-framing.d.cts +18 -3
  311. package/dist/ws-framing.d.cts.map +1 -1
  312. package/dist/ws-framing.d.ts +18 -3
  313. package/dist/ws-framing.d.ts.map +1 -1
  314. package/dist/ws-framing.js +151 -36
  315. package/dist/ws-framing.js.map +1 -1
  316. package/dist/ws-gemini-live.cjs +2 -2
  317. package/dist/ws-gemini-live.d.ts +2 -2
  318. package/dist/ws-gemini-live.js +2 -2
  319. package/dist/ws-live.cjs +401 -0
  320. package/dist/ws-live.cjs.map +1 -0
  321. package/dist/ws-live.js +400 -0
  322. package/dist/ws-live.js.map +1 -0
  323. package/dist/ws-realtime.cjs +46 -2
  324. package/dist/ws-realtime.cjs.map +1 -1
  325. package/dist/ws-realtime.d.cts.map +1 -1
  326. package/dist/ws-realtime.d.ts +2 -2
  327. package/dist/ws-realtime.d.ts.map +1 -1
  328. package/dist/ws-realtime.js +46 -2
  329. package/dist/ws-realtime.js.map +1 -1
  330. package/dist/ws-responses.cjs +2 -2
  331. package/dist/ws-responses.js +2 -2
  332. package/dist/ws-upstream.cjs +118 -0
  333. package/dist/ws-upstream.cjs.map +1 -0
  334. package/dist/ws-upstream.js +115 -0
  335. package/dist/ws-upstream.js.map +1 -0
  336. package/fixtures/openai-live-client.json +390 -0
  337. package/fixtures/openai-live-managed.json +709 -0
  338. package/package.json +1 -1
package/dist/helpers.js CHANGED
@@ -26,6 +26,18 @@ function resolveStrictMode(serverDefault, rawHeaders) {
26
26
  return serverDefault ?? false;
27
27
  }
28
28
  /**
29
+ * Would a fixture miss on this request have been forwarded upstream? This is
30
+ * the ONE rule behind the no-fixture chaos journal `source` label: "proxy"
31
+ * only when record mode has an upstream for THIS provider and strict mode is
32
+ * not refusing the miss first. `effectiveStrict` is the header-resolved value
33
+ * from {@link resolveStrictMode}. `record.providers` is read guarded — a JS
34
+ * caller can hand over `record: {}`.
35
+ */
36
+ function wouldProxyMiss(effectiveStrict, record, providerKey) {
37
+ if (effectiveStrict || providerKey === void 0) return false;
38
+ return Boolean(record?.providers?.[providerKey]);
39
+ }
40
+ /**
29
41
  * Returns `true` or `false` when the X-AIMock-Strict header overrides the
30
42
  * server default, or `undefined` when it doesn't. Designed to be spread
31
43
  * directly into a journal entry's `response` object:
@@ -142,6 +154,10 @@ function flattenHeaders(headers) {
142
154
  }
143
155
  return flat;
144
156
  }
157
+ /** Structural discriminator; registration performs full transcript validation. */
158
+ function isLiveResponse(value) {
159
+ return value !== null && typeof value === "object" && !Array.isArray(value) && "live" in value;
160
+ }
145
161
  function isResponseFactory(r) {
146
162
  return typeof r === "function";
147
163
  }
@@ -176,6 +192,57 @@ function normalizeFactoryResponse(raw) {
176
192
  function generateId(prefix = "chatcmpl") {
177
193
  return `${prefix}-${randomBytes(12).toString("base64url")}`;
178
194
  }
195
+ /**
196
+ * Resolve the request id for this HTTP request.
197
+ *
198
+ * - When the caller sends a well-formed `X-Request-Id` (1-128 chars of
199
+ * `A-Za-z0-9-_.:`), it is echoed verbatim so distributed traces correlate.
200
+ * - Otherwise (absent, empty, too long, or illegal characters) a fresh
201
+ * `req-…` id is generated — never trust an attacker-controlled correlation
202
+ * value to be a valid log key.
203
+ *
204
+ * Returns `{ id, generated }`. The server normalizes
205
+ * `req.headers["x-request-id"]` to the resolved value, so every downstream
206
+ * `flattenHeaders` journal snapshot carries it with zero per-handler edits —
207
+ * which also means a MINTED id would otherwise ride the egress header set to
208
+ * a real provider. The server therefore passes `generated` to
209
+ * `markMintedRequestId` so `buildForwardHeaders` can drop it; a caller's own
210
+ * id still forwards verbatim.
211
+ */
212
+ function resolveRequestId(rawHeaders) {
213
+ const raw = rawHeaders["x-request-id"];
214
+ const first = Array.isArray(raw) ? raw[0] : raw;
215
+ if (typeof first === "string") {
216
+ const trimmed = first.trim();
217
+ if (trimmed.length >= 1 && trimmed.length <= 128 && /^[A-Za-z0-9\-_.:]+$/.test(trimmed)) return {
218
+ id: trimmed,
219
+ generated: false
220
+ };
221
+ }
222
+ return {
223
+ id: generateId("req"),
224
+ generated: true
225
+ };
226
+ }
227
+ /**
228
+ * Requests whose `x-request-id` aimock MINTED (the caller sent none, or sent
229
+ * an unusable one). The normalized header is indistinguishable from a
230
+ * caller-supplied one by inspection, so the provenance is tracked out-of-band
231
+ * and keyed on the request object, exactly like the egress auth marker.
232
+ */
233
+ const mintedRequestIds = /* @__PURE__ */ new WeakSet();
234
+ /** @internal Record that this request's `x-request-id` is aimock's own. */
235
+ function markMintedRequestId(req, generated) {
236
+ if (generated) mintedRequestIds.add(req);
237
+ }
238
+ /**
239
+ * @internal True when `x-request-id` on this request was minted by aimock.
240
+ * Egress paths use it to avoid transmitting an invented correlation id to a
241
+ * real provider.
242
+ */
243
+ function hasMintedRequestId(req) {
244
+ return mintedRequestIds.has(req);
245
+ }
179
246
  function generateToolCallId() {
180
247
  return `call_${randomBytes(12).toString("base64url")}`;
181
248
  }
@@ -254,6 +321,24 @@ function resolveFixtureBlocks(blocks) {
254
321
  } else throw new Error(`Invalid fixture block at index ${i}: unknown type ${JSON.stringify(b.type)} (expected "text" or "toolCall")`);
255
322
  });
256
323
  }
324
+ /** Project normalized ordered blocks without changing the fixture or generating ids. */
325
+ function resolveFixtureBlockOutcome(blocks) {
326
+ const ordered = resolveFixtureBlocks(blocks);
327
+ let content = "";
328
+ const toolCalls = [];
329
+ for (const block of ordered) if (block.type === "text") content += block.text;
330
+ else toolCalls.push({
331
+ name: block.name,
332
+ arguments: block.arguments,
333
+ ...block.id !== void 0 ? { id: block.id } : {}
334
+ });
335
+ return {
336
+ ordered,
337
+ content,
338
+ toolCalls,
339
+ hasToolCalls: toolCalls.length > 0
340
+ };
341
+ }
257
342
  function isErrorResponse(r) {
258
343
  return "error" in r && r.error !== null && typeof r.error === "object" && "message" in r.error && typeof r.error.message === "string";
259
344
  }
@@ -603,7 +688,8 @@ function buildContentWithToolCallsChunks(content, toolCalls, model, chunkSize, r
603
688
  const chunks = [];
604
689
  const fingerprint = overrides?.systemFingerprint;
605
690
  if (blocks && blocks.length > 0) {
606
- const ordered = resolveFixtureBlocks(blocks);
691
+ const outcome = resolveFixtureBlockOutcome(blocks);
692
+ const ordered = outcome.ordered;
607
693
  if (reasoning) for (let i = 0; i < reasoning.length; i += chunkSize) {
608
694
  const slice = reasoning.slice(i, i + chunkSize);
609
695
  chunks.push({
@@ -710,7 +796,7 @@ function buildContentWithToolCallsChunks(content, toolCalls, model, chunkSize, r
710
796
  index: 0,
711
797
  delta: {},
712
798
  logprobs: null,
713
- finish_reason: overrides?.finishReason ?? "tool_calls"
799
+ finish_reason: overrides?.finishReason ?? (outcome.hasToolCalls ? "tool_calls" : "stop")
714
800
  }],
715
801
  ...fingerprint !== void 0 && { system_fingerprint: fingerprint }
716
802
  });
@@ -859,7 +945,31 @@ function buildContentWithToolCallsCompletion(content, toolCalls, model, reasonin
859
945
  };
860
946
  }
861
947
  const DEFAULT_MAX_BODY_BYTES = 10 * 1024 * 1024;
862
- function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
948
+ /**
949
+ * A body read that stopped because the CLIENT sent more bytes than the route
950
+ * allows. The socket is already destroyed when this rejects, so no status line
951
+ * ever reaches the caller — but the fault is the caller's, and error arms that
952
+ * journal and log the failure need to say so. Carrying the classification on
953
+ * the error type (rather than re-matching the message text) is what lets them:
954
+ * the message is unchanged from the plain `Error` this replaced.
955
+ */
956
+ var RequestBodyTooLargeError = class extends Error {
957
+ constructor(maxBytes) {
958
+ super(`Request body exceeded size limit of ${maxBytes} bytes`);
959
+ this.maxBytes = maxBytes;
960
+ this.name = "RequestBodyTooLargeError";
961
+ }
962
+ };
963
+ /**
964
+ * Read a request body as raw bytes, preserving every octet.
965
+ *
966
+ * This is the byte-level primitive {@link readBody} is built on: routes that
967
+ * must not lose bytes (binary file uploads) take the Buffer, everything else
968
+ * keeps taking the decoded string. Splitting it this way leaves the text path
969
+ * byte-identical — `readBody` performs exactly the same `Buffer.concat(...)`
970
+ * + default (utf8) `toString()` it always did, just one call later.
971
+ */
972
+ function readBodyBuffer(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
863
973
  return new Promise((resolve, reject) => {
864
974
  const chunks = [];
865
975
  let totalBytes = 0;
@@ -870,7 +980,7 @@ function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
870
980
  if (totalBytes > maxBytes) {
871
981
  settled = true;
872
982
  req.destroy();
873
- reject(/* @__PURE__ */ new Error(`Request body exceeded size limit of ${maxBytes} bytes`));
983
+ reject(new RequestBodyTooLargeError(maxBytes));
874
984
  return;
875
985
  }
876
986
  chunks.push(chunk);
@@ -878,7 +988,7 @@ function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
878
988
  req.on("end", () => {
879
989
  if (!settled) {
880
990
  settled = true;
881
- resolve(Buffer.concat(chunks).toString());
991
+ resolve(Buffer.concat(chunks));
882
992
  }
883
993
  });
884
994
  req.on("error", (err) => {
@@ -890,6 +1000,59 @@ function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
890
1000
  });
891
1001
  }
892
1002
  /**
1003
+ * Read a request body that may legitimately be over-size, without either
1004
+ * buffering it all or dropping the socket.
1005
+ *
1006
+ * {@link readBodyBuffer} answers an over-size body with `req.destroy()`: no
1007
+ * status line, no body, no CORS headers. That is the right default for routes
1008
+ * whose limit is a pure DoS bound, but it is the wrong answer for a route that
1009
+ * owes the caller a `400` describing what was wrong — the caller cannot read an
1010
+ * error it never receives. So this variant splits the two concerns:
1011
+ *
1012
+ * - `maxBytes` bounds MEMORY. Past it the buffered chunks are dropped and the
1013
+ * body is only counted, so peak retention never exceeds `maxBytes` no matter
1014
+ * how large the body is. The caller gets `buffer: null` and answers itself.
1015
+ * - `drainMaxBytes` bounds WORK, and is the only socket drop here: a body that
1016
+ * keeps coming past it is not worth draining and rejects as `readBodyBuffer`
1017
+ * would.
1018
+ */
1019
+ function readBodyBufferBounded(req, maxBytes, drainMaxBytes) {
1020
+ return new Promise((resolve, reject) => {
1021
+ let chunks = [];
1022
+ let totalBytes = 0;
1023
+ let settled = false;
1024
+ req.on("data", (chunk) => {
1025
+ if (settled) return;
1026
+ totalBytes += chunk.length;
1027
+ if (chunks !== null && totalBytes > maxBytes) chunks = null;
1028
+ if (totalBytes > drainMaxBytes) {
1029
+ settled = true;
1030
+ req.destroy();
1031
+ reject(new RequestBodyTooLargeError(drainMaxBytes));
1032
+ return;
1033
+ }
1034
+ if (chunks !== null) chunks.push(chunk);
1035
+ });
1036
+ req.on("end", () => {
1037
+ if (settled) return;
1038
+ settled = true;
1039
+ resolve({
1040
+ buffer: chunks === null ? null : Buffer.concat(chunks),
1041
+ bytesRead: totalBytes
1042
+ });
1043
+ });
1044
+ req.on("error", (err) => {
1045
+ if (!settled) {
1046
+ settled = true;
1047
+ reject(err);
1048
+ }
1049
+ });
1050
+ });
1051
+ }
1052
+ function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
1053
+ return readBodyBuffer(req, maxBytes).then((buf) => buf.toString());
1054
+ }
1055
+ /**
893
1056
  * Case-insensitive substring/regex match used for search, rerank, and
894
1057
  * moderation endpoints where exact casing rarely matters. String patterns
895
1058
  * are lowercased on both sides before comparison.
@@ -1121,7 +1284,51 @@ function buildEmbeddingResponse(embeddings, model, usage) {
1121
1284
  }
1122
1285
  };
1123
1286
  }
1287
+ /**
1288
+ * Build a stable, human-readable identifier for a fixture's match shape, for
1289
+ * any log line that has to name WHICH fixture it means. The `Fixture` type
1290
+ * carries no `id`/`name`, so the matchers are the only handle a reader has.
1291
+ *
1292
+ * Used by the relaxed-turnIndex warning (`router.ts`) and by the chaos
1293
+ * rejected-value warning (`chaos.ts`); one implementation so the two name the
1294
+ * same fixture the same way. The obvious `JSON.stringify(match)` is unfit: it
1295
+ * DROPS `predicate` functions (non-serialisable) and serialises any RegExp
1296
+ * matcher to `{}`, so a predicate- or regex-gated fixture's warning collapsed to
1297
+ * an uninformative "served fixture {}" / `{"userMessage":{}}` blob.
1298
+ *
1299
+ * Instead we list the PRESENT matcher keys in declaration order, annotating each
1300
+ * by VALUE KIND so predicates and regexes survive: `predicate(fn)`,
1301
+ * `userMessage(regex)`, `userMessage("hello")`, `turnIndex=0`, etc. The
1302
+ * fixture's array `index` is prefixed as a stable positional identifier when
1303
+ * the caller knows it (i.e. `>= 0`); callers holding only the fixture object
1304
+ * pass `-1` and get the matcher summary alone. String/number values are shown
1305
+ * inline (truncated) so a content match remains recognisable; the whole string
1306
+ * is capped to keep the log line bounded.
1307
+ */
1308
+ const DESCRIBE_MATCH_MAX = 160;
1309
+ function describeMatch(match, index) {
1310
+ const parts = [];
1311
+ for (const [key, value] of Object.entries(match)) {
1312
+ if (value === void 0) continue;
1313
+ if (typeof value === "function") parts.push(key === "predicate" ? "[predicate]" : `${key}[fn]`);
1314
+ else if (value instanceof RegExp) parts.push(`${key}(${value})`);
1315
+ else if (typeof value === "string") {
1316
+ const v = value.length > 40 ? `${value.slice(0, 40)}…` : value;
1317
+ parts.push(`${key}(${JSON.stringify(v)})`);
1318
+ } else if (Array.isArray(value)) parts.push(`${key}(${value.length} item${value.length === 1 ? "" : "s"})`);
1319
+ else if (typeof value === "object" && value !== null) {
1320
+ const json = JSON.stringify(value);
1321
+ parts.push(`${key}(${json.length > 40 ? `${json.slice(0, 40)}…` : json})`);
1322
+ } else parts.push(`${key}=${String(value)}`);
1323
+ }
1324
+ const keys = parts.length > 0 ? parts.join(", ") : "no matchers";
1325
+ const full = `${index >= 0 ? `#${index} ` : ""}{ ${keys} }`;
1326
+ if (full.length <= DESCRIBE_MATCH_MAX) return full;
1327
+ const head = full.slice(0, DESCRIBE_MATCH_MAX - 4);
1328
+ const cut = head.lastIndexOf(", ");
1329
+ return `${cut > 0 ? head.slice(0, cut) : head}, … }`;
1330
+ }
1124
1331
 
1125
1332
  //#endregion
1126
- export { FORMAT_TO_CONTENT_TYPE, MAX_EMBEDDING_DIMENSIONS, buildContentWithToolCallsChunks, buildContentWithToolCallsCompletion, buildEmbeddingResponse, buildTextChunks, buildTextCompletion, buildToolCallChunks, buildToolCallCompletion, buildUsageChunk, extractOverrides, flattenHeaders, formatToMime, generateDeterministicEmbedding, generateId, generateMessageId, generateToolCallId, generateToolUseId, getContext, getTestId, isAudioResponse, isContentWithToolCallsResponse, isEmbeddingResponse, isErrorResponse, isImageResponse, isJSONResponse, isJsonObject, isResponseFactory, isTextResponse, isToolCallResponse, isTranscriptionResponse, isVideoResponse, matchesPattern, normalizeEmbeddingInput, normalizeTextInput, readBody, resolveFixtureBlocks, resolveReasoningArtifactsForModel, resolveReasoningForModel, resolveResponse, resolveStrictMode, resolveTestId, resolveUsage, serializeErrorResponse, slugifyContext, slugifyTestId, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField, validateChatMessages, validateEmbeddingDimensions, validateToolsField };
1333
+ export { FORMAT_TO_CONTENT_TYPE, MAX_EMBEDDING_DIMENSIONS, RequestBodyTooLargeError, buildContentWithToolCallsChunks, buildContentWithToolCallsCompletion, buildEmbeddingResponse, buildTextChunks, buildTextCompletion, buildToolCallChunks, buildToolCallCompletion, buildUsageChunk, describeMatch, extractOverrides, flattenHeaders, formatToMime, generateDeterministicEmbedding, generateId, generateMessageId, generateToolCallId, generateToolUseId, getContext, getTestId, hasMintedRequestId, isAudioResponse, isContentWithToolCallsResponse, isEmbeddingResponse, isErrorResponse, isImageResponse, isJSONResponse, isJsonObject, isLiveResponse, isResponseFactory, isTextResponse, isToolCallResponse, isTranscriptionResponse, isVideoResponse, markMintedRequestId, matchesPattern, normalizeEmbeddingInput, normalizeTextInput, readBody, readBodyBufferBounded, resolveFixtureBlockOutcome, resolveFixtureBlocks, resolveReasoningArtifactsForModel, resolveReasoningForModel, resolveRequestId, resolveResponse, resolveStrictMode, resolveTestId, resolveUsage, serializeErrorResponse, slugifyContext, slugifyTestId, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField, validateChatMessages, validateEmbeddingDimensions, validateToolsField, wouldProxyMiss };
1127
1334
  //# sourceMappingURL=helpers.js.map