@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
@@ -1 +1 @@
1
- {"version":3,"file":"recorder.d.cts","names":[],"sources":["../src/recorder.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAkMiB,qBAAA;;;QAGT;;UAGS,YAAA;;;;;;;;;;;;;;;;;;mCAkBkB,oCAAoC;;;;;;;;;;;;;;;;;;;;;;KAuB3D,YAAA;;;;;;;;;;;;;;;iBA6MU,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yBACD,oCACI,+CAEH;WAEC;UACD;2BACiB,0BAA0B;+BAG3C,eACT,QAAQ"}
1
+ {"version":3,"file":"recorder.d.cts","names":[],"sources":["../src/recorder.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAmMiB,qBAAA;;;QAGT;;UAGS,YAAA;;;;;;;;;;;;;;;;;;mCAkBkB,oCAAoC;;;;;;;;;;;;;;;;;;;;;;KAuB3D,YAAA;;;;;;;;;;;;;;;iBA6MU,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yBACD,oCACI,+CAEH;WAEC;UACD;2BACiB,0BAA0B;+BAG3C,eACT,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"recorder.d.ts","names":[],"sources":["../src/recorder.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAkMiB,qBAAA;;;QAGT;;UAGS,YAAA;;;;;;;;;;;;;;;;;;mCAkBkB,oCAAoC;;;;;;;;;;;;;;;;;;;;;;KAuB3D,YAAA;;;;;;;;;;;;;;;iBA6MU,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yBACD,oCACI,+CAEH;WAEC;UACD;2BACiB,0BAA0B;+BAG3C,eACT,QAAQ"}
1
+ {"version":3,"file":"recorder.d.ts","names":[],"sources":["../src/recorder.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAmMiB,qBAAA;;;QAGT;;UAGS,YAAA;;;;;;;;;;;;;;;;;;mCAkBkB,oCAAoC;;;;;;;;;;;;;;;;;;;;;;KAuB3D,YAAA;;;;;;;;;;;;;;;iBA6MU,cAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yBACD,oCACI,+CAEH;WAEC;UACD;2BACiB,0BAA0B;+BAG3C,eACT,QAAQ"}
package/dist/recorder.js CHANGED
@@ -354,6 +354,8 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
354
354
  if (collapsed.truncated) defaults.logger.warn("Bedrock EventStream: CRC mismatch — response may be truncated");
355
355
  if (collapsed.droppedChunks && collapsed.droppedChunks > 0) defaults.logger.warn(`${collapsed.droppedChunks} chunk(s) dropped during stream collapse${collapsed.firstDroppedSample ? ` — first: ${collapsed.firstDroppedSample}` : ""}`);
356
356
  if (collapsed.harmonyUnparsed) defaults.logger.warn(`Harmony tokens present but unparseable — content preserved verbatim${collapsed.harmonyNote ? ` (${collapsed.harmonyNote})` : ""}`);
357
+ const collapsedUsage = sanitizeRecordedUsage(collapsed.usage);
358
+ const usageSpread = collapsedUsage ? { usage: collapsedUsage } : {};
357
359
  if (collapsed.transcription) fixtureResponse = { transcription: collapsed.transcription };
358
360
  else if (collapsed.audioB64) {
359
361
  const audioToolCallsSpread = collapsed.toolCalls && collapsed.toolCalls.length > 0 ? { toolCalls: collapsed.toolCalls.map((tc) => ({
@@ -384,7 +386,8 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
384
386
  ...reasoningSpread,
385
387
  ...reasoningSignatureSpread,
386
388
  ...redactedThinkingSpread,
387
- ...webSearchesSpread
389
+ ...webSearchesSpread,
390
+ ...usageSpread
388
391
  };
389
392
  } else {
390
393
  const reasoningSpread = collapsed.reasoning ? { reasoning: collapsed.reasoning } : {};
@@ -407,21 +410,24 @@ async function proxyAndRecord(req, res, request, providerKey, pathname, fixtures
407
410
  ...reasoningSpread,
408
411
  ...reasoningSignatureSpread,
409
412
  ...redactedThinkingSpread,
410
- ...webSearchesSpread
413
+ ...webSearchesSpread,
414
+ ...usageSpread
411
415
  };
412
416
  } else fixtureResponse = {
413
417
  toolCalls: sanitizedToolCalls,
414
418
  ...reasoningSpread,
415
419
  ...reasoningSignatureSpread,
416
420
  ...redactedThinkingSpread,
417
- ...webSearchesSpread
421
+ ...webSearchesSpread,
422
+ ...usageSpread
418
423
  };
419
424
  } else fixtureResponse = {
420
425
  content: collapsed.content ?? "",
421
426
  ...reasoningSpread,
422
427
  ...reasoningSignatureSpread,
423
428
  ...redactedThinkingSpread,
424
- ...webSearchesSpread
429
+ ...webSearchesSpread,
430
+ ...usageSpread
425
431
  };
426
432
  }
427
433
  } else {
@@ -771,6 +777,63 @@ function toToolCallArguments(raw) {
771
777
  return JSON.stringify(raw);
772
778
  }
773
779
  /**
780
+ * `usage` sub-objects that carry numeric breakdowns rather than a scalar. The
781
+ * inner fields are NOT allowlisted here on purpose: the recorder keeps every
782
+ * finite-numeric inner field (documented or forward-compat), matching the
783
+ * load-time validator in fixture-loader.ts, whose index-signature escape hatch
784
+ * accepts undocumented numeric inner keys too. A `Set` (own-key membership via
785
+ * `.has()`, no prototype-chain walk) mirrors that validator's
786
+ * `new Set(Object.keys(...))` classification so anything this recorder writes
787
+ * loads cleanly.
788
+ */
789
+ const USAGE_OBJECT_FIELDS = new Set([
790
+ "cost_details",
791
+ "prompt_tokens_details",
792
+ "completion_tokens_details"
793
+ ]);
794
+ /**
795
+ * Sanitize a provider-reported `usage` object into the fixture
796
+ * `response.usage` override shape (#368).
797
+ *
798
+ * The recorder persists real upstream usage so replay can serve the provider's
799
+ * ACTUAL token counts (instead of the `ceil(len/4)` estimate) and OpenRouter's
800
+ * `cost` — which previously never survived recording at all. Upstream usage is
801
+ * provider-specific and forward-extending, so this passes fields through rather
802
+ * than whitelisting them, but only in the shapes the fixture contract accepts:
803
+ *
804
+ * - numeric scalars (`prompt_tokens`, `cost`, `native_tokens_prompt`, …) — kept
805
+ * - `is_byok` boolean — kept
806
+ * - the documented breakdown objects — kept, with non-numeric inner fields
807
+ * dropped (the load-time validator rejects those, and a fixture the recorder
808
+ * writes must always load)
809
+ * - anything else (strings, arrays, nulls, unknown objects) — DROPPED, because
810
+ * `fixture-loader.ts` errors on a non-numeric extra `usage` key and a recorded
811
+ * fixture that fails validation is worse than one missing an exotic field
812
+ *
813
+ * Returns `undefined` when nothing survives, so the caller omits `usage`
814
+ * entirely and keeps pre-#368 fixtures byte-identical.
815
+ */
816
+ function sanitizeRecordedUsage(raw) {
817
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
818
+ const out = {};
819
+ for (const [key, val] of Object.entries(raw)) {
820
+ if (val === void 0 || val === null) continue;
821
+ if (USAGE_OBJECT_FIELDS.has(key)) {
822
+ if (typeof val !== "object" || val === null || Array.isArray(val)) continue;
823
+ const inner = {};
824
+ for (const [innerKey, innerVal] of Object.entries(val)) if (typeof innerVal === "number" && Number.isFinite(innerVal)) inner[innerKey] = innerVal;
825
+ if (Object.keys(inner).length > 0) out[key] = inner;
826
+ continue;
827
+ }
828
+ if (key === "is_byok") {
829
+ if (typeof val === "boolean") out[key] = val;
830
+ continue;
831
+ }
832
+ if (typeof val === "number" && Number.isFinite(val)) out[key] = val;
833
+ }
834
+ return Object.keys(out).length > 0 ? out : void 0;
835
+ }
836
+ /**
774
837
  * Detect the response format from the parsed upstream JSON and convert
775
838
  * it into an aimock FixtureResponse.
776
839
  */
@@ -877,6 +940,8 @@ function buildFixtureResponse(parsed, status, logger, request) {
877
940
  const hasToolCalls = Array.isArray(message.tool_calls) && message.tool_calls.length > 0;
878
941
  const hasContent = typeof message.content === "string" && message.content.length > 0;
879
942
  const openaiReasoning = typeof message.reasoning_content === "string" && message.reasoning_content.length > 0 ? message.reasoning_content : typeof message.reasoning === "string" && message.reasoning.length > 0 ? message.reasoning : void 0;
943
+ const openaiUsage = sanitizeRecordedUsage(obj.usage);
944
+ const usageSpread = openaiUsage ? { usage: openaiUsage } : {};
880
945
  if (hasToolCalls) {
881
946
  const toolCalls = message.tool_calls.map((tc) => {
882
947
  const fn = tc.function;
@@ -889,20 +954,24 @@ function buildFixtureResponse(parsed, status, logger, request) {
889
954
  if (hasContent) return {
890
955
  content: message.content,
891
956
  toolCalls,
892
- ...openaiReasoning ? { reasoning: openaiReasoning } : {}
957
+ ...openaiReasoning ? { reasoning: openaiReasoning } : {},
958
+ ...usageSpread
893
959
  };
894
960
  return {
895
961
  toolCalls,
896
- ...openaiReasoning ? { reasoning: openaiReasoning } : {}
962
+ ...openaiReasoning ? { reasoning: openaiReasoning } : {},
963
+ ...usageSpread
897
964
  };
898
965
  }
899
966
  if (hasContent) return {
900
967
  content: message.content,
901
- ...openaiReasoning ? { reasoning: openaiReasoning } : {}
968
+ ...openaiReasoning ? { reasoning: openaiReasoning } : {},
969
+ ...usageSpread
902
970
  };
903
971
  return {
904
972
  content: "",
905
- ...openaiReasoning ? { reasoning: openaiReasoning } : {}
973
+ ...openaiReasoning ? { reasoning: openaiReasoning } : {},
974
+ ...usageSpread
906
975
  };
907
976
  }
908
977
  }