@copilotkit/aimock 1.37.4 → 1.39.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 (175) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +48 -0
  4. package/README.md +50 -11
  5. package/dist/agui-handler.cjs +20 -18
  6. package/dist/agui-handler.cjs.map +1 -1
  7. package/dist/agui-handler.d.cts +8 -1
  8. package/dist/agui-handler.d.cts.map +1 -1
  9. package/dist/agui-handler.d.ts +8 -1
  10. package/dist/agui-handler.d.ts.map +1 -1
  11. package/dist/agui-handler.js +20 -18
  12. package/dist/agui-handler.js.map +1 -1
  13. package/dist/agui-recorder.cjs +6 -0
  14. package/dist/agui-recorder.cjs.map +1 -1
  15. package/dist/agui-recorder.d.cts.map +1 -1
  16. package/dist/agui-recorder.d.ts.map +1 -1
  17. package/dist/agui-recorder.js +6 -0
  18. package/dist/agui-recorder.js.map +1 -1
  19. package/dist/agui-stub.d.cts +2 -2
  20. package/dist/agui-stub.d.ts +2 -2
  21. package/dist/agui-types.d.cts +19 -1
  22. package/dist/agui-types.d.cts.map +1 -1
  23. package/dist/agui-types.d.ts +19 -1
  24. package/dist/agui-types.d.ts.map +1 -1
  25. package/dist/aimock-cli.cjs +1 -1
  26. package/dist/aimock-cli.cjs.map +1 -1
  27. package/dist/aimock-cli.js +1 -1
  28. package/dist/aimock-cli.js.map +1 -1
  29. package/dist/api-key-auth.cjs +166 -0
  30. package/dist/api-key-auth.cjs.map +1 -0
  31. package/dist/api-key-auth.d.cts +17 -0
  32. package/dist/api-key-auth.d.cts.map +1 -0
  33. package/dist/api-key-auth.d.ts +17 -0
  34. package/dist/api-key-auth.d.ts.map +1 -0
  35. package/dist/api-key-auth.js +158 -0
  36. package/dist/api-key-auth.js.map +1 -0
  37. package/dist/cli.cjs +14 -11
  38. package/dist/cli.cjs.map +1 -1
  39. package/dist/cli.js +14 -11
  40. package/dist/cli.js.map +1 -1
  41. package/dist/config-loader.cjs +4 -2
  42. package/dist/config-loader.cjs.map +1 -1
  43. package/dist/config-loader.d.cts +2 -1
  44. package/dist/config-loader.d.cts.map +1 -1
  45. package/dist/config-loader.d.ts +2 -1
  46. package/dist/config-loader.d.ts.map +1 -1
  47. package/dist/config-loader.js +5 -3
  48. package/dist/config-loader.js.map +1 -1
  49. package/dist/fal-audio.cjs +2 -0
  50. package/dist/fal-audio.cjs.map +1 -1
  51. package/dist/fal-audio.d.cts.map +1 -1
  52. package/dist/fal-audio.d.ts.map +1 -1
  53. package/dist/fal-audio.js +2 -0
  54. package/dist/fal-audio.js.map +1 -1
  55. package/dist/fal.cjs +4 -1
  56. package/dist/fal.cjs.map +1 -1
  57. package/dist/fal.d.cts.map +1 -1
  58. package/dist/fal.d.ts.map +1 -1
  59. package/dist/fal.js +4 -1
  60. package/dist/fal.js.map +1 -1
  61. package/dist/fixture-loader.cjs +0 -0
  62. package/dist/fixture-loader.cjs.map +1 -1
  63. package/dist/fixture-loader.d.cts +3 -1
  64. package/dist/fixture-loader.d.cts.map +1 -1
  65. package/dist/fixture-loader.d.ts +3 -1
  66. package/dist/fixture-loader.d.ts.map +1 -1
  67. package/dist/fixture-loader.js +0 -0
  68. package/dist/fixture-loader.js.map +1 -1
  69. package/dist/grok-video.cjs +9 -2
  70. package/dist/grok-video.cjs.map +1 -1
  71. package/dist/grok-video.js +10 -3
  72. package/dist/grok-video.js.map +1 -1
  73. package/dist/helpers.cjs +16 -22
  74. package/dist/helpers.cjs.map +1 -1
  75. package/dist/helpers.d.cts.map +1 -1
  76. package/dist/helpers.d.ts.map +1 -1
  77. package/dist/helpers.js +16 -21
  78. package/dist/helpers.js.map +1 -1
  79. package/dist/index.d.cts +3 -3
  80. package/dist/index.d.ts +3 -3
  81. package/dist/llmock.cjs +37 -12
  82. package/dist/llmock.cjs.map +1 -1
  83. package/dist/llmock.d.cts +26 -2
  84. package/dist/llmock.d.cts.map +1 -1
  85. package/dist/llmock.d.ts +26 -2
  86. package/dist/llmock.d.ts.map +1 -1
  87. package/dist/llmock.js +39 -15
  88. package/dist/llmock.js.map +1 -1
  89. package/dist/openrouter-chat.cjs +333 -0
  90. package/dist/openrouter-chat.cjs.map +1 -0
  91. package/dist/openrouter-chat.js +325 -0
  92. package/dist/openrouter-chat.js.map +1 -0
  93. package/dist/openrouter-video.cjs +24 -7
  94. package/dist/openrouter-video.cjs.map +1 -1
  95. package/dist/openrouter-video.d.cts.map +1 -1
  96. package/dist/openrouter-video.d.ts.map +1 -1
  97. package/dist/openrouter-video.js +25 -8
  98. package/dist/openrouter-video.js.map +1 -1
  99. package/dist/provider-auth.cjs +20 -0
  100. package/dist/provider-auth.cjs.map +1 -1
  101. package/dist/provider-auth.js +20 -1
  102. package/dist/provider-auth.js.map +1 -1
  103. package/dist/recorder.cjs +50 -8
  104. package/dist/recorder.cjs.map +1 -1
  105. package/dist/recorder.d.cts.map +1 -1
  106. package/dist/recorder.d.ts.map +1 -1
  107. package/dist/recorder.js +50 -10
  108. package/dist/recorder.js.map +1 -1
  109. package/dist/responses.cjs +200 -89
  110. package/dist/responses.cjs.map +1 -1
  111. package/dist/responses.d.cts +18 -3
  112. package/dist/responses.d.cts.map +1 -1
  113. package/dist/responses.d.ts +18 -3
  114. package/dist/responses.d.ts.map +1 -1
  115. package/dist/responses.js +199 -90
  116. package/dist/responses.js.map +1 -1
  117. package/dist/server.cjs +190 -83
  118. package/dist/server.cjs.map +1 -1
  119. package/dist/server.d.cts +7 -2
  120. package/dist/server.d.cts.map +1 -1
  121. package/dist/server.d.ts +7 -2
  122. package/dist/server.d.ts.map +1 -1
  123. package/dist/server.js +190 -85
  124. package/dist/server.js.map +1 -1
  125. package/dist/sse-writer.cjs +3 -0
  126. package/dist/sse-writer.cjs.map +1 -1
  127. package/dist/sse-writer.d.cts +8 -0
  128. package/dist/sse-writer.d.cts.map +1 -1
  129. package/dist/sse-writer.d.ts +8 -0
  130. package/dist/sse-writer.d.ts.map +1 -1
  131. package/dist/sse-writer.js +3 -0
  132. package/dist/sse-writer.js.map +1 -1
  133. package/dist/stream-collapse.cjs +103 -0
  134. package/dist/stream-collapse.cjs.map +1 -1
  135. package/dist/stream-collapse.d.cts +7 -0
  136. package/dist/stream-collapse.d.cts.map +1 -1
  137. package/dist/stream-collapse.d.ts +7 -0
  138. package/dist/stream-collapse.d.ts.map +1 -1
  139. package/dist/stream-collapse.js +103 -0
  140. package/dist/stream-collapse.js.map +1 -1
  141. package/dist/transcription.cjs +49 -2
  142. package/dist/transcription.cjs.map +1 -1
  143. package/dist/transcription.d.cts.map +1 -1
  144. package/dist/transcription.d.ts.map +1 -1
  145. package/dist/transcription.js +50 -3
  146. package/dist/transcription.js.map +1 -1
  147. package/dist/types.d.cts +187 -5
  148. package/dist/types.d.cts.map +1 -1
  149. package/dist/types.d.ts +187 -5
  150. package/dist/types.d.ts.map +1 -1
  151. package/dist/vector-types.d.ts.map +1 -1
  152. package/dist/veo-video.cjs +9 -2
  153. package/dist/veo-video.cjs.map +1 -1
  154. package/dist/veo-video.js +10 -3
  155. package/dist/veo-video.js.map +1 -1
  156. package/dist/ws-gemini-live.cjs +41 -6
  157. package/dist/ws-gemini-live.cjs.map +1 -1
  158. package/dist/ws-gemini-live.js +41 -6
  159. package/dist/ws-gemini-live.js.map +1 -1
  160. package/dist/ws-realtime.cjs +306 -57
  161. package/dist/ws-realtime.cjs.map +1 -1
  162. package/dist/ws-realtime.d.cts +1 -0
  163. package/dist/ws-realtime.d.cts.map +1 -1
  164. package/dist/ws-realtime.d.ts +1 -0
  165. package/dist/ws-realtime.d.ts.map +1 -1
  166. package/dist/ws-realtime.js +307 -58
  167. package/dist/ws-realtime.js.map +1 -1
  168. package/dist/ws-responses.cjs +11 -6
  169. package/dist/ws-responses.cjs.map +1 -1
  170. package/dist/ws-responses.d.cts.map +1 -1
  171. package/dist/ws-responses.d.ts.map +1 -1
  172. package/dist/ws-responses.js +12 -7
  173. package/dist/ws-responses.js.map +1 -1
  174. package/package.json +3 -2
  175. package/skills/write-fixtures/SKILL.md +53 -19
package/dist/responses.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { isReasoningModel } from "./model-utils.js";
1
2
  import { extractOverrides, flattenHeaders, generateId, generateToolCallId, getContext, getTestId, isContentWithToolCallsResponse, isErrorResponse, isTextResponse, isToolCallResponse, resolveFixtureBlocks, resolveReasoningForModel, resolveResponse, resolveStrictMode, serializeErrorResponse, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField } from "./helpers.js";
2
3
  import { matchFixtureDiagnostic, recordMatchOptions } from "./router.js";
3
4
  import { calculateDelay, delay, writeErrorResponse } from "./sse-writer.js";
@@ -161,8 +162,8 @@ function responseId() {
161
162
  function itemId() {
162
163
  return generateId("msg");
163
164
  }
164
- function buildTextStreamEvents(content, model, chunkSize, reasoning, webSearches, overrides) {
165
- const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides);
165
+ function buildTextStreamEvents(content, model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
166
+ const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
166
167
  const { events: msgEvents, msgItem } = buildMessageOutputEvents(content, chunkSize, nextOutputIndex);
167
168
  events.push(...msgEvents);
168
169
  events.push({
@@ -179,8 +180,8 @@ function buildTextStreamEvents(content, model, chunkSize, reasoning, webSearches
179
180
  });
180
181
  return events;
181
182
  }
182
- function buildToolCallStreamEvents(toolCalls, model, chunkSize, reasoning, webSearches, overrides) {
183
- const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides);
183
+ function buildToolCallStreamEvents(toolCalls, model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
184
+ const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
184
185
  const fcOutputItems = [];
185
186
  for (let idx = 0; idx < toolCalls.length; idx++) {
186
187
  const tc = toolCalls[idx];
@@ -244,66 +245,184 @@ function buildToolCallStreamEvents(toolCalls, model, chunkSize, reasoning, webSe
244
245
  });
245
246
  return events;
246
247
  }
247
- function buildReasoningStreamEvents(reasoning, model, chunkSize) {
248
+ /**
249
+ * Whether the incoming Responses request should receive encrypted reasoning.
250
+ *
251
+ * Two observed triggers, gated on EITHER:
252
+ * - `include: ["reasoning.encrypted_content"]` — the explicit opt-in, and what
253
+ * `agent-framework-openai` >= 1.11.0 auto-appends on its stateless-replay path
254
+ * (it never sends `store`), so this is the branch that fires for real clients.
255
+ * - `store: false` — captured responses carry the blob when not server-side
256
+ * stored (ZDR) and omit it when stored; kept as a secondary trigger for
257
+ * clients that go stateless without opting in via `include`.
258
+ *
259
+ * Stored / opted-out replays stay byte-identical. Exported so the WebSocket
260
+ * Responses transport can share one gate.
261
+ */
262
+ function requestWantsEncryptedReasoning(req) {
263
+ if (requestIncludesEncryptedReasoning(req)) return true;
264
+ return req.store === false;
265
+ }
266
+ /**
267
+ * Whether the request carries the EXPLICIT `include` opt-in — a strictly
268
+ * narrower gate than `requestWantsEncryptedReasoning`, which also fires on
269
+ * `store: false`.
270
+ *
271
+ * This is the gate for SYNTHESIZING a reasoning item that the fixture does not
272
+ * declare (see `shouldSynthesizeBlobOnlyReasoning`), and it is deliberately the
273
+ * narrow one. Attaching a field to an item aimock was already emitting is a much
274
+ * smaller step than conjuring a whole output item that did not previously exist,
275
+ * so the larger behavior change gets the gate that is directly observable in the
276
+ * request rather than the inferred `store: false` one. `agent-framework-openai`
277
+ * >= 1.11.0 auto-appends `include` on its stateless-replay path and never sends
278
+ * `store` at all, so the motivating client is fully served by this branch — the
279
+ * narrowing costs the feature nothing.
280
+ *
281
+ * Exported so the WebSocket Responses transport shares one gate.
282
+ */
283
+ function requestIncludesEncryptedReasoning(req) {
284
+ const include = req.include;
285
+ return Array.isArray(include) && include.includes("reasoning.encrypted_content");
286
+ }
287
+ /**
288
+ * Synthetic stand-in for OpenAI's opaque `reasoning.encrypted_content`. aimock
289
+ * has no real ciphertext; it emits a base64 placeholder derived from the
290
+ * reasoning id (stable for a given item, opaque like the real field). Consumers
291
+ * store it (e.g. as agent-framework `protected_data`) and replay it verbatim;
292
+ * aimock matches on content and ignores the echoed blob. Without it,
293
+ * agent-framework-openai >= 1.11.0 hard-fails a reasoning + multi-tool chain on
294
+ * the follow-up request. See microsoft/agent-framework#7233.
295
+ *
296
+ * aimock skips inbound reasoning items entirely, so it cannot reproduce
297
+ * OpenAI's `invalid_encrypted_content` rejection of a mismatched blob/id — a
298
+ * known replay-only limitation.
299
+ */
300
+ function syntheticEncryptedReasoning(reasoningId) {
301
+ return Buffer.from(`aimock-encrypted-reasoning:${reasoningId}`).toString("base64");
302
+ }
303
+ /**
304
+ * Build a Responses `reasoning` output item. `summaryText` controls the summary
305
+ * (present for the terminal `done` / non-streaming item, omitted for the
306
+ * in-progress `added` item); `emitEncrypted` controls the blob INDEPENDENTLY of
307
+ * the summary, so a blob with an empty summary is expressible. aimock emits the
308
+ * blob only on the terminal item and omits it on `added`: real OpenAI populates
309
+ * `added` opportunistically, but the field is `anyOf: [string, null]` and
310
+ * non-required, so consumers should read it at `done` and treat `added` as
311
+ * best-effort — omitting there is legal and harmless.
312
+ */
313
+ function buildReasoningOutputItem(reasoningId, opts = {}) {
314
+ const item = {
315
+ type: "reasoning",
316
+ id: reasoningId,
317
+ summary: opts.summaryText === void 0 ? [] : [{
318
+ type: "summary_text",
319
+ text: opts.summaryText
320
+ }]
321
+ };
322
+ if (opts.emitEncrypted) item.encrypted_content = syntheticEncryptedReasoning(reasoningId);
323
+ return item;
324
+ }
325
+ /**
326
+ * Whether to synthesize a summary-LESS reasoning item that exists purely to
327
+ * carry the encrypted blob.
328
+ *
329
+ * Every reasoning item aimock emits otherwise originates in a fixture's declared
330
+ * `reasoning` summary text. But a fixture RECORDED from the real stateless
331
+ * agent-framework flow typically has NO summary — OpenAI returns `summary: []`
332
+ * unless summaries are explicitly requested — so keying the item on a declared
333
+ * summary starves the exact flow this feature exists to serve: fully opted in,
334
+ * yet no reasoning item and therefore no blob. Real OpenAI, for a
335
+ * reasoning-capable model, still returns a reasoning item (`summary: []`) with
336
+ * the blob populated. So synthesize one, gated on:
337
+ *
338
+ * - the EXPLICIT `include` opt-in ONLY (`requestIncludesEncryptedReasoning`),
339
+ * which is NARROWER than the `requestWantsEncryptedReasoning` gate that
340
+ * controls the blob itself. A `store: false` request whose fixture declares no
341
+ * summary therefore gets NO reasoning item, exactly as before this change.
342
+ * Two reasons: (1) creating an output item that did not previously exist is a
343
+ * bigger behavior change than adding a field to an item already being
344
+ * emitted, so it earns the gate that is directly observable in the request
345
+ * rather than the inferred one; (2) the `store: false` trigger's supporting
346
+ * capture evidence is not verifiable from this repo, and a larger change must
347
+ * not be stacked on an unverifiable premise. `agent-framework-openai` >=
348
+ * 1.11.0 sends `include` and never `store`, so nothing is lost.
349
+ * - the REQUESTED model's reasoning capability (aimock#254) — emitting a
350
+ * reasoning item for gpt-4o would be LESS faithful, not more, since that
351
+ * model has no reasoning channel at all. Unlike `resolveReasoningForModel`,
352
+ * which fails open for a declared summary (a recorded summary is evidence the
353
+ * model did reason), there is nothing to preserve here: a synthesized item on
354
+ * a non-reasoning model would be pure fabrication, so this gate is hard.
355
+ *
356
+ * Note this is INDEPENDENT of `emitEncryptedReasoning`: when a fixture DOES
357
+ * declare a summary, the blob still rides on it under either trigger (including
358
+ * `store: false`), unchanged.
359
+ */
360
+ function shouldSynthesizeBlobOnlyReasoning(reasoning, model, synthesizeSummarylessReasoning) {
361
+ if (reasoning) return false;
362
+ if (!synthesizeSummarylessReasoning) return false;
363
+ return isReasoningModel(model);
364
+ }
365
+ /**
366
+ * `reasoning` is `undefined` for a synthesized blob-only item (see
367
+ * `shouldSynthesizeBlobOnlyReasoning`). In that case the item's `summary` is
368
+ * `[]`, so the summary-part / summary-text events are SKIPPED entirely — they
369
+ * would describe a part that does not exist on the item — leaving a coherent
370
+ * `output_item.added` → `output_item.done` pair with nothing between.
371
+ */
372
+ function buildReasoningStreamEvents(reasoning, chunkSize, emitEncryptedReasoning = false) {
248
373
  const reasoningId = generateId("rs");
249
374
  const events = [];
250
375
  events.push({
251
376
  type: "response.output_item.added",
252
377
  output_index: 0,
253
- item: {
254
- type: "reasoning",
255
- id: reasoningId,
256
- summary: []
257
- }
378
+ item: buildReasoningOutputItem(reasoningId)
258
379
  });
259
- events.push({
260
- type: "response.reasoning_summary_part.added",
261
- item_id: reasoningId,
262
- output_index: 0,
263
- summary_index: 0,
264
- part: {
265
- type: "summary_text",
266
- text: ""
380
+ if (reasoning !== void 0) {
381
+ events.push({
382
+ type: "response.reasoning_summary_part.added",
383
+ item_id: reasoningId,
384
+ output_index: 0,
385
+ summary_index: 0,
386
+ part: {
387
+ type: "summary_text",
388
+ text: ""
389
+ }
390
+ });
391
+ for (let i = 0; i < reasoning.length; i += chunkSize) {
392
+ const slice = reasoning.slice(i, i + chunkSize);
393
+ events.push({
394
+ type: "response.reasoning_summary_text.delta",
395
+ item_id: reasoningId,
396
+ output_index: 0,
397
+ summary_index: 0,
398
+ delta: slice
399
+ });
267
400
  }
268
- });
269
- for (let i = 0; i < reasoning.length; i += chunkSize) {
270
- const slice = reasoning.slice(i, i + chunkSize);
271
401
  events.push({
272
- type: "response.reasoning_summary_text.delta",
402
+ type: "response.reasoning_summary_text.done",
273
403
  item_id: reasoningId,
274
404
  output_index: 0,
275
405
  summary_index: 0,
276
- delta: slice
406
+ text: reasoning
407
+ });
408
+ events.push({
409
+ type: "response.reasoning_summary_part.done",
410
+ item_id: reasoningId,
411
+ output_index: 0,
412
+ summary_index: 0,
413
+ part: {
414
+ type: "summary_text",
415
+ text: reasoning
416
+ }
277
417
  });
278
418
  }
279
- events.push({
280
- type: "response.reasoning_summary_text.done",
281
- item_id: reasoningId,
282
- output_index: 0,
283
- summary_index: 0,
284
- text: reasoning
285
- });
286
- events.push({
287
- type: "response.reasoning_summary_part.done",
288
- item_id: reasoningId,
289
- output_index: 0,
290
- summary_index: 0,
291
- part: {
292
- type: "summary_text",
293
- text: reasoning
294
- }
295
- });
296
419
  events.push({
297
420
  type: "response.output_item.done",
298
421
  output_index: 0,
299
- item: {
300
- type: "reasoning",
301
- id: reasoningId,
302
- summary: [{
303
- type: "summary_text",
304
- text: reasoning
305
- }]
306
- }
422
+ item: buildReasoningOutputItem(reasoningId, {
423
+ summaryText: reasoning,
424
+ emitEncrypted: emitEncryptedReasoning
425
+ })
307
426
  });
308
427
  return events;
309
428
  }
@@ -341,7 +460,7 @@ function buildWebSearchStreamEvents(queries, startOutputIndex) {
341
460
  }
342
461
  return events;
343
462
  }
344
- function buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides) {
463
+ function buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
345
464
  const respId = overrides?.id ?? responseId();
346
465
  const created = overrides?.created ?? Math.floor(Date.now() / 1e3);
347
466
  const effectiveModel = overrides?.model ?? model;
@@ -370,8 +489,8 @@ function buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrid
370
489
  output: []
371
490
  }
372
491
  });
373
- if (reasoning) {
374
- const reasoningEvents = buildReasoningStreamEvents(reasoning, model, chunkSize);
492
+ if (reasoning || shouldSynthesizeBlobOnlyReasoning(reasoning, model, synthesizeSummarylessReasoning)) {
493
+ const reasoningEvents = buildReasoningStreamEvents(reasoning, chunkSize, emitEncryptedReasoning);
375
494
  events.push(...reasoningEvents);
376
495
  const doneEvent = reasoningEvents.find((e) => e.type === "response.output_item.done" && e.item?.type === "reasoning");
377
496
  if (doneEvent) prefixOutputItems.push(doneEvent.item);
@@ -518,16 +637,12 @@ function buildFunctionCallOutputEvents(toolCall, chunkSize, outputIndex) {
518
637
  fcItem
519
638
  };
520
639
  }
521
- function buildOutputPrefix(content, reasoning, webSearches) {
640
+ function buildOutputPrefix(content, model, reasoning, webSearches, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
522
641
  const output = [];
523
- if (reasoning) output.push({
524
- type: "reasoning",
525
- id: generateId("rs"),
526
- summary: [{
527
- type: "summary_text",
528
- text: reasoning
529
- }]
530
- });
642
+ if (reasoning || shouldSynthesizeBlobOnlyReasoning(reasoning, model, synthesizeSummarylessReasoning)) output.push(buildReasoningOutputItem(generateId("rs"), {
643
+ summaryText: reasoning,
644
+ emitEncrypted: emitEncryptedReasoning
645
+ }));
531
646
  if (webSearches && webSearches.length > 0) for (const query of webSearches) output.push({
532
647
  type: "web_search_call",
533
648
  id: generateId("ws"),
@@ -561,19 +676,15 @@ function buildResponseEnvelope(model, output, overrides) {
561
676
  usage: responsesUsage(overrides)
562
677
  };
563
678
  }
564
- function buildTextResponse(content, model, reasoning, webSearches, overrides) {
565
- return buildResponseEnvelope(model, buildOutputPrefix(content, reasoning, webSearches), overrides);
679
+ function buildTextResponse(content, model, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
680
+ return buildResponseEnvelope(model, buildOutputPrefix(content, model, reasoning, webSearches, emitEncryptedReasoning, synthesizeSummarylessReasoning), overrides);
566
681
  }
567
- function buildToolCallResponse(toolCalls, model, reasoning, webSearches, overrides) {
682
+ function buildToolCallResponse(toolCalls, model, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
568
683
  const output = [];
569
- if (reasoning) output.push({
570
- type: "reasoning",
571
- id: generateId("rs"),
572
- summary: [{
573
- type: "summary_text",
574
- text: reasoning
575
- }]
576
- });
684
+ if (reasoning || shouldSynthesizeBlobOnlyReasoning(reasoning, model, synthesizeSummarylessReasoning)) output.push(buildReasoningOutputItem(generateId("rs"), {
685
+ summaryText: reasoning,
686
+ emitEncrypted: emitEncryptedReasoning
687
+ }));
577
688
  if (webSearches && webSearches.length > 0) for (const query of webSearches) output.push({
578
689
  type: "web_search_call",
579
690
  id: generateId("ws"),
@@ -593,8 +704,8 @@ function buildToolCallResponse(toolCalls, model, reasoning, webSearches, overrid
593
704
  });
594
705
  return buildResponseEnvelope(model, output, overrides);
595
706
  }
596
- function buildContentWithToolCallsStreamEvents(content, toolCalls, model, chunkSize, reasoning, webSearches, overrides, blocks) {
597
- const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides);
707
+ function buildContentWithToolCallsStreamEvents(content, toolCalls, model, chunkSize, reasoning, webSearches, overrides, blocks, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
708
+ const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
598
709
  const orderedOutputItems = [];
599
710
  if (blocks && blocks.length > 0) {
600
711
  const ordered = resolveFixtureBlocks(blocks);
@@ -663,18 +774,14 @@ function buildMessageOutputItem(content) {
663
774
  }]
664
775
  };
665
776
  }
666
- function buildContentWithToolCallsResponse(content, toolCalls, model, reasoning, webSearches, overrides, blocks) {
777
+ function buildContentWithToolCallsResponse(content, toolCalls, model, reasoning, webSearches, overrides, blocks, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
667
778
  if (blocks && blocks.length > 0) {
668
779
  const ordered = resolveFixtureBlocks(blocks);
669
780
  const output = [];
670
- if (reasoning) output.push({
671
- type: "reasoning",
672
- id: generateId("rs"),
673
- summary: [{
674
- type: "summary_text",
675
- text: reasoning
676
- }]
677
- });
781
+ if (reasoning || shouldSynthesizeBlobOnlyReasoning(reasoning, model, synthesizeSummarylessReasoning)) output.push(buildReasoningOutputItem(generateId("rs"), {
782
+ summaryText: reasoning,
783
+ emitEncrypted: emitEncryptedReasoning
784
+ }));
678
785
  if (webSearches && webSearches.length > 0) for (const query of webSearches) output.push({
679
786
  type: "web_search_call",
680
787
  id: generateId("ws"),
@@ -692,7 +799,7 @@ function buildContentWithToolCallsResponse(content, toolCalls, model, reasoning,
692
799
  }));
693
800
  return buildResponseEnvelope(model, output, overrides);
694
801
  }
695
- const output = buildOutputPrefix(content, reasoning, webSearches);
802
+ const output = buildOutputPrefix(content, model, reasoning, webSearches, emitEncryptedReasoning, synthesizeSummarylessReasoning);
696
803
  for (const tc of toolCalls) output.push(buildFunctionCallOutputItem(tc));
697
804
  return buildResponseEnvelope(model, output, overrides);
698
805
  }
@@ -748,6 +855,8 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
748
855
  const completionReq = responsesToCompletionRequest(responsesReq);
749
856
  completionReq._endpointType = "chat";
750
857
  completionReq._context = getContext(req);
858
+ const emitEncryptedReasoning = requestWantsEncryptedReasoning(responsesReq);
859
+ const synthesizeSummarylessReasoning = requestIncludesEncryptedReasoning(responsesReq);
751
860
  const testId = getTestId(req);
752
861
  const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform, recordMatchOptions(!!defaults.record, defaults.logger));
753
862
  if (fixture) {
@@ -854,11 +963,11 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
854
963
  }
855
964
  });
856
965
  if (responsesReq.stream !== true) {
857
- const body = buildContentWithToolCallsResponse(response.content ?? "", response.toolCalls ?? [], completionReq.model, effReasoning, response.webSearches, overrides, response.blocks);
966
+ const body = buildContentWithToolCallsResponse(response.content ?? "", response.toolCalls ?? [], completionReq.model, effReasoning, response.webSearches, overrides, response.blocks, emitEncryptedReasoning, synthesizeSummarylessReasoning);
858
967
  res.writeHead(200, { "Content-Type": "application/json" });
859
968
  res.end(JSON.stringify(body));
860
969
  } else {
861
- const events = buildContentWithToolCallsStreamEvents(response.content ?? "", response.toolCalls ?? [], completionReq.model, chunkSize, effReasoning, response.webSearches, overrides, response.blocks);
970
+ const events = buildContentWithToolCallsStreamEvents(response.content ?? "", response.toolCalls ?? [], completionReq.model, chunkSize, effReasoning, response.webSearches, overrides, response.blocks, emitEncryptedReasoning, synthesizeSummarylessReasoning);
862
971
  const interruption = createInterruptionSignal(fixture);
863
972
  if (!await writeResponsesSSEStream(res, events, {
864
973
  latency,
@@ -891,11 +1000,11 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
891
1000
  }
892
1001
  });
893
1002
  if (responsesReq.stream !== true) {
894
- const body = buildTextResponse(response.content, completionReq.model, effReasoning, response.webSearches, overrides);
1003
+ const body = buildTextResponse(response.content, completionReq.model, effReasoning, response.webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
895
1004
  res.writeHead(200, { "Content-Type": "application/json" });
896
1005
  res.end(JSON.stringify(body));
897
1006
  } else {
898
- const events = buildTextStreamEvents(response.content, completionReq.model, chunkSize, effReasoning, response.webSearches, overrides);
1007
+ const events = buildTextStreamEvents(response.content, completionReq.model, chunkSize, effReasoning, response.webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
899
1008
  const interruption = createInterruptionSignal(fixture);
900
1009
  if (!await writeResponsesSSEStream(res, events, {
901
1010
  latency,
@@ -928,11 +1037,11 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
928
1037
  }
929
1038
  });
930
1039
  if (responsesReq.stream !== true) {
931
- const body = buildToolCallResponse(response.toolCalls, completionReq.model, effReasoning, response.webSearches, overrides);
1040
+ const body = buildToolCallResponse(response.toolCalls, completionReq.model, effReasoning, response.webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
932
1041
  res.writeHead(200, { "Content-Type": "application/json" });
933
1042
  res.end(JSON.stringify(body));
934
1043
  } else {
935
- const events = buildToolCallStreamEvents(response.toolCalls, completionReq.model, chunkSize, effReasoning, response.webSearches, overrides);
1044
+ const events = buildToolCallStreamEvents(response.toolCalls, completionReq.model, chunkSize, effReasoning, response.webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
936
1045
  const interruption = createInterruptionSignal(fixture);
937
1046
  if (!await writeResponsesSSEStream(res, events, {
938
1047
  latency,
@@ -967,5 +1076,5 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
967
1076
  }
968
1077
 
969
1078
  //#endregion
970
- export { buildContentWithToolCallsStreamEvents, buildTextStreamEvents, buildToolCallStreamEvents, handleResponses, responsesToCompletionRequest };
1079
+ export { buildContentWithToolCallsStreamEvents, buildTextStreamEvents, buildToolCallStreamEvents, handleResponses, requestIncludesEncryptedReasoning, requestWantsEncryptedReasoning, responsesToCompletionRequest };
971
1080
  //# sourceMappingURL=responses.js.map