@copilotkit/aimock 1.34.0 → 1.35.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 (150) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +16 -0
  4. package/README.md +2 -1
  5. package/dist/agui-types.d.cts.map +1 -1
  6. package/dist/agui-types.d.ts.map +1 -1
  7. package/dist/bedrock-converse.cjs +110 -8
  8. package/dist/bedrock-converse.cjs.map +1 -1
  9. package/dist/bedrock-converse.d.cts.map +1 -1
  10. package/dist/bedrock-converse.d.ts.map +1 -1
  11. package/dist/bedrock-converse.js +111 -9
  12. package/dist/bedrock-converse.js.map +1 -1
  13. package/dist/bedrock.cjs +141 -4
  14. package/dist/bedrock.cjs.map +1 -1
  15. package/dist/bedrock.d.cts.map +1 -1
  16. package/dist/bedrock.d.ts.map +1 -1
  17. package/dist/bedrock.js +142 -5
  18. package/dist/bedrock.js.map +1 -1
  19. package/dist/cohere.cjs +89 -7
  20. package/dist/cohere.cjs.map +1 -1
  21. package/dist/cohere.d.cts.map +1 -1
  22. package/dist/cohere.d.ts.map +1 -1
  23. package/dist/cohere.js +90 -8
  24. package/dist/cohere.js.map +1 -1
  25. package/dist/config-loader.d.cts.map +1 -1
  26. package/dist/fixture-loader.cjs +121 -20
  27. package/dist/fixture-loader.cjs.map +1 -1
  28. package/dist/fixture-loader.d.cts.map +1 -1
  29. package/dist/fixture-loader.d.ts.map +1 -1
  30. package/dist/fixture-loader.js +121 -20
  31. package/dist/fixture-loader.js.map +1 -1
  32. package/dist/gemini-interactions.cjs +97 -60
  33. package/dist/gemini-interactions.cjs.map +1 -1
  34. package/dist/gemini-interactions.d.cts.map +1 -1
  35. package/dist/gemini-interactions.d.ts.map +1 -1
  36. package/dist/gemini-interactions.js +98 -61
  37. package/dist/gemini-interactions.js.map +1 -1
  38. package/dist/gemini.cjs +71 -6
  39. package/dist/gemini.cjs.map +1 -1
  40. package/dist/gemini.d.cts.map +1 -1
  41. package/dist/gemini.d.ts.map +1 -1
  42. package/dist/gemini.js +72 -7
  43. package/dist/gemini.js.map +1 -1
  44. package/dist/grok-video.cjs +834 -0
  45. package/dist/grok-video.cjs.map +1 -0
  46. package/dist/grok-video.d.cts +74 -0
  47. package/dist/grok-video.d.cts.map +1 -0
  48. package/dist/grok-video.d.ts +74 -0
  49. package/dist/grok-video.d.ts.map +1 -0
  50. package/dist/grok-video.js +829 -0
  51. package/dist/grok-video.js.map +1 -0
  52. package/dist/helpers.cjs +181 -2
  53. package/dist/helpers.cjs.map +1 -1
  54. package/dist/helpers.d.cts +33 -3
  55. package/dist/helpers.d.cts.map +1 -1
  56. package/dist/helpers.d.ts +33 -3
  57. package/dist/helpers.d.ts.map +1 -1
  58. package/dist/helpers.js +181 -3
  59. package/dist/helpers.js.map +1 -1
  60. package/dist/index.cjs +11 -0
  61. package/dist/index.d.cts +5 -3
  62. package/dist/index.d.ts +5 -3
  63. package/dist/index.js +4 -2
  64. package/dist/messages.cjs +99 -10
  65. package/dist/messages.cjs.map +1 -1
  66. package/dist/messages.d.cts.map +1 -1
  67. package/dist/messages.d.ts.map +1 -1
  68. package/dist/messages.js +100 -11
  69. package/dist/messages.js.map +1 -1
  70. package/dist/metrics.cjs +11 -1
  71. package/dist/metrics.cjs.map +1 -1
  72. package/dist/metrics.d.cts.map +1 -1
  73. package/dist/metrics.d.ts.map +1 -1
  74. package/dist/metrics.js +8 -1
  75. package/dist/metrics.js.map +1 -1
  76. package/dist/ollama.cjs +74 -4
  77. package/dist/ollama.cjs.map +1 -1
  78. package/dist/ollama.d.cts.map +1 -1
  79. package/dist/ollama.d.ts.map +1 -1
  80. package/dist/ollama.js +75 -5
  81. package/dist/ollama.js.map +1 -1
  82. package/dist/openrouter-video.cjs +19 -138
  83. package/dist/openrouter-video.cjs.map +1 -1
  84. package/dist/openrouter-video.d.cts.map +1 -1
  85. package/dist/openrouter-video.d.ts.map +1 -1
  86. package/dist/openrouter-video.js +1 -120
  87. package/dist/openrouter-video.js.map +1 -1
  88. package/dist/recorder.cjs +12 -9
  89. package/dist/recorder.cjs.map +1 -1
  90. package/dist/recorder.js +12 -9
  91. package/dist/recorder.js.map +1 -1
  92. package/dist/responses.cjs +136 -58
  93. package/dist/responses.cjs.map +1 -1
  94. package/dist/responses.d.cts +2 -2
  95. package/dist/responses.d.cts.map +1 -1
  96. package/dist/responses.d.ts +2 -2
  97. package/dist/responses.d.ts.map +1 -1
  98. package/dist/responses.js +137 -59
  99. package/dist/responses.js.map +1 -1
  100. package/dist/server.cjs +162 -20
  101. package/dist/server.cjs.map +1 -1
  102. package/dist/server.d.cts +4 -0
  103. package/dist/server.d.cts.map +1 -1
  104. package/dist/server.d.ts +4 -0
  105. package/dist/server.d.ts.map +1 -1
  106. package/dist/server.js +164 -22
  107. package/dist/server.js.map +1 -1
  108. package/dist/stream-collapse.cjs +300 -74
  109. package/dist/stream-collapse.cjs.map +1 -1
  110. package/dist/stream-collapse.d.cts +17 -1
  111. package/dist/stream-collapse.d.cts.map +1 -1
  112. package/dist/stream-collapse.d.ts +17 -1
  113. package/dist/stream-collapse.d.ts.map +1 -1
  114. package/dist/stream-collapse.js +300 -74
  115. package/dist/stream-collapse.js.map +1 -1
  116. package/dist/types.d.cts +104 -7
  117. package/dist/types.d.cts.map +1 -1
  118. package/dist/types.d.ts +104 -7
  119. package/dist/types.d.ts.map +1 -1
  120. package/dist/veo-video.cjs +794 -0
  121. package/dist/veo-video.cjs.map +1 -0
  122. package/dist/veo-video.d.cts +50 -0
  123. package/dist/veo-video.d.cts.map +1 -0
  124. package/dist/veo-video.d.ts +50 -0
  125. package/dist/veo-video.d.ts.map +1 -0
  126. package/dist/veo-video.js +789 -0
  127. package/dist/veo-video.js.map +1 -0
  128. package/dist/video-proxy-shared.cjs +145 -0
  129. package/dist/video-proxy-shared.cjs.map +1 -0
  130. package/dist/video-proxy-shared.js +140 -0
  131. package/dist/video-proxy-shared.js.map +1 -0
  132. package/dist/ws-gemini-live.cjs +96 -3
  133. package/dist/ws-gemini-live.cjs.map +1 -1
  134. package/dist/ws-gemini-live.d.cts.map +1 -1
  135. package/dist/ws-gemini-live.d.ts.map +1 -1
  136. package/dist/ws-gemini-live.js +97 -4
  137. package/dist/ws-gemini-live.js.map +1 -1
  138. package/dist/ws-realtime.cjs +281 -4
  139. package/dist/ws-realtime.cjs.map +1 -1
  140. package/dist/ws-realtime.d.cts.map +1 -1
  141. package/dist/ws-realtime.d.ts.map +1 -1
  142. package/dist/ws-realtime.js +282 -5
  143. package/dist/ws-realtime.js.map +1 -1
  144. package/dist/ws-responses.cjs +1 -1
  145. package/dist/ws-responses.cjs.map +1 -1
  146. package/dist/ws-responses.js +1 -1
  147. package/dist/ws-responses.js.map +1 -1
  148. package/fixtures/examples/llm/blocks-tool-first.json +13 -0
  149. package/package.json +1 -1
  150. package/skills/write-fixtures/SKILL.md +19 -1
@@ -12,6 +12,88 @@ let node_zlib = require("node:zlib");
12
12
  * text followed by tool calls.
13
13
  */
14
14
  /**
15
+ * Normalize a tool call's accumulated `arguments` into valid JSON exactly like
16
+ * the flat-`toolCalls` recorder path: an empty / whitespace-only / missing
17
+ * value becomes `"{}"`, never `""`. Mirrors `recorder.ts` `toToolCallArguments`
18
+ * so a `blocks[].arguments` value is always parseable JSON and never disagrees
19
+ * with the flat `toolCalls` entry for the same call.
20
+ */
21
+ function normalizeToolArguments(args) {
22
+ if (args === void 0 || args.trim() === "") return "{}";
23
+ return args;
24
+ }
25
+ /**
26
+ * Build a finalized {@link FixtureBlock.toolCall} from a tool-call accumulator,
27
+ * normalizing `arguments` so the block agrees byte-for-byte with the flat
28
+ * `toolCalls` entry built from the SAME accumulator object.
29
+ */
30
+ function toToolCallBlock(ref) {
31
+ return {
32
+ type: "toolCall",
33
+ name: ref.name,
34
+ arguments: normalizeToolArguments(ref.arguments),
35
+ ...ref.id ? { id: ref.id } : {}
36
+ };
37
+ }
38
+ /**
39
+ * Decide whether a recorded atom sequence is "interleaved" and, if so, build
40
+ * the ordered {@link FixtureBlock} list. Returns `undefined` when NOT
41
+ * interleaved (text-first, text-only, or tool-only) so callers leave
42
+ * `CollapseResult.blocks` unset and the recorder keeps the legacy shape.
43
+ *
44
+ * Interleaved ⇔ (a tool atom appears strictly before the first text atom) OR
45
+ * (a text atom appears after any tool atom). A stream with no tool atoms, or
46
+ * with no text atoms, is never interleaved. Text-first-then-tools is the common
47
+ * legacy case and is explicitly NOT interleaved.
48
+ *
49
+ * CONSISTENCY (#274): each toolCall block is derived from the SAME accumulator
50
+ * object referenced by its atom and normalized identically to the flat
51
+ * `toolCalls` path ({@link toToolCallBlock} / {@link normalizeToolArguments}).
52
+ * Because the atom `ref` is the very object the flat list is built from, the
53
+ * block and its flat counterpart describe the same call by identity — even when
54
+ * upstream tool-call indices do not match stream-arrival order. Empty/missing
55
+ * arguments normalize to `"{}"` in BOTH representations, never `""`.
56
+ */
57
+ function buildOrderedBlocks(atoms) {
58
+ let firstTextIndex = -1;
59
+ let firstToolIndex = -1;
60
+ let textAfterTool = false;
61
+ let sawTool = false;
62
+ let sawText = false;
63
+ for (let i = 0; i < atoms.length; i++) if (atoms[i].kind === "text") {
64
+ sawText = true;
65
+ if (firstTextIndex === -1) firstTextIndex = i;
66
+ if (sawTool) textAfterTool = true;
67
+ } else {
68
+ sawTool = true;
69
+ if (firstToolIndex === -1) firstToolIndex = i;
70
+ }
71
+ if (!sawTool || !sawText) return void 0;
72
+ if (!(firstToolIndex < firstTextIndex) && !textAfterTool) return void 0;
73
+ const blocks = [];
74
+ let pendingText = "";
75
+ let hasPendingText = false;
76
+ const flushText = () => {
77
+ if (hasPendingText) {
78
+ blocks.push({
79
+ type: "text",
80
+ text: pendingText
81
+ });
82
+ pendingText = "";
83
+ hasPendingText = false;
84
+ }
85
+ };
86
+ for (const a of atoms) if (a.kind === "text") {
87
+ pendingText += a.text;
88
+ hasPendingText = true;
89
+ } else {
90
+ flushText();
91
+ blocks.push(toToolCallBlock(a.ref));
92
+ }
93
+ flushText();
94
+ return blocks;
95
+ }
96
+ /**
15
97
  * The opaque `data` of a non-empty Anthropic `redacted_thinking` block, or
16
98
  * `undefined` if `block` is not a redacted_thinking block or carries empty/no
17
99
  * data. NON-EMPTY is required: the replay-side validator rejects a leading
@@ -96,6 +178,7 @@ function collapseOpenAISSE(body) {
96
178
  const toolCallMap = /* @__PURE__ */ new Map();
97
179
  let nextSyntheticIndex = 1e6;
98
180
  const idKeyMap = /* @__PURE__ */ new Map();
181
+ const orderAtoms = [];
99
182
  for (const line of lines) {
100
183
  const data = extractSSEData(splitSSELines(line));
101
184
  if (data === void 0) continue;
@@ -133,7 +216,13 @@ function collapseOpenAISSE(body) {
133
216
  const delta = choices[0].delta;
134
217
  if (!delta) continue;
135
218
  if (typeof delta.reasoning_content === "string") reasoning += delta.reasoning_content;
136
- if (typeof delta.content === "string") content += delta.content;
219
+ if (typeof delta.content === "string") {
220
+ content += delta.content;
221
+ if (delta.content.length > 0) orderAtoms.push({
222
+ kind: "text",
223
+ text: delta.content
224
+ });
225
+ }
137
226
  const toolCalls = delta.tool_calls;
138
227
  if (toolCalls) for (const tc of toolCalls) {
139
228
  const fn = tc.function;
@@ -148,11 +237,18 @@ function collapseOpenAISSE(body) {
148
237
  idKeyMap.set(rawId, index);
149
238
  }
150
239
  } else index = nextSyntheticIndex++;
151
- if (!toolCallMap.has(index)) toolCallMap.set(index, {
152
- id: rawId ?? "",
153
- name: fn?.name ?? "",
154
- arguments: ""
155
- });
240
+ if (!toolCallMap.has(index)) {
241
+ const created = {
242
+ id: rawId ?? "",
243
+ name: fn?.name ?? "",
244
+ arguments: ""
245
+ };
246
+ toolCallMap.set(index, created);
247
+ orderAtoms.push({
248
+ kind: "toolCall",
249
+ ref: created
250
+ });
251
+ }
156
252
  const entry = toolCallMap.get(index);
157
253
  if (fn?.name && typeof fn.name === "string" && !entry.name) entry.name = fn.name;
158
254
  if (tc.id && typeof tc.id === "string" && !entry.id) entry.id = tc.id;
@@ -172,14 +268,21 @@ function collapseOpenAISSE(body) {
172
268
  }
173
269
  }
174
270
  if (toolCallMap.size > 0 || harmonyToolCalls.length > 0) {
175
- const sorted = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b);
271
+ const blocks = buildOrderedBlocks(orderAtoms);
272
+ const orderedToolCalls = orderAtoms.filter((a) => a.kind === "toolCall").map((a) => ({
273
+ name: a.ref.name,
274
+ arguments: normalizeToolArguments(a.ref.arguments),
275
+ ...a.ref.id ? { id: a.ref.id } : {}
276
+ }));
277
+ const indexSortedToolCalls = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b).map(([, tc]) => ({
278
+ name: tc.name,
279
+ arguments: normalizeToolArguments(tc.arguments),
280
+ ...tc.id ? { id: tc.id } : {}
281
+ }));
176
282
  return {
283
+ ...blocks ? { blocks } : {},
177
284
  ...content ? { content } : {},
178
- toolCalls: [...sorted.map(([, tc]) => ({
179
- name: tc.name,
180
- arguments: tc.arguments,
181
- ...tc.id ? { id: tc.id } : {}
182
- })), ...harmonyToolCalls],
285
+ toolCalls: [...blocks ? orderedToolCalls : indexSortedToolCalls, ...harmonyToolCalls],
183
286
  ...reasoning ? { reasoning } : {},
184
287
  ...webSearchQueries.length > 0 ? { webSearches: webSearchQueries } : {},
185
288
  ...droppedChunks > 0 ? { droppedChunks } : {},
@@ -216,6 +319,7 @@ function collapseAnthropicSSE(body) {
216
319
  const toolCallMap = /* @__PURE__ */ new Map();
217
320
  let nextSyntheticIndex = 1e6;
218
321
  let lastSyntheticIndex;
322
+ const orderAtoms = [];
219
323
  for (const block of blocks) {
220
324
  const lines = splitSSELines(block);
221
325
  const eventLine = lines.find((l) => l.startsWith("event:"));
@@ -240,17 +344,28 @@ function collapseAnthropicSSE(body) {
240
344
  if (typeof parsed.index === "number") index = parsed.index;
241
345
  else index = nextSyntheticIndex++;
242
346
  lastSyntheticIndex = index;
243
- toolCallMap.set(index, {
347
+ const created = {
244
348
  id: contentBlock.id ?? "",
245
349
  name: contentBlock.name ?? "",
246
350
  arguments: ""
351
+ };
352
+ toolCallMap.set(index, created);
353
+ orderAtoms.push({
354
+ kind: "toolCall",
355
+ ref: created
247
356
  });
248
357
  }
249
358
  }
250
359
  if (eventType === "content_block_delta") {
251
360
  const delta = parsed.delta;
252
361
  if (!delta) continue;
253
- if (delta.type === "text_delta" && typeof delta.text === "string") content += delta.text;
362
+ if (delta.type === "text_delta" && typeof delta.text === "string") {
363
+ content += delta.text;
364
+ if (delta.text.length > 0) orderAtoms.push({
365
+ kind: "text",
366
+ text: delta.text
367
+ });
368
+ }
254
369
  if (delta.type === "thinking_delta" && typeof delta.thinking === "string") reasoning += delta.thinking;
255
370
  if (delta.type === "signature_delta" && typeof delta.signature === "string") reasoningSignature = delta.signature;
256
371
  if (delta.type === "input_json_delta" && typeof delta.partial_json === "string") {
@@ -265,14 +380,21 @@ function collapseAnthropicSSE(body) {
265
380
  }
266
381
  }
267
382
  if (toolCallMap.size > 0) {
268
- const sorted = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b);
383
+ const orderedBlocks = buildOrderedBlocks(orderAtoms);
384
+ const orderedToolCalls = orderAtoms.filter((a) => a.kind === "toolCall").map((a) => ({
385
+ name: a.ref.name,
386
+ arguments: normalizeToolArguments(a.ref.arguments),
387
+ ...a.ref.id ? { id: a.ref.id } : {}
388
+ }));
389
+ const indexSortedToolCalls = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b).map(([, tc]) => ({
390
+ name: tc.name,
391
+ arguments: normalizeToolArguments(tc.arguments),
392
+ ...tc.id ? { id: tc.id } : {}
393
+ }));
269
394
  return {
395
+ ...orderedBlocks ? { blocks: orderedBlocks } : {},
270
396
  ...content ? { content } : {},
271
- toolCalls: sorted.map(([, tc]) => ({
272
- name: tc.name,
273
- arguments: tc.arguments,
274
- ...tc.id ? { id: tc.id } : {}
275
- })),
397
+ toolCalls: orderedBlocks ? orderedToolCalls : indexSortedToolCalls,
276
398
  ...reasoning ? { reasoning } : {},
277
399
  ...reasoningSignature ? { reasoningSignature } : {},
278
400
  ...redactedThinking.length > 0 ? { redactedThinking } : {},
@@ -304,6 +426,7 @@ function collapseGeminiSSE(body) {
304
426
  let audioB64 = "";
305
427
  let audioMimeType;
306
428
  const toolCalls = [];
429
+ const orderAtoms = [];
307
430
  for (const line of lines) {
308
431
  const data = extractSSEData(splitSSELines(line));
309
432
  if (data === void 0) continue;
@@ -324,33 +447,52 @@ function collapseGeminiSSE(body) {
324
447
  if (!parts || parts.length === 0) continue;
325
448
  for (const part of parts) if (part.functionCall) {
326
449
  const fc = part.functionCall;
327
- toolCalls.push({
450
+ const created = {
328
451
  name: String(fc.name ?? ""),
329
452
  arguments: typeof fc.args === "string" ? fc.args : JSON.stringify(fc.args ?? {})
453
+ };
454
+ toolCalls.push(created);
455
+ orderAtoms.push({
456
+ kind: "toolCall",
457
+ ref: created
330
458
  });
331
459
  } else if (part.inlineData && typeof part.inlineData.mimeType === "string" && part.inlineData.mimeType.startsWith("audio/")) {
332
460
  const inlineData = part.inlineData;
333
461
  if (!audioMimeType) audioMimeType = inlineData.mimeType;
334
462
  if (typeof inlineData.data === "string") audioB64 += inlineData.data;
335
463
  } else if (typeof part.text === "string") if (part.thought) reasoning += part.text;
336
- else content += part.text;
464
+ else {
465
+ content += part.text;
466
+ if (part.text.length > 0) orderAtoms.push({
467
+ kind: "text",
468
+ text: part.text
469
+ });
470
+ }
337
471
  }
472
+ const normalizedToolCalls = toolCalls.map((tc) => ({
473
+ ...tc,
474
+ arguments: normalizeToolArguments(tc.arguments)
475
+ }));
338
476
  if (audioB64) return {
339
477
  audioB64,
340
478
  audioMimeType,
341
479
  ...content ? { content } : {},
342
480
  ...reasoning ? { reasoning } : {},
343
- ...toolCalls.length > 0 ? { toolCalls } : {},
344
- ...droppedChunks > 0 ? { droppedChunks } : {},
345
- ...firstDroppedSample ? { firstDroppedSample } : {}
346
- };
347
- if (toolCalls.length > 0) return {
348
- ...content ? { content } : {},
349
- toolCalls,
350
- ...reasoning ? { reasoning } : {},
481
+ ...normalizedToolCalls.length > 0 ? { toolCalls: normalizedToolCalls } : {},
351
482
  ...droppedChunks > 0 ? { droppedChunks } : {},
352
483
  ...firstDroppedSample ? { firstDroppedSample } : {}
353
484
  };
485
+ if (toolCalls.length > 0) {
486
+ const blocks = buildOrderedBlocks(orderAtoms);
487
+ return {
488
+ ...blocks ? { blocks } : {},
489
+ ...content ? { content } : {},
490
+ toolCalls: normalizedToolCalls,
491
+ ...reasoning ? { reasoning } : {},
492
+ ...droppedChunks > 0 ? { droppedChunks } : {},
493
+ ...firstDroppedSample ? { firstDroppedSample } : {}
494
+ };
495
+ }
354
496
  return {
355
497
  content,
356
498
  ...reasoning ? { reasoning } : {},
@@ -381,6 +523,7 @@ function collapseOllamaNDJSON(body) {
381
523
  let harmonyUnparsed = false;
382
524
  let harmonyNote;
383
525
  const toolCalls = [];
526
+ const orderAtoms = [];
384
527
  for (const line of lines) {
385
528
  let parsed;
386
529
  try {
@@ -392,15 +535,34 @@ function collapseOllamaNDJSON(body) {
392
535
  }
393
536
  const message = parsed.message;
394
537
  if (message) {
395
- if (typeof message.content === "string") content += message.content;
538
+ if (typeof message.content === "string") {
539
+ content += message.content;
540
+ if (message.content.length > 0) orderAtoms.push({
541
+ kind: "text",
542
+ text: message.content
543
+ });
544
+ }
396
545
  if (Array.isArray(message.tool_calls)) for (const tc of message.tool_calls) {
397
546
  const fn = tc.function;
398
- if (fn) toolCalls.push({
399
- name: String(fn.name ?? ""),
400
- arguments: typeof fn.arguments === "string" ? fn.arguments : JSON.stringify(fn.arguments ?? {})
401
- });
547
+ if (fn) {
548
+ const created = {
549
+ name: String(fn.name ?? ""),
550
+ arguments: typeof fn.arguments === "string" ? fn.arguments : JSON.stringify(fn.arguments ?? {})
551
+ };
552
+ toolCalls.push(created);
553
+ orderAtoms.push({
554
+ kind: "toolCall",
555
+ ref: created
556
+ });
557
+ }
402
558
  }
403
- } else if (typeof parsed.response === "string") content += parsed.response;
559
+ } else if (typeof parsed.response === "string") {
560
+ content += parsed.response;
561
+ if (parsed.response.length > 0) orderAtoms.push({
562
+ kind: "text",
563
+ text: parsed.response
564
+ });
565
+ }
404
566
  }
405
567
  if (toolCalls.length === 0 && require_harmony.isHarmonyContent(content)) {
406
568
  const parsedHarmony = require_harmony.parseHarmonyContent(content);
@@ -413,15 +575,23 @@ function collapseOllamaNDJSON(body) {
413
575
  toolCalls.push(...parsedHarmony.toolCalls);
414
576
  }
415
577
  }
416
- if (toolCalls.length > 0) return {
417
- ...content ? { content } : {},
418
- toolCalls,
419
- ...reasoning ? { reasoning } : {},
420
- ...droppedChunks > 0 ? { droppedChunks } : {},
421
- ...firstDroppedSample ? { firstDroppedSample } : {},
422
- ...harmonyUnparsed ? { harmonyUnparsed: true } : {},
423
- ...harmonyNote ? { harmonyNote } : {}
424
- };
578
+ if (toolCalls.length > 0) {
579
+ const blocks = buildOrderedBlocks(orderAtoms);
580
+ const normalizedToolCalls = toolCalls.map((tc) => ({
581
+ ...tc,
582
+ arguments: normalizeToolArguments(tc.arguments)
583
+ }));
584
+ return {
585
+ ...blocks ? { blocks } : {},
586
+ ...content ? { content } : {},
587
+ toolCalls: normalizedToolCalls,
588
+ ...reasoning ? { reasoning } : {},
589
+ ...droppedChunks > 0 ? { droppedChunks } : {},
590
+ ...firstDroppedSample ? { firstDroppedSample } : {},
591
+ ...harmonyUnparsed ? { harmonyUnparsed: true } : {},
592
+ ...harmonyNote ? { harmonyNote } : {}
593
+ };
594
+ }
425
595
  return {
426
596
  content,
427
597
  ...reasoning ? { reasoning } : {},
@@ -446,6 +616,7 @@ function collapseCohereSSE(body) {
446
616
  const toolCallMap = /* @__PURE__ */ new Map();
447
617
  let nextSyntheticIndex = 1e6;
448
618
  let lastStartKey;
619
+ const orderAtoms = [];
449
620
  for (const block of blocks) {
450
621
  const lines = splitSSELines(block);
451
622
  const eventLine = lines.find((l) => l.startsWith("event:"));
@@ -464,7 +635,13 @@ function collapseCohereSSE(body) {
464
635
  if (eventType === "content-delta") {
465
636
  const contentObj = (parsed.delta?.message)?.content;
466
637
  if (contentObj && contentObj.type === "thinking" && typeof contentObj.thinking === "string") reasoning += contentObj.thinking;
467
- else if (contentObj && typeof contentObj.text === "string") content += contentObj.text;
638
+ else if (contentObj && typeof contentObj.text === "string") {
639
+ content += contentObj.text;
640
+ if (contentObj.text.length > 0) orderAtoms.push({
641
+ kind: "text",
642
+ text: contentObj.text
643
+ });
644
+ }
468
645
  }
469
646
  if (eventType === "tool-call-start") {
470
647
  let index;
@@ -474,10 +651,15 @@ function collapseCohereSSE(body) {
474
651
  const toolCalls = (parsed.delta?.message)?.tool_calls;
475
652
  if (toolCalls) {
476
653
  const fn = toolCalls.function;
477
- toolCallMap.set(index, {
654
+ const created = {
478
655
  id: toolCalls.id ?? "",
479
656
  name: fn?.name ?? "",
480
657
  arguments: ""
658
+ };
659
+ toolCallMap.set(index, created);
660
+ orderAtoms.push({
661
+ kind: "toolCall",
662
+ ref: created
481
663
  });
482
664
  }
483
665
  }
@@ -498,14 +680,21 @@ function collapseCohereSSE(body) {
498
680
  }
499
681
  }
500
682
  if (toolCallMap.size > 0) {
501
- const sorted = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b);
683
+ const orderedBlocks = buildOrderedBlocks(orderAtoms);
684
+ const orderedToolCalls = orderAtoms.filter((a) => a.kind === "toolCall").map((a) => ({
685
+ name: a.ref.name,
686
+ arguments: normalizeToolArguments(a.ref.arguments),
687
+ ...a.ref.id ? { id: a.ref.id } : {}
688
+ }));
689
+ const indexSortedToolCalls = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b).map(([, tc]) => ({
690
+ name: tc.name,
691
+ arguments: normalizeToolArguments(tc.arguments),
692
+ ...tc.id ? { id: tc.id } : {}
693
+ }));
502
694
  return {
695
+ ...orderedBlocks ? { blocks: orderedBlocks } : {},
503
696
  ...content ? { content } : {},
504
- toolCalls: sorted.map(([, tc]) => ({
505
- name: tc.name,
506
- arguments: tc.arguments,
507
- ...tc.id ? { id: tc.id } : {}
508
- })),
697
+ toolCalls: orderedBlocks ? orderedToolCalls : indexSortedToolCalls,
509
698
  ...reasoning ? { reasoning } : {},
510
699
  ...droppedChunks > 0 ? { droppedChunks } : {},
511
700
  ...firstDroppedSample ? { firstDroppedSample } : {}
@@ -618,6 +807,7 @@ function collapseBedrockEventStream(body) {
618
807
  let droppedChunks = 0;
619
808
  let firstDroppedSample;
620
809
  const toolCallMap = /* @__PURE__ */ new Map();
810
+ const orderAtoms = [];
621
811
  for (const frame of frames) {
622
812
  const frameStr = frame.payload.toString("utf8");
623
813
  let parsed;
@@ -630,7 +820,13 @@ function collapseBedrockEventStream(body) {
630
820
  }
631
821
  if (parsed.type === "content_block_delta") {
632
822
  const delta = parsed.delta;
633
- if (delta?.type === "text_delta" && typeof delta.text === "string") content += delta.text;
823
+ if (delta?.type === "text_delta" && typeof delta.text === "string") {
824
+ content += delta.text;
825
+ if (delta.text.length > 0) orderAtoms.push({
826
+ kind: "text",
827
+ text: delta.text
828
+ });
829
+ }
634
830
  if (delta?.type === "thinking_delta" && typeof delta.thinking === "string") reasoning += delta.thinking;
635
831
  if (delta?.type === "signature_delta" && typeof delta.signature === "string") reasoningSignature = delta.signature;
636
832
  if (delta?.type === "input_json_delta" && typeof delta.partial_json === "string") {
@@ -649,11 +845,18 @@ function collapseBedrockEventStream(body) {
649
845
  const index = parsed.index;
650
846
  const redactedData = capturedRedactedData(block);
651
847
  if (redactedData !== void 0) redactedThinking.push(redactedData);
652
- if (block?.type === "tool_use" && index !== void 0) toolCallMap.set(index, {
653
- id: block.id ?? "",
654
- name: block.name ?? "",
655
- arguments: ""
656
- });
848
+ if (block?.type === "tool_use" && index !== void 0) {
849
+ const created = {
850
+ id: block.id ?? "",
851
+ name: block.name ?? "",
852
+ arguments: ""
853
+ };
854
+ toolCallMap.set(index, created);
855
+ orderAtoms.push({
856
+ kind: "toolCall",
857
+ ref: created
858
+ });
859
+ }
657
860
  continue;
658
861
  }
659
862
  if (parsed.contentBlockStart) {
@@ -662,10 +865,15 @@ function collapseBedrockEventStream(body) {
662
865
  const start = blockStart.start;
663
866
  if (start?.toolUse && index !== void 0) {
664
867
  const toolUse = start.toolUse;
665
- toolCallMap.set(index, {
868
+ const created = {
666
869
  id: toolUse.toolUseId ?? "",
667
870
  name: toolUse.name ?? "",
668
871
  arguments: ""
872
+ };
873
+ toolCallMap.set(index, created);
874
+ orderAtoms.push({
875
+ kind: "toolCall",
876
+ ref: created
669
877
  });
670
878
  }
671
879
  }
@@ -674,7 +882,13 @@ function collapseBedrockEventStream(body) {
674
882
  const index = parsed.contentBlockIndex ?? blockDelta.contentBlockIndex;
675
883
  const delta = blockDelta.delta;
676
884
  if (!delta) continue;
677
- if (typeof delta.text === "string") content += delta.text;
885
+ if (typeof delta.text === "string") {
886
+ content += delta.text;
887
+ if (delta.text.length > 0) orderAtoms.push({
888
+ kind: "text",
889
+ text: delta.text
890
+ });
891
+ }
678
892
  if (typeof delta.reasoningContent === "object" && delta.reasoningContent !== null) {
679
893
  const reasoningDelta = delta.reasoningContent;
680
894
  if (typeof reasoningDelta.text === "string") reasoning += reasoningDelta.text;
@@ -692,19 +906,30 @@ function collapseBedrockEventStream(body) {
692
906
  }
693
907
  }
694
908
  }
695
- if (toolCallMap.size > 0) return {
696
- toolCalls: Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b).map(([, tc]) => ({
909
+ if (toolCallMap.size > 0) {
910
+ const orderedBlocks = buildOrderedBlocks(orderAtoms);
911
+ const orderedToolCalls = orderAtoms.filter((a) => a.kind === "toolCall").map((a) => ({
912
+ name: a.ref.name,
913
+ arguments: normalizeToolArguments(a.ref.arguments),
914
+ ...a.ref.id ? { id: a.ref.id } : {}
915
+ }));
916
+ const indexSortedToolCalls = Array.from(toolCallMap.entries()).sort(([a], [b]) => a - b).map(([, tc]) => ({
697
917
  name: tc.name,
698
- arguments: tc.arguments,
918
+ arguments: normalizeToolArguments(tc.arguments),
699
919
  ...tc.id ? { id: tc.id } : {}
700
- })),
701
- ...reasoning ? { reasoning } : {},
702
- ...reasoningSignature ? { reasoningSignature } : {},
703
- ...redactedThinking.length > 0 ? { redactedThinking } : {},
704
- ...droppedChunks > 0 ? { droppedChunks } : {},
705
- ...firstDroppedSample ? { firstDroppedSample } : {},
706
- ...truncated ? { truncated } : {}
707
- };
920
+ }));
921
+ return {
922
+ ...orderedBlocks ? { blocks: orderedBlocks } : {},
923
+ ...content ? { content } : {},
924
+ toolCalls: orderedBlocks ? orderedToolCalls : indexSortedToolCalls,
925
+ ...reasoning ? { reasoning } : {},
926
+ ...reasoningSignature ? { reasoningSignature } : {},
927
+ ...redactedThinking.length > 0 ? { redactedThinking } : {},
928
+ ...droppedChunks > 0 ? { droppedChunks } : {},
929
+ ...firstDroppedSample ? { firstDroppedSample } : {},
930
+ ...truncated ? { truncated } : {}
931
+ };
932
+ }
708
933
  return {
709
934
  content,
710
935
  ...reasoning ? { reasoning } : {},
@@ -778,7 +1003,7 @@ function collapseGeminiInteractionsSSE(body) {
778
1003
  }
779
1004
  } else if (delta.type === "function_call") toolCalls.push({
780
1005
  name: String(delta.name ?? ""),
781
- arguments: typeof delta.arguments === "string" ? delta.arguments : JSON.stringify(delta.arguments ?? {}),
1006
+ arguments: typeof delta.arguments === "string" ? normalizeToolArguments(delta.arguments) : JSON.stringify(delta.arguments ?? {}),
782
1007
  ...delta.id ? { id: String(delta.id) } : {}
783
1008
  });
784
1009
  else if (delta.type === "thought_summary") {
@@ -797,11 +1022,12 @@ function collapseGeminiInteractionsSSE(body) {
797
1022
  } catch {
798
1023
  droppedChunks++;
799
1024
  if (droppedChunks === 1) firstDroppedSample = `assembled arguments_delta not valid JSON for "${tc.name}": ${surrogateSafeSlice(args, 200)}`;
1025
+ args = "{}";
800
1026
  }
801
1027
  } else args = typeof tc.argsObj === "string" ? tc.argsObj : JSON.stringify(tc.argsObj ?? {});
802
1028
  toolCalls.push({
803
1029
  name: tc.name,
804
- arguments: args,
1030
+ arguments: normalizeToolArguments(args),
805
1031
  ...tc.id ? { id: tc.id } : {}
806
1032
  });
807
1033
  }