@copilotkit/aimock 1.42.0 → 1.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +56 -0
  4. package/README.md +102 -16
  5. package/dist/agui-mock.cjs +1 -1
  6. package/dist/agui-mock.cjs.map +1 -1
  7. package/dist/agui-mock.d.cts.map +1 -1
  8. package/dist/agui-mock.d.ts.map +1 -1
  9. package/dist/agui-mock.js +1 -1
  10. package/dist/agui-mock.js.map +1 -1
  11. package/dist/agui-recorder.cjs +33 -11
  12. package/dist/agui-recorder.cjs.map +1 -1
  13. package/dist/agui-recorder.d.cts +10 -1
  14. package/dist/agui-recorder.d.cts.map +1 -1
  15. package/dist/agui-recorder.d.ts +10 -1
  16. package/dist/agui-recorder.d.ts.map +1 -1
  17. package/dist/agui-recorder.js +33 -11
  18. package/dist/agui-recorder.js.map +1 -1
  19. package/dist/agui-types.d.cts +1 -0
  20. package/dist/agui-types.d.cts.map +1 -1
  21. package/dist/agui-types.d.ts +1 -0
  22. package/dist/agui-types.d.ts.map +1 -1
  23. package/dist/aimock-cli.cjs +38 -10
  24. package/dist/aimock-cli.cjs.map +1 -1
  25. package/dist/aimock-cli.d.cts +5 -0
  26. package/dist/aimock-cli.d.cts.map +1 -1
  27. package/dist/aimock-cli.d.ts +5 -0
  28. package/dist/aimock-cli.d.ts.map +1 -1
  29. package/dist/aimock-cli.js +38 -10
  30. package/dist/aimock-cli.js.map +1 -1
  31. package/dist/batches.cjs +458 -0
  32. package/dist/batches.cjs.map +1 -0
  33. package/dist/batches.d.cts +57 -0
  34. package/dist/batches.d.cts.map +1 -0
  35. package/dist/batches.d.ts +57 -0
  36. package/dist/batches.d.ts.map +1 -0
  37. package/dist/batches.js +453 -0
  38. package/dist/batches.js.map +1 -0
  39. package/dist/bedrock-converse.cjs +12 -8
  40. package/dist/bedrock-converse.cjs.map +1 -1
  41. package/dist/bedrock-converse.d.cts.map +1 -1
  42. package/dist/bedrock-converse.d.ts.map +1 -1
  43. package/dist/bedrock-converse.js +14 -10
  44. package/dist/bedrock-converse.js.map +1 -1
  45. package/dist/bedrock.cjs +10 -8
  46. package/dist/bedrock.cjs.map +1 -1
  47. package/dist/bedrock.d.cts.map +1 -1
  48. package/dist/bedrock.d.ts.map +1 -1
  49. package/dist/bedrock.js +12 -10
  50. package/dist/bedrock.js.map +1 -1
  51. package/dist/byteplus-video.cjs +3 -3
  52. package/dist/byteplus-video.cjs.map +1 -1
  53. package/dist/byteplus-video.js +4 -4
  54. package/dist/byteplus-video.js.map +1 -1
  55. package/dist/chaos.cjs +622 -72
  56. package/dist/chaos.cjs.map +1 -1
  57. package/dist/chaos.d.cts +164 -7
  58. package/dist/chaos.d.cts.map +1 -1
  59. package/dist/chaos.d.ts +164 -7
  60. package/dist/chaos.d.ts.map +1 -1
  61. package/dist/chaos.js +613 -74
  62. package/dist/chaos.js.map +1 -1
  63. package/dist/cli.cjs +42 -23
  64. package/dist/cli.cjs.map +1 -1
  65. package/dist/cli.js +42 -23
  66. package/dist/cli.js.map +1 -1
  67. package/dist/cohere.cjs +10 -8
  68. package/dist/cohere.cjs.map +1 -1
  69. package/dist/cohere.d.cts.map +1 -1
  70. package/dist/cohere.d.ts.map +1 -1
  71. package/dist/cohere.js +12 -10
  72. package/dist/cohere.js.map +1 -1
  73. package/dist/config-loader.d.cts.map +1 -1
  74. package/dist/config-loader.d.ts.map +1 -1
  75. package/dist/convert.cjs +1 -1
  76. package/dist/convert.cjs.map +1 -1
  77. package/dist/convert.js +1 -1
  78. package/dist/convert.js.map +1 -1
  79. package/dist/elevenlabs-audio.cjs +3 -3
  80. package/dist/elevenlabs-audio.cjs.map +1 -1
  81. package/dist/elevenlabs-audio.js +4 -4
  82. package/dist/elevenlabs-audio.js.map +1 -1
  83. package/dist/elevenlabs-voice.cjs +1053 -0
  84. package/dist/elevenlabs-voice.cjs.map +1 -0
  85. package/dist/elevenlabs-voice.d.cts +72 -0
  86. package/dist/elevenlabs-voice.d.cts.map +1 -0
  87. package/dist/elevenlabs-voice.d.ts +72 -0
  88. package/dist/elevenlabs-voice.d.ts.map +1 -0
  89. package/dist/elevenlabs-voice.js +1048 -0
  90. package/dist/elevenlabs-voice.js.map +1 -0
  91. package/dist/embeddings.cjs +8 -4
  92. package/dist/embeddings.cjs.map +1 -1
  93. package/dist/embeddings.d.cts.map +1 -1
  94. package/dist/embeddings.d.ts.map +1 -1
  95. package/dist/embeddings.js +9 -5
  96. package/dist/embeddings.js.map +1 -1
  97. package/dist/fal-audio.cjs +3 -3
  98. package/dist/fal-audio.cjs.map +1 -1
  99. package/dist/fal-audio.js +4 -4
  100. package/dist/fal-audio.js.map +1 -1
  101. package/dist/fal.cjs +28 -4
  102. package/dist/fal.cjs.map +1 -1
  103. package/dist/fal.d.cts +16 -1
  104. package/dist/fal.d.cts.map +1 -1
  105. package/dist/fal.d.ts +16 -1
  106. package/dist/fal.d.ts.map +1 -1
  107. package/dist/fal.js +28 -5
  108. package/dist/fal.js.map +1 -1
  109. package/dist/files.cjs +1071 -0
  110. package/dist/files.cjs.map +1 -0
  111. package/dist/files.d.cts +68 -0
  112. package/dist/files.d.cts.map +1 -0
  113. package/dist/files.d.ts +68 -0
  114. package/dist/files.d.ts.map +1 -0
  115. package/dist/files.js +1059 -0
  116. package/dist/files.js.map +1 -0
  117. package/dist/fine-tuning.cjs +1051 -0
  118. package/dist/fine-tuning.cjs.map +1 -0
  119. package/dist/fine-tuning.d.cts +96 -0
  120. package/dist/fine-tuning.d.cts.map +1 -0
  121. package/dist/fine-tuning.d.ts +96 -0
  122. package/dist/fine-tuning.d.ts.map +1 -0
  123. package/dist/fine-tuning.js +1044 -0
  124. package/dist/fine-tuning.js.map +1 -0
  125. package/dist/fixture-loader.cjs +0 -0
  126. package/dist/fixture-loader.cjs.map +1 -1
  127. package/dist/fixture-loader.d.cts +37 -5
  128. package/dist/fixture-loader.d.cts.map +1 -1
  129. package/dist/fixture-loader.d.ts +37 -5
  130. package/dist/fixture-loader.d.ts.map +1 -1
  131. package/dist/fixture-loader.js +0 -0
  132. package/dist/fixture-loader.js.map +1 -1
  133. package/dist/gemini-embeddings.cjs +2 -2
  134. package/dist/gemini-embeddings.cjs.map +1 -1
  135. package/dist/gemini-embeddings.js +3 -3
  136. package/dist/gemini-embeddings.js.map +1 -1
  137. package/dist/gemini-interactions.cjs +13 -7
  138. package/dist/gemini-interactions.cjs.map +1 -1
  139. package/dist/gemini-interactions.d.cts.map +1 -1
  140. package/dist/gemini-interactions.d.ts.map +1 -1
  141. package/dist/gemini-interactions.js +15 -9
  142. package/dist/gemini-interactions.js.map +1 -1
  143. package/dist/gemini.cjs +11 -7
  144. package/dist/gemini.cjs.map +1 -1
  145. package/dist/gemini.d.cts.map +1 -1
  146. package/dist/gemini.d.ts.map +1 -1
  147. package/dist/gemini.js +13 -9
  148. package/dist/gemini.js.map +1 -1
  149. package/dist/grok-video.cjs +14 -14
  150. package/dist/grok-video.cjs.map +1 -1
  151. package/dist/grok-video.js +15 -15
  152. package/dist/grok-video.js.map +1 -1
  153. package/dist/helpers.cjs +229 -7
  154. package/dist/helpers.cjs.map +1 -1
  155. package/dist/helpers.d.cts +38 -2
  156. package/dist/helpers.d.cts.map +1 -1
  157. package/dist/helpers.d.ts +38 -2
  158. package/dist/helpers.d.ts.map +1 -1
  159. package/dist/helpers.js +221 -8
  160. package/dist/helpers.js.map +1 -1
  161. package/dist/images.cjs +54 -123
  162. package/dist/images.cjs.map +1 -1
  163. package/dist/images.d.cts.map +1 -1
  164. package/dist/images.d.ts.map +1 -1
  165. package/dist/images.js +55 -124
  166. package/dist/images.js.map +1 -1
  167. package/dist/index.cjs +41 -8
  168. package/dist/index.d.cts +12 -7
  169. package/dist/index.d.ts +12 -7
  170. package/dist/index.js +14 -10
  171. package/dist/jest.cjs +14 -7
  172. package/dist/jest.cjs.map +1 -1
  173. package/dist/jest.d.cts +3 -2
  174. package/dist/jest.d.cts.map +1 -1
  175. package/dist/jest.d.ts +3 -2
  176. package/dist/jest.d.ts.map +1 -1
  177. package/dist/jest.js +14 -7
  178. package/dist/jest.js.map +1 -1
  179. package/dist/journal.cjs +41 -4
  180. package/dist/journal.cjs.map +1 -1
  181. package/dist/journal.d.cts +44 -3
  182. package/dist/journal.d.cts.map +1 -1
  183. package/dist/journal.d.ts +44 -3
  184. package/dist/journal.d.ts.map +1 -1
  185. package/dist/journal.js +41 -5
  186. package/dist/journal.js.map +1 -1
  187. package/dist/live-fixture.cjs +1192 -0
  188. package/dist/live-fixture.cjs.map +1 -0
  189. package/dist/live-fixture.js +1187 -0
  190. package/dist/live-fixture.js.map +1 -0
  191. package/dist/live-recorder.cjs +256 -0
  192. package/dist/live-recorder.cjs.map +1 -0
  193. package/dist/live-recorder.js +254 -0
  194. package/dist/live-recorder.js.map +1 -0
  195. package/dist/live-replay.cjs +286 -0
  196. package/dist/live-replay.cjs.map +1 -0
  197. package/dist/live-replay.js +285 -0
  198. package/dist/live-replay.js.map +1 -0
  199. package/dist/live-sanitize.cjs +196 -0
  200. package/dist/live-sanitize.cjs.map +1 -0
  201. package/dist/live-sanitize.js +196 -0
  202. package/dist/live-sanitize.js.map +1 -0
  203. package/dist/live-types.d.cts +71 -0
  204. package/dist/live-types.d.cts.map +1 -0
  205. package/dist/live-types.d.ts +71 -0
  206. package/dist/live-types.d.ts.map +1 -0
  207. package/dist/llmock.cjs +52 -41
  208. package/dist/llmock.cjs.map +1 -1
  209. package/dist/llmock.d.cts +16 -5
  210. package/dist/llmock.d.cts.map +1 -1
  211. package/dist/llmock.d.ts +16 -5
  212. package/dist/llmock.d.ts.map +1 -1
  213. package/dist/llmock.js +53 -42
  214. package/dist/llmock.js.map +1 -1
  215. package/dist/messages.cjs +11 -7
  216. package/dist/messages.cjs.map +1 -1
  217. package/dist/messages.d.cts.map +1 -1
  218. package/dist/messages.d.ts.map +1 -1
  219. package/dist/messages.js +13 -9
  220. package/dist/messages.js.map +1 -1
  221. package/dist/metrics.cjs +258 -5
  222. package/dist/metrics.cjs.map +1 -1
  223. package/dist/metrics.d.cts +3 -1
  224. package/dist/metrics.d.cts.map +1 -1
  225. package/dist/metrics.d.ts +3 -1
  226. package/dist/metrics.d.ts.map +1 -1
  227. package/dist/metrics.js +255 -6
  228. package/dist/metrics.js.map +1 -1
  229. package/dist/moderation.cjs +10 -1
  230. package/dist/moderation.cjs.map +1 -1
  231. package/dist/moderation.d.cts.map +1 -1
  232. package/dist/moderation.d.ts.map +1 -1
  233. package/dist/moderation.js +10 -1
  234. package/dist/moderation.js.map +1 -1
  235. package/dist/ollama.cjs +5 -5
  236. package/dist/ollama.cjs.map +1 -1
  237. package/dist/ollama.js +6 -6
  238. package/dist/ollama.js.map +1 -1
  239. package/dist/openrouter-video.cjs +5 -5
  240. package/dist/openrouter-video.cjs.map +1 -1
  241. package/dist/openrouter-video.js +6 -6
  242. package/dist/openrouter-video.js.map +1 -1
  243. package/dist/recorder.cjs +45 -9
  244. package/dist/recorder.cjs.map +1 -1
  245. package/dist/recorder.d.cts.map +1 -1
  246. package/dist/recorder.d.ts.map +1 -1
  247. package/dist/recorder.js +43 -11
  248. package/dist/recorder.js.map +1 -1
  249. package/dist/responses.cjs +4 -3
  250. package/dist/responses.cjs.map +1 -1
  251. package/dist/responses.js +5 -5
  252. package/dist/responses.js.map +1 -1
  253. package/dist/router.cjs +20 -33
  254. package/dist/router.cjs.map +1 -1
  255. package/dist/router.d.cts +4 -1
  256. package/dist/router.d.cts.map +1 -1
  257. package/dist/router.d.ts +4 -1
  258. package/dist/router.d.ts.map +1 -1
  259. package/dist/router.js +20 -34
  260. package/dist/router.js.map +1 -1
  261. package/dist/server.cjs +701 -625
  262. package/dist/server.cjs.map +1 -1
  263. package/dist/server.d.cts +1 -0
  264. package/dist/server.d.cts.map +1 -1
  265. package/dist/server.d.ts +1 -0
  266. package/dist/server.d.ts.map +1 -1
  267. package/dist/server.js +704 -628
  268. package/dist/server.js.map +1 -1
  269. package/dist/speech.cjs +2 -2
  270. package/dist/speech.cjs.map +1 -1
  271. package/dist/speech.js +3 -3
  272. package/dist/speech.js.map +1 -1
  273. package/dist/transcription.cjs +4 -4
  274. package/dist/transcription.cjs.map +1 -1
  275. package/dist/transcription.js +5 -5
  276. package/dist/transcription.js.map +1 -1
  277. package/dist/types.d.cts +119 -16
  278. package/dist/types.d.cts.map +1 -1
  279. package/dist/types.d.ts +119 -16
  280. package/dist/types.d.ts.map +1 -1
  281. package/dist/validate-cli.cjs +925 -0
  282. package/dist/validate-cli.cjs.map +1 -0
  283. package/dist/validate-cli.js +924 -0
  284. package/dist/validate-cli.js.map +1 -0
  285. package/dist/vector-types.d.cts.map +1 -1
  286. package/dist/vector-types.d.ts.map +1 -1
  287. package/dist/veo-video.cjs +13 -13
  288. package/dist/veo-video.cjs.map +1 -1
  289. package/dist/veo-video.js +14 -14
  290. package/dist/veo-video.js.map +1 -1
  291. package/dist/video.cjs +4 -4
  292. package/dist/video.cjs.map +1 -1
  293. package/dist/video.d.cts +1 -1
  294. package/dist/video.d.cts.map +1 -1
  295. package/dist/video.d.ts +1 -1
  296. package/dist/video.d.ts.map +1 -1
  297. package/dist/video.js +5 -5
  298. package/dist/video.js.map +1 -1
  299. package/dist/vitest.cjs +13 -6
  300. package/dist/vitest.cjs.map +1 -1
  301. package/dist/vitest.d.cts +2 -1
  302. package/dist/vitest.d.cts.map +1 -1
  303. package/dist/vitest.d.ts +2 -1
  304. package/dist/vitest.d.ts.map +1 -1
  305. package/dist/vitest.js +14 -7
  306. package/dist/vitest.js.map +1 -1
  307. package/dist/watcher.cjs +2 -1
  308. package/dist/watcher.cjs.map +1 -1
  309. package/dist/watcher.js +2 -1
  310. package/dist/watcher.js.map +1 -1
  311. package/dist/ws-framing.cjs +150 -35
  312. package/dist/ws-framing.cjs.map +1 -1
  313. package/dist/ws-framing.d.cts +18 -3
  314. package/dist/ws-framing.d.cts.map +1 -1
  315. package/dist/ws-framing.d.ts +18 -3
  316. package/dist/ws-framing.d.ts.map +1 -1
  317. package/dist/ws-framing.js +151 -36
  318. package/dist/ws-framing.js.map +1 -1
  319. package/dist/ws-gemini-live.cjs +2 -2
  320. package/dist/ws-gemini-live.d.ts +2 -2
  321. package/dist/ws-gemini-live.js +2 -2
  322. package/dist/ws-live.cjs +401 -0
  323. package/dist/ws-live.cjs.map +1 -0
  324. package/dist/ws-live.js +400 -0
  325. package/dist/ws-live.js.map +1 -0
  326. package/dist/ws-realtime.cjs +46 -2
  327. package/dist/ws-realtime.cjs.map +1 -1
  328. package/dist/ws-realtime.d.cts.map +1 -1
  329. package/dist/ws-realtime.d.ts +2 -2
  330. package/dist/ws-realtime.d.ts.map +1 -1
  331. package/dist/ws-realtime.js +46 -2
  332. package/dist/ws-realtime.js.map +1 -1
  333. package/dist/ws-responses.cjs +2 -2
  334. package/dist/ws-responses.js +2 -2
  335. package/dist/ws-upstream.cjs +118 -0
  336. package/dist/ws-upstream.cjs.map +1 -0
  337. package/dist/ws-upstream.js +115 -0
  338. package/dist/ws-upstream.js.map +1 -0
  339. package/fixtures/openai-live-client.json +390 -0
  340. package/fixtures/openai-live-managed.json +709 -0
  341. package/package.json +1 -1
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({
@@ -613,7 +699,10 @@ function buildContentWithToolCallsChunks(content, toolCalls, model, chunkSize, r
613
699
  model: effectiveModel,
614
700
  choices: [{
615
701
  index: 0,
616
- delta: { reasoning_content: slice },
702
+ delta: {
703
+ ...i === 0 && { role: overrides?.role ?? "assistant" },
704
+ reasoning_content: slice
705
+ },
617
706
  logprobs: null,
618
707
  finish_reason: null
619
708
  }],
@@ -707,7 +796,7 @@ function buildContentWithToolCallsChunks(content, toolCalls, model, chunkSize, r
707
796
  index: 0,
708
797
  delta: {},
709
798
  logprobs: null,
710
- finish_reason: overrides?.finishReason ?? "tool_calls"
799
+ finish_reason: overrides?.finishReason ?? (outcome.hasToolCalls ? "tool_calls" : "stop")
711
800
  }],
712
801
  ...fingerprint !== void 0 && { system_fingerprint: fingerprint }
713
802
  });
@@ -722,7 +811,10 @@ function buildContentWithToolCallsChunks(content, toolCalls, model, chunkSize, r
722
811
  model: effectiveModel,
723
812
  choices: [{
724
813
  index: 0,
725
- delta: { reasoning_content: slice },
814
+ delta: {
815
+ ...i === 0 && { role: overrides?.role ?? "assistant" },
816
+ reasoning_content: slice
817
+ },
726
818
  logprobs: null,
727
819
  finish_reason: null
728
820
  }],
@@ -853,7 +945,31 @@ function buildContentWithToolCallsCompletion(content, toolCalls, model, reasonin
853
945
  };
854
946
  }
855
947
  const DEFAULT_MAX_BODY_BYTES = 10 * 1024 * 1024;
856
- 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) {
857
973
  return new Promise((resolve, reject) => {
858
974
  const chunks = [];
859
975
  let totalBytes = 0;
@@ -864,7 +980,7 @@ function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
864
980
  if (totalBytes > maxBytes) {
865
981
  settled = true;
866
982
  req.destroy();
867
- reject(/* @__PURE__ */ new Error(`Request body exceeded size limit of ${maxBytes} bytes`));
983
+ reject(new RequestBodyTooLargeError(maxBytes));
868
984
  return;
869
985
  }
870
986
  chunks.push(chunk);
@@ -872,9 +988,59 @@ function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
872
988
  req.on("end", () => {
873
989
  if (!settled) {
874
990
  settled = true;
875
- resolve(Buffer.concat(chunks).toString());
991
+ resolve(Buffer.concat(chunks));
992
+ }
993
+ });
994
+ req.on("error", (err) => {
995
+ if (!settled) {
996
+ settled = true;
997
+ reject(err);
876
998
  }
877
999
  });
1000
+ });
1001
+ }
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
+ });
878
1044
  req.on("error", (err) => {
879
1045
  if (!settled) {
880
1046
  settled = true;
@@ -883,6 +1049,9 @@ function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
883
1049
  });
884
1050
  });
885
1051
  }
1052
+ function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
1053
+ return readBodyBuffer(req, maxBytes).then((buf) => buf.toString());
1054
+ }
886
1055
  /**
887
1056
  * Case-insensitive substring/regex match used for search, rerank, and
888
1057
  * moderation endpoints where exact casing rarely matters. String patterns
@@ -1115,7 +1284,51 @@ function buildEmbeddingResponse(embeddings, model, usage) {
1115
1284
  }
1116
1285
  };
1117
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
+ }
1118
1331
 
1119
1332
  //#endregion
1120
- 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 };
1121
1334
  //# sourceMappingURL=helpers.js.map