@copilotkit/aimock 1.38.0 → 1.40.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 (81) 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 +24 -2
  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-stub.d.cts +2 -2
  14. package/dist/agui-stub.d.ts +2 -2
  15. package/dist/agui-types.d.cts +84 -3
  16. package/dist/agui-types.d.cts.map +1 -1
  17. package/dist/agui-types.d.ts +84 -3
  18. package/dist/agui-types.d.ts.map +1 -1
  19. package/dist/aimock-cli.cjs +1 -1
  20. package/dist/aimock-cli.cjs.map +1 -1
  21. package/dist/aimock-cli.js +1 -1
  22. package/dist/aimock-cli.js.map +1 -1
  23. package/dist/cli.cjs +10 -10
  24. package/dist/cli.cjs.map +1 -1
  25. package/dist/cli.js +10 -10
  26. package/dist/cli.js.map +1 -1
  27. package/dist/config-loader.d.cts.map +1 -1
  28. package/dist/helpers.cjs +8 -4
  29. package/dist/helpers.cjs.map +1 -1
  30. package/dist/helpers.d.cts.map +1 -1
  31. package/dist/helpers.d.ts.map +1 -1
  32. package/dist/helpers.js +8 -4
  33. package/dist/helpers.js.map +1 -1
  34. package/dist/index.d.cts +2 -2
  35. package/dist/index.d.ts +2 -2
  36. package/dist/llmock.cjs +23 -9
  37. package/dist/llmock.cjs.map +1 -1
  38. package/dist/llmock.d.cts +22 -0
  39. package/dist/llmock.d.cts.map +1 -1
  40. package/dist/llmock.d.ts +22 -0
  41. package/dist/llmock.d.ts.map +1 -1
  42. package/dist/llmock.js +25 -11
  43. package/dist/llmock.js.map +1 -1
  44. package/dist/openrouter-chat.cjs +41 -0
  45. package/dist/openrouter-chat.cjs.map +1 -1
  46. package/dist/openrouter-chat.js +41 -0
  47. package/dist/openrouter-chat.js.map +1 -1
  48. package/dist/openrouter-video.cjs.map +1 -1
  49. package/dist/openrouter-video.js.map +1 -1
  50. package/dist/recorder.cjs +77 -8
  51. package/dist/recorder.cjs.map +1 -1
  52. package/dist/recorder.d.cts.map +1 -1
  53. package/dist/recorder.d.ts.map +1 -1
  54. package/dist/recorder.js +77 -8
  55. package/dist/recorder.js.map +1 -1
  56. package/dist/server.cjs +80 -17
  57. package/dist/server.cjs.map +1 -1
  58. package/dist/server.d.cts +6 -1
  59. package/dist/server.d.cts.map +1 -1
  60. package/dist/server.d.ts +6 -1
  61. package/dist/server.d.ts.map +1 -1
  62. package/dist/server.js +80 -18
  63. package/dist/server.js.map +1 -1
  64. package/dist/stream-collapse.cjs +97 -6
  65. package/dist/stream-collapse.cjs.map +1 -1
  66. package/dist/stream-collapse.d.cts +16 -0
  67. package/dist/stream-collapse.d.cts.map +1 -1
  68. package/dist/stream-collapse.d.ts +16 -0
  69. package/dist/stream-collapse.d.ts.map +1 -1
  70. package/dist/stream-collapse.js +97 -6
  71. package/dist/stream-collapse.js.map +1 -1
  72. package/dist/types.d.cts +22 -3
  73. package/dist/types.d.cts.map +1 -1
  74. package/dist/types.d.ts +22 -3
  75. package/dist/types.d.ts.map +1 -1
  76. package/dist/vector-types.d.ts.map +1 -1
  77. package/dist/ws-gemini-live.cjs +41 -6
  78. package/dist/ws-gemini-live.cjs.map +1 -1
  79. package/dist/ws-gemini-live.js +41 -6
  80. package/dist/ws-gemini-live.js.map +1 -1
  81. package/package.json +5 -3
@@ -55,6 +55,22 @@ interface CollapseResult {
55
55
  */
56
56
  redactedThinking?: string[];
57
57
  webSearches?: string[];
58
+ /**
59
+ * The provider-reported `usage` object from the stream's final usage frame,
60
+ * captured VERBATIM (#368). OpenAI-compatible streams (including OpenRouter)
61
+ * close with a `chat.completion.chunk` whose `choices` is empty and whose
62
+ * `usage` carries the real token counts — plus, on OpenRouter,
63
+ * `cost` / `cost_details` / `native_tokens_*`. Collapsing dropped that frame,
64
+ * so a recorded fixture could only ever replay estimated (`ceil(len/4)`) token
65
+ * counts and never a provider-reported cost. Last-usage-wins: a stream that
66
+ * emits several usage frames keeps the final one. Absent when the upstream
67
+ * stream carried no usage (e.g. `stream_options.include_usage` unset).
68
+ *
69
+ * Kept as a loose record because the field set is provider-specific and
70
+ * forward-extending; the recorder sanitizes it into the fixture
71
+ * `response.usage` override shape before persisting.
72
+ */
73
+ usage?: Record<string, unknown>;
58
74
  toolCalls?: ToolCall[];
59
75
  droppedChunks?: number;
60
76
  firstDroppedSample?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"stream-collapse.d.ts","names":[],"sources":["../src/stream-collapse.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA2WA;AA4RA;AAkMA;AAyJA;AAmIA;AAyRA;;;;;AA8PA;AAwLA;;;;;;AAKiB,cAnxDJ,0BAmxDI,EAAA,MAAA;;iBAxwDD,8BAAA;UAgDC,cAAA;;;;gBAID;;;YACJ;;;;;;;;;;;;;;;;;;;;;;cAsBE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAgCH;;;;;;;;;;;;;;;;;;;iBA+MK,iBAAA,mBAAoC;;;;;;;;iBA4RpC,oBAAA,mBAAuC;;;;;;;iBAkMvC,iBAAA,mBAAoC;;;;;;;;;;;;;;;iBAyJpC,oBAAA,mBAAuC;;;;;;;iBAmIvC,iBAAA,mBAAoC;;;;;;;iBAyRpC,0BAAA,UAAoC,SAAS;;;;;;;;;;;;;;;iBA8P7C,6BAAA,mBAAgD;;;;;;iBAwLhD,yBAAA,mCAED,kCACE,iBACN,SACR"}
1
+ {"version":3,"file":"stream-collapse.d.ts","names":[],"sources":["../src/stream-collapse.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AA2XA;AAiaA;AAkMA;AAyJA;AAmIA;AA6RA;;;;;AA0RA;AAwLA;;;;;AAKG,cAx8DU,0BAw8DV,EAAA,MAAA;;iBA77Da,8BAAA;UAgDC,cAAA;;;;gBAID;;;YACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqCF;cACI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAgCH;;;;;;;;;;;;;;;;;;;iBA+MK,iBAAA,mBAAoC;;;;;;;;iBAiapC,oBAAA,mBAAuC;;;;;;;iBAkMvC,iBAAA,mBAAoC;;;;;;;;;;;;;;;iBAyJpC,oBAAA,mBAAuC;;;;;;;iBAmIvC,iBAAA,mBAAoC;;;;;;;iBA6RpC,0BAAA,UAAoC,SAAS;;;;;;;;;;;;;;;iBA0R7C,6BAAA,mBAAgD;;;;;;iBAwLhD,yBAAA,mCAED,kCACE,iBACN,SACR"}
@@ -244,6 +244,7 @@ function collapseOpenAISSE(rawBody) {
244
244
  let transcriptUsage;
245
245
  let reasoning = "";
246
246
  const webSearchQueries = [];
247
+ let usage;
247
248
  let droppedChunks = 0;
248
249
  let firstDroppedSample;
249
250
  let harmonyUnparsed = false;
@@ -251,6 +252,7 @@ function collapseOpenAISSE(rawBody) {
251
252
  const toolCallMap = /* @__PURE__ */ new Map();
252
253
  let nextSyntheticIndex = 1e6;
253
254
  const idKeyMap = /* @__PURE__ */ new Map();
255
+ let lastToolCallKey;
254
256
  const orderAtoms = [];
255
257
  for (const line of lines) {
256
258
  const data = extractSSEData(splitSSELines(line));
@@ -274,7 +276,7 @@ function collapseOpenAISSE(rawBody) {
274
276
  transcript = parsed.text;
275
277
  transcriptSeen = true;
276
278
  if (Array.isArray(parsed.languages)) transcriptLanguages = parsed.languages.filter((language) => typeof language === "object" && language !== null && typeof language.code === "string").map((language) => ({ code: language.code }));
277
- if (parsed.usage && typeof parsed.usage === "object") transcriptUsage = parsed.usage;
279
+ if (parsed.usage && typeof parsed.usage === "object" && !Array.isArray(parsed.usage) && Object.keys(parsed.usage).length > 0) transcriptUsage = parsed.usage;
278
280
  continue;
279
281
  }
280
282
  if (parsed.type === "response.reasoning_summary_text.delta" && typeof parsed.delta === "string") {
@@ -290,12 +292,90 @@ function collapseOpenAISSE(rawBody) {
290
292
  continue;
291
293
  }
292
294
  }
295
+ if (item?.type === "function_call" && typeof parsed.output_index === "number") {
296
+ const entry = toolCallMap.get(parsed.output_index);
297
+ if (entry) {
298
+ if (!entry.id && typeof item.call_id === "string") entry.id = item.call_id;
299
+ if (!entry.name && typeof item.name === "string") entry.name = item.name;
300
+ if (entry.arguments === "" && typeof item.arguments === "string") entry.arguments = item.arguments;
301
+ } else {
302
+ const created = {
303
+ id: typeof item.call_id === "string" ? item.call_id : "",
304
+ name: typeof item.name === "string" ? item.name : "",
305
+ arguments: typeof item.arguments === "string" ? item.arguments : ""
306
+ };
307
+ toolCallMap.set(parsed.output_index, created);
308
+ orderAtoms.push({
309
+ kind: "toolCall",
310
+ ref: created
311
+ });
312
+ }
313
+ continue;
314
+ }
315
+ }
316
+ if (parsed.type === "response.output_item.added") {
317
+ const item = parsed.item;
318
+ if (item?.type === "function_call" && typeof parsed.output_index === "number") {
319
+ if (!toolCallMap.has(parsed.output_index)) {
320
+ const created = {
321
+ id: typeof item.call_id === "string" ? item.call_id : "",
322
+ name: typeof item.name === "string" ? item.name : "",
323
+ arguments: ""
324
+ };
325
+ toolCallMap.set(parsed.output_index, created);
326
+ orderAtoms.push({
327
+ kind: "toolCall",
328
+ ref: created
329
+ });
330
+ }
331
+ continue;
332
+ }
333
+ }
334
+ if (parsed.type === "response.function_call_arguments.delta" && typeof parsed.delta === "string" && typeof parsed.output_index === "number") {
335
+ let entry = toolCallMap.get(parsed.output_index);
336
+ if (!entry) {
337
+ entry = {
338
+ id: "",
339
+ name: "",
340
+ arguments: ""
341
+ };
342
+ toolCallMap.set(parsed.output_index, entry);
343
+ orderAtoms.push({
344
+ kind: "toolCall",
345
+ ref: entry
346
+ });
347
+ }
348
+ entry.arguments += parsed.delta;
349
+ continue;
350
+ }
351
+ if (parsed.type === "response.function_call_arguments.done" && typeof parsed.output_index === "number") {
352
+ const entry = toolCallMap.get(parsed.output_index);
353
+ if (entry) {
354
+ if (entry.arguments === "" && typeof parsed.arguments === "string") entry.arguments = parsed.arguments;
355
+ } else if (typeof parsed.arguments === "string") {
356
+ const created = {
357
+ id: "",
358
+ name: "",
359
+ arguments: parsed.arguments
360
+ };
361
+ toolCallMap.set(parsed.output_index, created);
362
+ orderAtoms.push({
363
+ kind: "toolCall",
364
+ ref: created
365
+ });
366
+ }
367
+ continue;
293
368
  }
294
369
  if (parsed.type === "response.output_text.delta" && typeof parsed.delta === "string") {
295
370
  content += parsed.delta;
371
+ if (parsed.delta.length > 0) orderAtoms.push({
372
+ kind: "text",
373
+ text: parsed.delta
374
+ });
296
375
  continue;
297
376
  }
298
377
  if (typeof parsed.type === "string" && parsed.type.startsWith("response.")) continue;
378
+ if (parsed.usage && typeof parsed.usage === "object" && !Array.isArray(parsed.usage) && Object.keys(parsed.usage).length > 0) usage = parsed.usage;
299
379
  const choices = parsed.choices;
300
380
  if (!choices || choices.length === 0) continue;
301
381
  const delta = choices[0].delta;
@@ -321,7 +401,9 @@ function collapseOpenAISSE(rawBody) {
321
401
  index = nextSyntheticIndex++;
322
402
  idKeyMap.set(rawId, index);
323
403
  }
324
- } else index = nextSyntheticIndex++;
404
+ } else if (lastToolCallKey !== void 0) index = lastToolCallKey;
405
+ else index = nextSyntheticIndex++;
406
+ lastToolCallKey = index;
325
407
  if (!toolCallMap.has(index)) {
326
408
  const created = {
327
409
  id: rawId ?? "",
@@ -375,6 +457,7 @@ function collapseOpenAISSE(rawBody) {
375
457
  toolCalls: [...blocks ? orderedToolCalls : indexSortedToolCalls, ...harmonyToolCalls],
376
458
  ...reasoning ? { reasoning } : {},
377
459
  ...webSearchQueries.length > 0 ? { webSearches: webSearchQueries } : {},
460
+ ...usage ? { usage } : {},
378
461
  ...droppedChunks > 0 ? { droppedChunks } : {},
379
462
  ...firstDroppedSample ? { firstDroppedSample } : {},
380
463
  ...harmonyUnparsed ? { harmonyUnparsed: true } : {},
@@ -391,6 +474,7 @@ function collapseOpenAISSE(rawBody) {
391
474
  content,
392
475
  ...reasoning ? { reasoning } : {},
393
476
  ...webSearchQueries.length > 0 ? { webSearches: webSearchQueries } : {},
477
+ ...usage ? { usage } : {},
394
478
  ...droppedChunks > 0 ? { droppedChunks } : {},
395
479
  ...firstDroppedSample ? { firstDroppedSample } : {},
396
480
  ...harmonyUnparsed ? { harmonyUnparsed: true } : {},
@@ -755,7 +839,6 @@ function collapseCohereSSE(rawBody) {
755
839
  let index;
756
840
  if (typeof parsed.index === "number") index = parsed.index;
757
841
  else index = nextSyntheticIndex++;
758
- lastStartKey = index;
759
842
  const toolCalls = (parsed.delta?.message)?.tool_calls;
760
843
  if (toolCalls) {
761
844
  const fn = toolCalls.function;
@@ -765,6 +848,7 @@ function collapseCohereSSE(rawBody) {
765
848
  arguments: ""
766
849
  };
767
850
  toolCallMap.set(index, created);
851
+ lastStartKey = index;
768
852
  orderAtoms.push({
769
853
  kind: "toolCall",
770
854
  ref: created
@@ -958,7 +1042,7 @@ function collapseBedrockEventStream(rawBody) {
958
1042
  const index = parsed.index;
959
1043
  const redactedData = capturedRedactedData(block);
960
1044
  if (redactedData !== void 0) redactedThinking.push(redactedData);
961
- if (block?.type === "tool_use" && index !== void 0) {
1045
+ if (block?.type === "tool_use") if (index !== void 0) {
962
1046
  const created = {
963
1047
  id: block.id ?? "",
964
1048
  name: block.name ?? "",
@@ -969,6 +1053,9 @@ function collapseBedrockEventStream(rawBody) {
969
1053
  kind: "toolCall",
970
1054
  ref: created
971
1055
  });
1056
+ } else {
1057
+ droppedChunks++;
1058
+ if (droppedChunks === 1) firstDroppedSample = `tool_use content_block_start with no index — tool call identity lost: ${surrogateSafeSlice(frameStr, 200)}`;
972
1059
  }
973
1060
  continue;
974
1061
  }
@@ -976,7 +1063,7 @@ function collapseBedrockEventStream(rawBody) {
976
1063
  const blockStart = parsed.contentBlockStart;
977
1064
  const index = parsed.contentBlockIndex ?? blockStart.contentBlockIndex;
978
1065
  const start = blockStart.start;
979
- if (start?.toolUse && index !== void 0) {
1066
+ if (start?.toolUse) if (index !== void 0) {
980
1067
  const toolUse = start.toolUse;
981
1068
  const created = {
982
1069
  id: toolUse.toolUseId ?? "",
@@ -988,6 +1075,9 @@ function collapseBedrockEventStream(rawBody) {
988
1075
  kind: "toolCall",
989
1076
  ref: created
990
1077
  });
1078
+ } else {
1079
+ droppedChunks++;
1080
+ if (droppedChunks === 1) firstDroppedSample = `contentBlockStart toolUse with no index — tool call identity lost: ${surrogateSafeSlice(frameStr, 200)}`;
991
1081
  }
992
1082
  }
993
1083
  if (parsed.contentBlockDelta) {
@@ -1174,7 +1264,8 @@ function collapseStreamingResponse(contentType, providerKey, body, logger) {
1174
1264
  const str = typeof body === "string" ? body : body.toString("utf8");
1175
1265
  switch (providerKey) {
1176
1266
  case "openai":
1177
- case "azure": return collapseOpenAISSE(str);
1267
+ case "azure":
1268
+ case "openrouter": return collapseOpenAISSE(str);
1178
1269
  case "anthropic": return collapseAnthropicSSE(str);
1179
1270
  case "gemini":
1180
1271
  case "vertexai": return collapseGeminiSSE(str);