assistant-stream 0.3.26 → 0.3.27

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 (121) hide show
  1. package/dist/core/AssistantStream.d.ts.map +1 -1
  2. package/dist/core/AssistantStreamChunk.d.ts +3 -3
  3. package/dist/core/accumulators/AssistantMessageStream.d.ts.map +1 -1
  4. package/dist/core/accumulators/assistant-message-accumulator.d.ts.map +1 -1
  5. package/dist/core/accumulators/assistant-message-accumulator.js +65 -28
  6. package/dist/core/accumulators/assistant-message-accumulator.js.map +1 -1
  7. package/dist/core/converters/toGenericMessages.js.map +1 -1
  8. package/dist/core/gorp/GorpStreamAccumulator.d.ts +15 -0
  9. package/dist/core/gorp/GorpStreamAccumulator.d.ts.map +1 -0
  10. package/dist/core/{object/ObjectStreamAccumulator.js → gorp/GorpStreamAccumulator.js} +11 -9
  11. package/dist/core/gorp/GorpStreamAccumulator.js.map +1 -0
  12. package/dist/core/gorp/GorpStreamDeltaTracker.d.ts +17 -0
  13. package/dist/core/gorp/GorpStreamDeltaTracker.d.ts.map +1 -0
  14. package/dist/core/gorp/GorpStreamDeltaTracker.js +38 -0
  15. package/dist/core/gorp/GorpStreamDeltaTracker.js.map +1 -0
  16. package/dist/core/gorp/GorpStreamResponse.d.ts +16 -0
  17. package/dist/core/gorp/GorpStreamResponse.d.ts.map +1 -0
  18. package/dist/core/gorp/GorpStreamResponse.js +51 -0
  19. package/dist/core/gorp/GorpStreamResponse.js.map +1 -0
  20. package/dist/core/gorp/changeTree.d.ts +16 -0
  21. package/dist/core/gorp/changeTree.d.ts.map +1 -0
  22. package/dist/core/gorp/changeTree.js +77 -0
  23. package/dist/core/gorp/changeTree.js.map +1 -0
  24. package/dist/core/gorp/createGorpStream.d.ts +16 -0
  25. package/dist/core/gorp/createGorpStream.d.ts.map +1 -0
  26. package/dist/core/{object/createObjectStream.js → gorp/createGorpStream.js} +13 -8
  27. package/dist/core/gorp/createGorpStream.js.map +1 -0
  28. package/dist/core/{object → gorp}/types.d.ts +6 -5
  29. package/dist/core/gorp/types.d.ts.map +1 -0
  30. package/dist/core/modules/assistant-stream.d.ts +5 -4
  31. package/dist/core/modules/assistant-stream.d.ts.map +1 -1
  32. package/dist/core/modules/assistant-stream.js +10 -6
  33. package/dist/core/modules/assistant-stream.js.map +1 -1
  34. package/dist/core/modules/tool-call.js +2 -2
  35. package/dist/core/modules/tool-call.js.map +1 -1
  36. package/dist/core/serialization/assistant-transport/AssistantTransport.d.ts.map +1 -1
  37. package/dist/core/serialization/assistant-transport/AssistantTransport.js +91 -1
  38. package/dist/core/serialization/assistant-transport/AssistantTransport.js.map +1 -1
  39. package/dist/core/serialization/data-stream/chunk-types.d.ts +2 -2
  40. package/dist/core/serialization/data-stream/chunk-types.js.map +1 -1
  41. package/dist/core/serialization/ui-message-stream/UIMessageStream.d.ts.map +1 -1
  42. package/dist/core/serialization/ui-message-stream/UIMessageStream.js +11 -1
  43. package/dist/core/serialization/ui-message-stream/UIMessageStream.js.map +1 -1
  44. package/dist/core/tool/ToolCallReader.d.ts.map +1 -1
  45. package/dist/core/tool/ToolCallReader.js.map +1 -1
  46. package/dist/core/tool/ToolExecutionStream.d.ts.map +1 -1
  47. package/dist/core/tool/ToolExecutionStream.js +9 -1
  48. package/dist/core/tool/ToolExecutionStream.js.map +1 -1
  49. package/dist/core/tool/ToolResponse.d.ts.map +1 -1
  50. package/dist/core/tool/toolResultStream.d.ts.map +1 -1
  51. package/dist/core/tool/toolResultStream.js +7 -2
  52. package/dist/core/tool/toolResultStream.js.map +1 -1
  53. package/dist/core/utils/stream/AssistantTransformStream.d.ts.map +1 -1
  54. package/dist/core/utils/stream/PipeableTransformStream.d.ts.map +1 -1
  55. package/dist/core/utils/stream/SSEEventDecoder.d.ts.map +1 -1
  56. package/dist/core/utils/stream/merge.d.ts +2 -0
  57. package/dist/core/utils/stream/merge.d.ts.map +1 -1
  58. package/dist/core/utils/stream/merge.js +27 -8
  59. package/dist/core/utils/stream/merge.js.map +1 -1
  60. package/dist/core/utils/stream/path-utils.d.ts.map +1 -1
  61. package/dist/index.d.ts +25 -4
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +14 -3
  64. package/dist/index.js.map +1 -0
  65. package/dist/resumable/ResumableStreamContext.d.ts.map +1 -1
  66. package/dist/resumable/ResumableStreamContext.js +12 -5
  67. package/dist/resumable/ResumableStreamContext.js.map +1 -1
  68. package/dist/resumable/errors.d.ts.map +1 -1
  69. package/dist/resumable/stores/redis-impl.d.ts.map +1 -1
  70. package/dist/utils/AsyncIterableStream.d.ts.map +1 -1
  71. package/dist/utils/AsyncIterableStream.js +18 -3
  72. package/dist/utils/AsyncIterableStream.js.map +1 -1
  73. package/dist/utils/promiseWithResolvers.d.ts.map +1 -1
  74. package/package.json +2 -2
  75. package/src/core/AssistantStreamChunk.ts +3 -3
  76. package/src/core/accumulators/assistant-message-accumulator.test.ts +374 -1
  77. package/src/core/accumulators/assistant-message-accumulator.ts +75 -26
  78. package/src/core/{object/ObjectStream.test.ts → gorp/GorpStream.test.ts} +86 -25
  79. package/src/core/gorp/GorpStreamAccumulator.test.ts +28 -0
  80. package/src/core/{object/ObjectStreamAccumulator.ts → gorp/GorpStreamAccumulator.ts} +13 -15
  81. package/src/core/gorp/GorpStreamDeltaTracker.test.ts +182 -0
  82. package/src/core/gorp/GorpStreamDeltaTracker.ts +55 -0
  83. package/src/core/{object/ObjectStreamResponse.test.ts → gorp/GorpStreamResponse.test.ts} +6 -6
  84. package/src/core/gorp/GorpStreamResponse.ts +88 -0
  85. package/src/core/gorp/changeTree.test.ts +168 -0
  86. package/src/core/gorp/changeTree.ts +96 -0
  87. package/src/core/{object/createObjectStream.ts → gorp/createGorpStream.ts} +23 -17
  88. package/src/core/{object → gorp}/types.ts +5 -3
  89. package/src/core/modules/assistant-stream.test.ts +154 -2
  90. package/src/core/modules/assistant-stream.ts +16 -6
  91. package/src/core/modules/tool-call.test.ts +67 -0
  92. package/src/core/modules/tool-call.ts +3 -3
  93. package/src/core/serialization/assistant-transport/AssistantTransport.test.ts +174 -1
  94. package/src/core/serialization/assistant-transport/AssistantTransport.ts +77 -1
  95. package/src/core/serialization/data-stream/chunk-types.ts +2 -2
  96. package/src/core/serialization/ui-message-stream/UIMessageStream.test.ts +111 -0
  97. package/src/core/serialization/ui-message-stream/UIMessageStream.ts +20 -1
  98. package/src/core/tool/ToolExecutionStream.ts +10 -0
  99. package/src/core/tool/toolResultStream.test.ts +50 -0
  100. package/src/core/tool/toolResultStream.ts +7 -2
  101. package/src/core/utils/stream/merge.ts +31 -9
  102. package/src/gorp.test.ts +42 -0
  103. package/src/index.ts +21 -6
  104. package/src/resumable/ResumableStreamContext.test.ts +116 -1
  105. package/src/resumable/ResumableStreamContext.ts +32 -5
  106. package/src/resumable/createResumableAssistantStreamResponse.test.ts +1 -25
  107. package/src/utils/AsyncIterableStream.test.ts +61 -0
  108. package/src/utils/AsyncIterableStream.ts +18 -3
  109. package/dist/core/object/ObjectStreamAccumulator.d.ts +0 -15
  110. package/dist/core/object/ObjectStreamAccumulator.d.ts.map +0 -1
  111. package/dist/core/object/ObjectStreamAccumulator.js.map +0 -1
  112. package/dist/core/object/ObjectStreamResponse.d.ts +0 -16
  113. package/dist/core/object/ObjectStreamResponse.d.ts.map +0 -1
  114. package/dist/core/object/ObjectStreamResponse.js +0 -57
  115. package/dist/core/object/ObjectStreamResponse.js.map +0 -1
  116. package/dist/core/object/createObjectStream.d.ts +0 -16
  117. package/dist/core/object/createObjectStream.d.ts.map +0 -1
  118. package/dist/core/object/createObjectStream.js.map +0 -1
  119. package/dist/core/object/types.d.ts.map +0 -1
  120. package/src/core/object/ObjectStreamResponse.ts +0 -114
  121. /package/dist/core/{object → gorp}/types.js +0 -0
@@ -0,0 +1,16 @@
1
+ //#region src/core/gorp/changeTree.d.ts
2
+ type ChangeNode = true | {
3
+ [key: string]: ChangeNode;
4
+ };
5
+ declare function createChangeNode(): {
6
+ [key: string]: ChangeNode;
7
+ };
8
+ declare function assertSafePathSegment(segment: string): void;
9
+ declare function markChanged(node: ChangeNode, path: readonly string[]): ChangeNode;
10
+ declare function mergeChanged(target: ChangeNode, source: ChangeNode): ChangeNode;
11
+ declare function lookupChange(node: ChangeNode, path: readonly string[]): ChangeNode | false;
12
+ declare function lookupValue(state: unknown, path: readonly string[]): unknown;
13
+ declare function diffKeys(newNode: unknown, oldNode: unknown): string[];
14
+ //#endregion
15
+ export { ChangeNode, assertSafePathSegment, createChangeNode, diffKeys, lookupChange, lookupValue, markChanged, mergeChanged };
16
+ //# sourceMappingURL=changeTree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changeTree.d.ts","names":[],"sources":["../../../src/core/gorp/changeTree.ts"],"mappings":";KAAY;GAAuB,cAAc;;iBAEjC;GAAuB,cAAc;;iBAMrC,sBAAsB;iBAMtB,YACd,MAAM,YACN,0BACC;iBAiBa,aACd,QAAQ,YACR,QAAQ,aACP;iBAwBa,aACd,MAAM,YACN,0BACC;iBAUa,YAAY,gBAAgB;iBAY5B,SAAS,kBAAkB"}
@@ -0,0 +1,77 @@
1
+ //#region src/core/gorp/changeTree.ts
2
+ function createChangeNode() {
3
+ return Object.create(null);
4
+ }
5
+ const UNSAFE_PATH_SEGMENTS = /* @__PURE__ */ new Set([
6
+ "__proto__",
7
+ "constructor",
8
+ "prototype"
9
+ ]);
10
+ function assertSafePathSegment(segment) {
11
+ if (UNSAFE_PATH_SEGMENTS.has(segment)) throw new Error(`Unsafe gorp path segment: ${segment}`);
12
+ }
13
+ function markChanged(node, path) {
14
+ if (node === true || path.length === 0) return true;
15
+ let cursor = node;
16
+ for (let i = 0; i < path.length - 1; i++) {
17
+ const key = path[i];
18
+ assertSafePathSegment(key);
19
+ const next = Object.hasOwn(cursor, key) ? cursor[key] : void 0;
20
+ if (next === true) return node;
21
+ if (next === void 0) cursor[key] = createChangeNode();
22
+ cursor = cursor[key];
23
+ }
24
+ const leaf = path[path.length - 1];
25
+ assertSafePathSegment(leaf);
26
+ cursor[leaf] = true;
27
+ return node;
28
+ }
29
+ function mergeChanged(target, source) {
30
+ if (target === true || source === true) return true;
31
+ for (const key of Object.keys(source)) {
32
+ assertSafePathSegment(key);
33
+ const sChild = source[key];
34
+ const tChild = Object.hasOwn(target, key) ? target[key] : void 0;
35
+ target[key] = tChild === void 0 ? cloneChangeNode(sChild) : mergeChanged(tChild, sChild);
36
+ }
37
+ return target;
38
+ }
39
+ function cloneChangeNode(source) {
40
+ if (source === true) return true;
41
+ const clone = createChangeNode();
42
+ for (const key of Object.keys(source)) {
43
+ assertSafePathSegment(key);
44
+ clone[key] = cloneChangeNode(source[key]);
45
+ }
46
+ return clone;
47
+ }
48
+ function lookupChange(node, path) {
49
+ for (const key of path) {
50
+ if (node === true) return true;
51
+ const next = Object.hasOwn(node, key) ? node[key] : void 0;
52
+ if (next === void 0) return false;
53
+ node = next;
54
+ }
55
+ return node;
56
+ }
57
+ function lookupValue(state, path) {
58
+ let node = state;
59
+ for (const key of path) {
60
+ assertSafePathSegment(key);
61
+ if (typeof node !== "object" || node === null) return void 0;
62
+ node = Object.hasOwn(node, key) ? node[key] : void 0;
63
+ }
64
+ return node;
65
+ }
66
+ function diffKeys(newNode, oldNode) {
67
+ const newKeys = typeof newNode === "object" && newNode !== null ? Object.keys(newNode) : [];
68
+ const oldKeys = typeof oldNode === "object" && oldNode !== null ? Object.keys(oldNode) : [];
69
+ if (oldKeys.length === 0) return newKeys;
70
+ const newSet = new Set(newKeys);
71
+ const deletedKeys = oldKeys.filter((k) => !newSet.has(k)).reverse();
72
+ return [...newKeys, ...deletedKeys];
73
+ }
74
+ //#endregion
75
+ export { assertSafePathSegment, createChangeNode, diffKeys, lookupChange, lookupValue, markChanged, mergeChanged };
76
+
77
+ //# sourceMappingURL=changeTree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changeTree.js","names":[],"sources":["../../../src/core/gorp/changeTree.ts"],"sourcesContent":["export type ChangeNode = true | { [key: string]: ChangeNode };\n\nexport function createChangeNode(): { [key: string]: ChangeNode } {\n return Object.create(null);\n}\n\nconst UNSAFE_PATH_SEGMENTS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\nexport function assertSafePathSegment(segment: string): void {\n if (UNSAFE_PATH_SEGMENTS.has(segment)) {\n throw new Error(`Unsafe gorp path segment: ${segment}`);\n }\n}\n\nexport function markChanged(\n node: ChangeNode,\n path: readonly string[],\n): ChangeNode {\n if (node === true || path.length === 0) return true;\n let cursor = node;\n for (let i = 0; i < path.length - 1; i++) {\n const key = path[i]!;\n assertSafePathSegment(key);\n const next = Object.hasOwn(cursor, key) ? cursor[key] : undefined;\n if (next === true) return node;\n if (next === undefined) cursor[key] = createChangeNode();\n cursor = cursor[key] as { [k: string]: ChangeNode };\n }\n const leaf = path[path.length - 1]!;\n assertSafePathSegment(leaf);\n cursor[leaf] = true;\n return node;\n}\n\nexport function mergeChanged(\n target: ChangeNode,\n source: ChangeNode,\n): ChangeNode {\n if (target === true || source === true) return true;\n for (const key of Object.keys(source)) {\n assertSafePathSegment(key);\n const sChild = source[key]!;\n const tChild = Object.hasOwn(target, key) ? target[key] : undefined;\n target[key] =\n tChild === undefined\n ? cloneChangeNode(sChild)\n : mergeChanged(tChild, sChild);\n }\n return target;\n}\n\nfunction cloneChangeNode(source: ChangeNode): ChangeNode {\n if (source === true) return true;\n const clone = createChangeNode();\n for (const key of Object.keys(source)) {\n assertSafePathSegment(key);\n clone[key] = cloneChangeNode(source[key]!);\n }\n return clone;\n}\n\nexport function lookupChange(\n node: ChangeNode,\n path: readonly string[],\n): ChangeNode | false {\n for (const key of path) {\n if (node === true) return true;\n const next = Object.hasOwn(node, key) ? node[key] : undefined;\n if (next === undefined) return false;\n node = next;\n }\n return node;\n}\n\nexport function lookupValue(state: unknown, path: readonly string[]): unknown {\n let node = state;\n for (const key of path) {\n assertSafePathSegment(key);\n if (typeof node !== \"object\" || node === null) return undefined;\n node = Object.hasOwn(node, key)\n ? (node as Record<string, unknown>)[key]\n : undefined;\n }\n return node;\n}\n\nexport function diffKeys(newNode: unknown, oldNode: unknown): string[] {\n const newKeys =\n typeof newNode === \"object\" && newNode !== null ? Object.keys(newNode) : [];\n const oldKeys =\n typeof oldNode === \"object\" && oldNode !== null ? Object.keys(oldNode) : [];\n if (oldKeys.length === 0) return newKeys;\n const newSet = new Set(newKeys);\n const deletedKeys = oldKeys.filter((k) => !newSet.has(k)).reverse();\n return [...newKeys, ...deletedKeys];\n}\n"],"mappings":";AAEA,SAAgB,mBAAkD;CAChE,OAAO,OAAO,OAAO,IAAI;AAC3B;AAEA,MAAM,uCAAuB,IAAI,IAAI;CAAC;CAAa;CAAe;AAAW,CAAC;AAE9E,SAAgB,sBAAsB,SAAuB;CAC3D,IAAI,qBAAqB,IAAI,OAAO,GAClC,MAAM,IAAI,MAAM,6BAA6B,SAAS;AAE1D;AAEA,SAAgB,YACd,MACA,MACY;CACZ,IAAI,SAAS,QAAQ,KAAK,WAAW,GAAG,OAAO;CAC/C,IAAI,SAAS;CACb,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,SAAS,GAAG,KAAK;EACxC,MAAM,MAAM,KAAK;EACjB,sBAAsB,GAAG;EACzB,MAAM,OAAO,OAAO,OAAO,QAAQ,GAAG,IAAI,OAAO,OAAO,KAAA;EACxD,IAAI,SAAS,MAAM,OAAO;EAC1B,IAAI,SAAS,KAAA,GAAW,OAAO,OAAO,iBAAiB;EACvD,SAAS,OAAO;CAClB;CACA,MAAM,OAAO,KAAK,KAAK,SAAS;CAChC,sBAAsB,IAAI;CAC1B,OAAO,QAAQ;CACf,OAAO;AACT;AAEA,SAAgB,aACd,QACA,QACY;CACZ,IAAI,WAAW,QAAQ,WAAW,MAAM,OAAO;CAC/C,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAAG;EACrC,sBAAsB,GAAG;EACzB,MAAM,SAAS,OAAO;EACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,GAAG,IAAI,OAAO,OAAO,KAAA;EAC1D,OAAO,OACL,WAAW,KAAA,IACP,gBAAgB,MAAM,IACtB,aAAa,QAAQ,MAAM;CACnC;CACA,OAAO;AACT;AAEA,SAAS,gBAAgB,QAAgC;CACvD,IAAI,WAAW,MAAM,OAAO;CAC5B,MAAM,QAAQ,iBAAiB;CAC/B,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAAG;EACrC,sBAAsB,GAAG;EACzB,MAAM,OAAO,gBAAgB,OAAO,IAAK;CAC3C;CACA,OAAO;AACT;AAEA,SAAgB,aACd,MACA,MACoB;CACpB,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,SAAS,MAAM,OAAO;EAC1B,MAAM,OAAO,OAAO,OAAO,MAAM,GAAG,IAAI,KAAK,OAAO,KAAA;EACpD,IAAI,SAAS,KAAA,GAAW,OAAO;EAC/B,OAAO;CACT;CACA,OAAO;AACT;AAEA,SAAgB,YAAY,OAAgB,MAAkC;CAC5E,IAAI,OAAO;CACX,KAAK,MAAM,OAAO,MAAM;EACtB,sBAAsB,GAAG;EACzB,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM,OAAO,KAAA;EACtD,OAAO,OAAO,OAAO,MAAM,GAAG,IACzB,KAAiC,OAClC,KAAA;CACN;CACA,OAAO;AACT;AAEA,SAAgB,SAAS,SAAkB,SAA4B;CACrE,MAAM,UACJ,OAAO,YAAY,YAAY,YAAY,OAAO,OAAO,KAAK,OAAO,IAAI,CAAC;CAC5E,MAAM,UACJ,OAAO,YAAY,YAAY,YAAY,OAAO,OAAO,KAAK,OAAO,IAAI,CAAC;CAC5E,IAAI,QAAQ,WAAW,GAAG,OAAO;CACjC,MAAM,SAAS,IAAI,IAAI,OAAO;CAC9B,MAAM,cAAc,QAAQ,QAAQ,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ;CAClE,OAAO,CAAC,GAAG,SAAS,GAAG,WAAW;AACpC"}
@@ -0,0 +1,16 @@
1
+ import { ReadonlyJSONValue } from "../../utils/json/json-value.js";
2
+ import "../../utils.js";
3
+ import { GorpStreamChunk, GorpStreamOperation } from "./types.js";
4
+ //#region src/core/gorp/createGorpStream.d.ts
5
+ type GorpStreamController = {
6
+ readonly abortSignal: AbortSignal;
7
+ enqueue(operations: readonly GorpStreamOperation[]): void;
8
+ };
9
+ type CreateGorpStreamOptions = {
10
+ execute: (controller: GorpStreamController) => void | PromiseLike<void>;
11
+ defaultValue?: ReadonlyJSONValue;
12
+ };
13
+ declare const createGorpStream: ({ execute, defaultValue }: CreateGorpStreamOptions) => ReadableStream<GorpStreamChunk>;
14
+ //#endregion
15
+ export { createGorpStream };
16
+ //# sourceMappingURL=createGorpStream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createGorpStream.d.ts","names":[],"sources":["../../../src/core/gorp/createGorpStream.ts"],"mappings":";;;;KAKK;WACM,aAAa;EAEtB,QAAQ,qBAAqB;;KA8D1B;EACH,UAAU,YAAY,gCAAgC;EACtD,eAAe;;cAGJ,qBAAoB,SAAA,gBAG9B,4BAAuB,eAAA"}
@@ -1,18 +1,20 @@
1
- import { ObjectStreamAccumulator } from "./ObjectStreamAccumulator.js";
1
+ import { GorpStreamAccumulator } from "./GorpStreamAccumulator.js";
2
2
  import { withPromiseOrValue } from "../utils/withPromiseOrValue.js";
3
- //#region src/core/object/createObjectStream.ts
4
- var ObjectStreamControllerImpl = class {
3
+ //#region src/core/gorp/createGorpStream.ts
4
+ var GorpStreamControllerImpl = class {
5
5
  _controller;
6
6
  _abortController = new AbortController();
7
7
  _accumulator;
8
+ _cancelled = false;
8
9
  get abortSignal() {
9
10
  return this._abortController.signal;
10
11
  }
11
12
  constructor(controller, defaultValue) {
12
13
  this._controller = controller;
13
- this._accumulator = new ObjectStreamAccumulator(defaultValue);
14
+ this._accumulator = new GorpStreamAccumulator(defaultValue);
14
15
  }
15
16
  enqueue(operations) {
17
+ if (this._cancelled) return;
16
18
  this._accumulator.append(operations);
17
19
  this._controller.enqueue({
18
20
  snapshot: this._accumulator.state,
@@ -20,12 +22,15 @@ var ObjectStreamControllerImpl = class {
20
22
  });
21
23
  }
22
24
  __internalError(error) {
25
+ if (this._cancelled) return;
23
26
  this._controller.error(error);
24
27
  }
25
28
  __internalClose() {
29
+ if (this._cancelled) return;
26
30
  this._controller.close();
27
31
  }
28
32
  __internalCancel(reason) {
33
+ this._cancelled = true;
29
34
  this._abortController.abort(reason);
30
35
  }
31
36
  };
@@ -33,14 +38,14 @@ const getStreamControllerPair = (defaultValue) => {
33
38
  let controller;
34
39
  return [new ReadableStream({
35
40
  start(c) {
36
- controller = new ObjectStreamControllerImpl(c, defaultValue);
41
+ controller = new GorpStreamControllerImpl(c, defaultValue);
37
42
  },
38
43
  cancel(reason) {
39
44
  controller.__internalCancel(reason);
40
45
  }
41
46
  }), controller];
42
47
  };
43
- const createObjectStream = ({ execute, defaultValue = {} }) => {
48
+ const createGorpStream = ({ execute, defaultValue = {} }) => {
44
49
  const [stream, controller] = getStreamControllerPair(defaultValue);
45
50
  withPromiseOrValue(() => execute(controller), () => {
46
51
  controller.__internalClose();
@@ -50,6 +55,6 @@ const createObjectStream = ({ execute, defaultValue = {} }) => {
50
55
  return stream;
51
56
  };
52
57
  //#endregion
53
- export { createObjectStream };
58
+ export { createGorpStream };
54
59
 
55
- //# sourceMappingURL=createObjectStream.js.map
60
+ //# sourceMappingURL=createGorpStream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createGorpStream.js","names":[],"sources":["../../../src/core/gorp/createGorpStream.ts"],"sourcesContent":["import type { ReadonlyJSONValue } from \"../../utils\";\nimport { withPromiseOrValue } from \"../utils/withPromiseOrValue\";\nimport { GorpStreamAccumulator } from \"./GorpStreamAccumulator\";\nimport type { GorpStreamOperation, GorpStreamChunk } from \"./types\";\n\ntype GorpStreamController = {\n readonly abortSignal: AbortSignal;\n\n enqueue(operations: readonly GorpStreamOperation[]): void;\n};\n\nclass GorpStreamControllerImpl implements GorpStreamController {\n private _controller: ReadableStreamDefaultController<GorpStreamChunk>;\n private _abortController = new AbortController();\n private _accumulator: GorpStreamAccumulator;\n private _cancelled = false;\n\n get abortSignal() {\n return this._abortController.signal;\n }\n\n constructor(\n controller: ReadableStreamDefaultController<GorpStreamChunk>,\n defaultValue: ReadonlyJSONValue,\n ) {\n this._controller = controller;\n this._accumulator = new GorpStreamAccumulator(defaultValue);\n }\n\n enqueue(operations: readonly GorpStreamOperation[]) {\n if (this._cancelled) return;\n\n this._accumulator.append(operations);\n\n this._controller.enqueue({\n snapshot: this._accumulator.state,\n operations,\n });\n }\n\n __internalError(error: unknown) {\n if (this._cancelled) return;\n this._controller.error(error);\n }\n\n __internalClose() {\n if (this._cancelled) return;\n this._controller.close();\n }\n\n __internalCancel(reason?: unknown) {\n this._cancelled = true;\n this._abortController.abort(reason);\n }\n}\n\nconst getStreamControllerPair = (defaultValue: ReadonlyJSONValue) => {\n let controller!: GorpStreamControllerImpl;\n const stream = new ReadableStream<GorpStreamChunk>({\n start(c) {\n controller = new GorpStreamControllerImpl(c, defaultValue);\n },\n cancel(reason: unknown) {\n controller.__internalCancel(reason);\n },\n });\n\n return [stream, controller] as const;\n};\n\ntype CreateGorpStreamOptions = {\n execute: (controller: GorpStreamController) => void | PromiseLike<void>;\n defaultValue?: ReadonlyJSONValue;\n};\n\nexport const createGorpStream = ({\n execute,\n defaultValue = {},\n}: CreateGorpStreamOptions) => {\n const [stream, controller] = getStreamControllerPair(defaultValue);\n\n withPromiseOrValue(\n () => execute(controller),\n () => {\n controller.__internalClose();\n },\n (e: unknown) => {\n controller.__internalError(e);\n },\n );\n\n return stream;\n};\n"],"mappings":";;;AAWA,IAAM,2BAAN,MAA+D;CAC7D;CACA,mBAA2B,IAAI,gBAAgB;CAC/C;CACA,aAAqB;CAErB,IAAI,cAAc;EAChB,OAAO,KAAK,iBAAiB;CAC/B;CAEA,YACE,YACA,cACA;EACA,KAAK,cAAc;EACnB,KAAK,eAAe,IAAI,sBAAsB,YAAY;CAC5D;CAEA,QAAQ,YAA4C;EAClD,IAAI,KAAK,YAAY;EAErB,KAAK,aAAa,OAAO,UAAU;EAEnC,KAAK,YAAY,QAAQ;GACvB,UAAU,KAAK,aAAa;GAC5B;EACF,CAAC;CACH;CAEA,gBAAgB,OAAgB;EAC9B,IAAI,KAAK,YAAY;EACrB,KAAK,YAAY,MAAM,KAAK;CAC9B;CAEA,kBAAkB;EAChB,IAAI,KAAK,YAAY;EACrB,KAAK,YAAY,MAAM;CACzB;CAEA,iBAAiB,QAAkB;EACjC,KAAK,aAAa;EAClB,KAAK,iBAAiB,MAAM,MAAM;CACpC;AACF;AAEA,MAAM,2BAA2B,iBAAoC;CACnE,IAAI;CAUJ,OAAO,CAAC,IATW,eAAgC;EACjD,MAAM,GAAG;GACP,aAAa,IAAI,yBAAyB,GAAG,YAAY;EAC3D;EACA,OAAO,QAAiB;GACtB,WAAW,iBAAiB,MAAM;EACpC;CACF,CAEa,GAAG,UAAU;AAC5B;AAOA,MAAa,oBAAoB,EAC/B,SACA,eAAe,CAAC,QACa;CAC7B,MAAM,CAAC,QAAQ,cAAc,wBAAwB,YAAY;CAEjE,yBACQ,QAAQ,UAAU,SAClB;EACJ,WAAW,gBAAgB;CAC7B,IACC,MAAe;EACd,WAAW,gBAAgB,CAAC;CAC9B,CACF;CAEA,OAAO;AACT"}
@@ -1,7 +1,7 @@
1
1
  import { ReadonlyJSONValue } from "../../utils/json/json-value.js";
2
2
  import "../../utils.js";
3
- //#region src/core/object/types.d.ts
4
- type ObjectStreamOperation = {
3
+ //#region src/core/gorp/types.d.ts
4
+ type AssistantTransportStateOperation = {
5
5
  readonly type: "set";
6
6
  readonly path: readonly string[];
7
7
  readonly value: ReadonlyJSONValue;
@@ -10,10 +10,11 @@ type ObjectStreamOperation = {
10
10
  readonly path: readonly string[];
11
11
  readonly value: string;
12
12
  };
13
- type ObjectStreamChunk = {
13
+ type GorpStreamOperation = AssistantTransportStateOperation;
14
+ type GorpStreamChunk = {
14
15
  readonly snapshot: ReadonlyJSONValue;
15
- readonly operations: readonly ObjectStreamOperation[];
16
+ readonly operations: readonly GorpStreamOperation[];
16
17
  };
17
18
  //#endregion
18
- export { ObjectStreamChunk, ObjectStreamOperation };
19
+ export { AssistantTransportStateOperation, GorpStreamChunk, GorpStreamOperation };
19
20
  //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/core/gorp/types.ts"],"mappings":";;;KAEY;WAEG;WACA;WACA,OAAO;;WAGP;WACA;WACA;;KAGH,sBAAsB;KAEtB;WACD,UAAU;WACV,qBAAqB"}
@@ -76,10 +76,11 @@ type AssistantStreamController = {
76
76
  * Creates an {@link AssistantStream} and writes to it with an
77
77
  * {@link AssistantStreamController}.
78
78
  *
79
- * The callback may write synchronously or asynchronously. If it throws, an
80
- * `error` chunk is emitted before the error is rethrown; when the callback
81
- * settles, the stream is closed automatically unless the controller was
82
- * already closed.
79
+ * The callback may write synchronously or asynchronously. If it throws while
80
+ * the stream is open, an `error` chunk is emitted. Failures after an explicit
81
+ * close are logged, while failures after consumer cancellation are discarded.
82
+ * When the callback settles, the stream is closed automatically unless the
83
+ * controller was already closed.
83
84
  */
84
85
  declare function createAssistantStream(callback: (controller: AssistantStreamController) => PromiseLike<void> | void): AssistantStream;
85
86
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"assistant-stream.d.ts","names":[],"sources":["../../../src/core/modules/assistant-stream.ts"],"mappings":";;;;;;;;KAuBK;EACH;EACA;EACA;EACA,OAAO;EACP,WAAW,iBAAiB;;;;;;;;;KAUlB;;EAEV,WAAW;;EAEX,gBAAgB;;EAEhB,aAAa,SAAS;;EAEtB,WAAW,SAAS;;EAEpB,WAAW,SAAS;;;;;;;;EAQpB,eAAe;;;;;;;EAOf,gBAAgB,kBAAkB;;;;;;;EAOlC,gBAAgB,SAAS,mBAAmB;;EAE5C,QAAQ,OAAO;;;;;;;EAOf,MAAM,QAAQ;;EAEd;;;;;;;EAOA,aAAa,mBAAmB;;;;;;;;;;;iBA2MlB,sBACd,WAAW,YAAY,8BAA8B,2BACpD;;;;;;;;iBAiCa,6CAA+B,iBAAA;;;;;;;;iBAsB/B,8BACd,WAAW,YAAY,8BAA8B,2BAAwB"}
1
+ {"version":3,"file":"assistant-stream.d.ts","names":[],"sources":["../../../src/core/modules/assistant-stream.ts"],"mappings":";;;;;;;;KAuBK;EACH;EACA;EACA;EACA,OAAO;EACP,WAAW,iBAAiB;;;;;;;;;KAUlB;;EAEV,WAAW;;EAEX,gBAAgB;;EAEhB,aAAa,SAAS;;EAEtB,WAAW,SAAS;;EAEpB,WAAW,SAAS;;;;;;;;EAQpB,eAAe;;;;;;;EAOf,gBAAgB,kBAAkB;;;;;;;EAOlC,gBAAgB,SAAS,mBAAmB;;EAE5C,QAAQ,OAAO;;;;;;;EAOf,MAAM,QAAQ;;EAEd;;;;;;;EAOA,aAAa,mBAAmB;;;;;;;;;;;;iBAoNlB,sBACd,WAAW,YAAY,8BAA8B,2BACpD;;;;;;;;iBAkCa,6CAA+B,iBAAA;;;;;;;;iBAsB/B,8BACd,WAAW,YAAY,8BAA8B,2BAAwB"}
@@ -18,7 +18,10 @@ var AssistantStreamControllerImpl = class AssistantStreamControllerImpl {
18
18
  };
19
19
  }
20
20
  get __internal_isClosed() {
21
- return this._state.merger.isSealed();
21
+ return this._state.merger.isSealed() || this._state.merger.isCancelled() || this._state.merger.isErrored();
22
+ }
23
+ get __internal_isCancelled() {
24
+ return this._state.merger.isCancelled();
22
25
  }
23
26
  __internal_getReadable() {
24
27
  return this._state.merger.readable;
@@ -133,10 +136,11 @@ var AssistantStreamControllerImpl = class AssistantStreamControllerImpl {
133
136
  * Creates an {@link AssistantStream} and writes to it with an
134
137
  * {@link AssistantStreamController}.
135
138
  *
136
- * The callback may write synchronously or asynchronously. If it throws, an
137
- * `error` chunk is emitted before the error is rethrown; when the callback
138
- * settles, the stream is closed automatically unless the controller was
139
- * already closed.
139
+ * The callback may write synchronously or asynchronously. If it throws while
140
+ * the stream is open, an `error` chunk is emitted. Failures after an explicit
141
+ * close are logged, while failures after consumer cancellation are discarded.
142
+ * When the callback settles, the stream is closed automatically unless the
143
+ * controller was already closed.
140
144
  */
141
145
  function createAssistantStream(callback) {
142
146
  const controller = new AssistantStreamControllerImpl();
@@ -149,7 +153,7 @@ function createAssistantStream(callback) {
149
153
  path: [],
150
154
  error: String(e)
151
155
  });
152
- throw e;
156
+ else if (!controller.__internal_isCancelled) console.error(e);
153
157
  } finally {
154
158
  if (!controller.__internal_isClosed) controller.close();
155
159
  }
@@ -1 +1 @@
1
- {"version":3,"file":"assistant-stream.js","names":[],"sources":["../../../src/core/modules/assistant-stream.ts"],"sourcesContent":["import { AssistantStream } from \"../AssistantStream\";\nimport type { AssistantStreamChunk, PartInit } from \"../AssistantStreamChunk\";\nimport { createMergeStream } from \"../utils/stream/merge\";\nimport { createTextStreamController, type TextStreamController } from \"./text\";\nimport {\n createToolCallStreamController,\n type ToolCallStreamController,\n} from \"./tool-call\";\nimport { Counter } from \"../utils/Counter\";\nimport {\n PathAppendEncoder,\n PathMergeEncoder,\n} from \"../utils/stream/path-utils\";\nimport { DataStreamEncoder } from \"../serialization/data-stream/DataStream\";\nimport type { DataPart, FilePart, SourcePart } from \"../utils/types\";\nimport { generateId } from \"../utils/generateId\";\nimport type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"../../utils/json/json-value\";\nimport type { ToolResponseLike } from \"../tool/ToolResponse\";\nimport { promiseWithResolvers } from \"../../utils/promiseWithResolvers\";\n\ntype ToolCallPartInit = {\n toolCallId?: string;\n toolName: string;\n argsText?: string;\n args?: ReadonlyJSONObject;\n response?: ToolResponseLike<ReadonlyJSONValue>;\n};\n\n/**\n * Imperative writer for constructing an {@link AssistantStream}.\n *\n * The controller handles part boundaries for common streaming operations. Use\n * `appendText` and `appendReasoning` for simple token streams, or open explicit\n * parts with `addTextPart` and `addToolCallPart` when you need direct control.\n */\nexport type AssistantStreamController = {\n /** Appends text to the current text part, opening one if needed. */\n appendText(textDelta: string): void;\n /** Appends reasoning text to the current reasoning part, opening one if needed. */\n appendReasoning(reasoningDelta: string): void;\n /** Appends a source citation part to the stream. */\n appendSource(options: SourcePart): void;\n /** Appends a file part to the stream. */\n appendFile(options: FilePart): void;\n /** Appends a named data part to the stream. */\n appendData(options: DataPart): void;\n /**\n * Opens a text part and returns its writer.\n *\n * Close the returned controller when the text part is complete. Opening a new\n * part through this controller closes any implicit text or reasoning append\n * part first.\n */\n addTextPart(): TextStreamController;\n /**\n * Opens a tool-call part by tool name and returns its writer.\n *\n * A tool call id is generated automatically. Use the object overload when the\n * caller already has an id, initial args, args text, or response.\n */\n addToolCallPart(options: string): ToolCallStreamController;\n /**\n * Opens a tool-call part and returns its writer.\n *\n * Use this overload to provide a stable `toolCallId`, initial arguments,\n * streamed argument text, or an immediate {@link ToolResponseLike}.\n */\n addToolCallPart(options: ToolCallPartInit): ToolCallStreamController;\n /** Enqueues a raw protocol chunk. Prefer higher-level helpers when possible. */\n enqueue(chunk: AssistantStreamChunk): void;\n /**\n * Merges another assistant stream into this stream.\n *\n * Paths from the merged stream are remapped so its parts appear at the next\n * available position in this controller's output.\n */\n merge(stream: AssistantStream): void;\n /** Closes any active part and finishes the stream. */\n close(): void;\n /**\n * Returns a controller that writes child parts with `parentId` attached.\n *\n * Use this for nested or related parts that should be associated with an\n * existing message or part in downstream renderers.\n */\n withParentId(parentId: string): AssistantStreamController;\n};\n\n// Shared state between controller instances\ntype AssistantStreamControllerState = {\n merger: ReturnType<typeof createMergeStream>;\n append?:\n | {\n controller: TextStreamController;\n kind: \"text\" | \"reasoning\";\n parentId: string | undefined;\n }\n | undefined;\n contentCounter: Counter;\n closeSubscriber?: () => void;\n};\n\nclass AssistantStreamControllerImpl implements AssistantStreamController {\n private readonly _state: AssistantStreamControllerState;\n private _parentId?: string;\n\n constructor(state?: AssistantStreamControllerState) {\n this._state = state || {\n merger: createMergeStream(),\n contentCounter: new Counter(),\n };\n }\n\n get __internal_isClosed() {\n return this._state.merger.isSealed();\n }\n\n __internal_getReadable() {\n return this._state.merger.readable;\n }\n\n __internal_subscribeToClose(callback: () => void) {\n this._state.closeSubscriber = callback;\n }\n\n private _addPart(part: PartInit, stream: AssistantStream) {\n if (this._state.append) {\n this._state.append.controller.close();\n this._state.append = undefined;\n }\n\n this.enqueue({\n type: \"part-start\",\n part,\n path: [],\n });\n this._state.merger.addStream(\n stream.pipeThrough(\n new PathAppendEncoder(this._state.contentCounter.value),\n ),\n );\n }\n\n merge(stream: AssistantStream) {\n this._state.merger.addStream(\n stream.pipeThrough(new PathMergeEncoder(this._state.contentCounter)),\n );\n }\n\n appendText(textDelta: string) {\n if (\n this._state.append?.kind !== \"text\" ||\n this._state.append.parentId !== this._parentId\n ) {\n this._state.append = {\n kind: \"text\",\n parentId: this._parentId,\n controller: this.addTextPart(),\n };\n }\n this._state.append.controller.append(textDelta);\n }\n\n appendReasoning(textDelta: string) {\n if (\n this._state.append?.kind !== \"reasoning\" ||\n this._state.append.parentId !== this._parentId\n ) {\n this._state.append = {\n kind: \"reasoning\",\n parentId: this._parentId,\n controller: this.addReasoningPart(),\n };\n }\n this._state.append.controller.append(textDelta);\n }\n\n addTextPart() {\n const [stream, controller] = createTextStreamController();\n this._addPart(this._withParentIdOption({ type: \"text\" }), stream);\n return controller;\n }\n\n addReasoningPart() {\n const [stream, controller] = createTextStreamController();\n this._addPart(this._withParentIdOption({ type: \"reasoning\" }), stream);\n return controller;\n }\n\n addToolCallPart(\n options: string | ToolCallPartInit,\n ): ToolCallStreamController {\n const opt = typeof options === \"string\" ? { toolName: options } : options;\n const toolName = opt.toolName;\n const toolCallId = opt.toolCallId ?? generateId();\n\n const [stream, controller] = createToolCallStreamController();\n this._addPart(\n {\n type: \"tool-call\",\n toolName,\n toolCallId,\n ...(this._parentId && { parentId: this._parentId }),\n },\n stream,\n );\n\n if (opt.argsText !== undefined) {\n controller.argsText.append(opt.argsText);\n controller.argsText.close();\n }\n if (opt.args !== undefined) {\n controller.argsText.append(JSON.stringify(opt.args));\n controller.argsText.close();\n }\n if (opt.response !== undefined) {\n controller.setResponse(opt.response);\n }\n\n return controller;\n }\n\n private _finishedPartStream(): AssistantStream {\n return new ReadableStream({\n start(controller) {\n controller.enqueue({ type: \"part-finish\", path: [] });\n controller.close();\n },\n });\n }\n\n private _withParentIdOption<T>(options: T): T {\n if (!this._parentId) return options;\n return { ...options, parentId: this._parentId };\n }\n\n appendSource(options: SourcePart) {\n this._addPart(\n this._withParentIdOption(options),\n this._finishedPartStream(),\n );\n }\n\n appendFile(options: FilePart) {\n this._addPart(\n this._withParentIdOption(options),\n this._finishedPartStream(),\n );\n }\n\n appendData(options: DataPart) {\n this._addPart(\n this._withParentIdOption(options),\n this._finishedPartStream(),\n );\n }\n\n enqueue(chunk: AssistantStreamChunk) {\n this._state.merger.enqueue(chunk);\n\n if (chunk.type === \"part-start\" && chunk.path.length === 0) {\n this._state.contentCounter.up();\n }\n }\n\n withParentId(parentId: string): AssistantStreamController {\n const controller = new AssistantStreamControllerImpl(this._state);\n controller._parentId = parentId;\n return controller;\n }\n\n close() {\n this._state.append?.controller?.close();\n this._state.merger.seal();\n\n this._state.closeSubscriber?.();\n }\n}\n\n/**\n * Creates an {@link AssistantStream} and writes to it with an\n * {@link AssistantStreamController}.\n *\n * The callback may write synchronously or asynchronously. If it throws, an\n * `error` chunk is emitted before the error is rethrown; when the callback\n * settles, the stream is closed automatically unless the controller was\n * already closed.\n */\nexport function createAssistantStream(\n callback: (controller: AssistantStreamController) => PromiseLike<void> | void,\n): AssistantStream {\n const controller = new AssistantStreamControllerImpl();\n\n const runTask = async () => {\n try {\n await callback(controller);\n } catch (e) {\n if (!controller.__internal_isClosed) {\n controller.enqueue({\n type: \"error\",\n path: [],\n error: String(e),\n });\n }\n throw e;\n } finally {\n if (!controller.__internal_isClosed) {\n controller.close();\n }\n }\n };\n runTask();\n\n return controller.__internal_getReadable();\n}\n\n/**\n * Creates an {@link AssistantStream} together with the controller used to\n * write into it.\n *\n * Use this when the stream needs to be returned before all writers are known.\n * Closing the returned controller finishes the paired stream.\n */\nexport function createAssistantStreamController() {\n const { resolve, promise } = promiseWithResolvers<void>();\n let controller!: AssistantStreamController;\n const stream = createAssistantStream((c) => {\n controller = c;\n\n (controller as AssistantStreamControllerImpl).__internal_subscribeToClose(\n resolve,\n );\n\n return promise;\n });\n return [stream, controller] as const;\n}\n\n/**\n * Creates a `Response` whose body is an encoded {@link AssistantStream}.\n *\n * This is the HTTP-route convenience form of {@link createAssistantStream}; it\n * uses {@link DataStreamEncoder} so the response can be consumed by matching\n * assistant-ui data stream decoders.\n */\nexport function createAssistantStreamResponse(\n callback: (controller: AssistantStreamController) => PromiseLike<void> | void,\n) {\n return AssistantStream.toResponse(\n createAssistantStream(callback),\n new DataStreamEncoder(),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"assistant-stream.js","names":[],"sources":["../../../src/core/modules/assistant-stream.ts"],"sourcesContent":["import { AssistantStream } from \"../AssistantStream\";\nimport type { AssistantStreamChunk, PartInit } from \"../AssistantStreamChunk\";\nimport { createMergeStream } from \"../utils/stream/merge\";\nimport { createTextStreamController, type TextStreamController } from \"./text\";\nimport {\n createToolCallStreamController,\n type ToolCallStreamController,\n} from \"./tool-call\";\nimport { Counter } from \"../utils/Counter\";\nimport {\n PathAppendEncoder,\n PathMergeEncoder,\n} from \"../utils/stream/path-utils\";\nimport { DataStreamEncoder } from \"../serialization/data-stream/DataStream\";\nimport type { DataPart, FilePart, SourcePart } from \"../utils/types\";\nimport { generateId } from \"../utils/generateId\";\nimport type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"../../utils/json/json-value\";\nimport type { ToolResponseLike } from \"../tool/ToolResponse\";\nimport { promiseWithResolvers } from \"../../utils/promiseWithResolvers\";\n\ntype ToolCallPartInit = {\n toolCallId?: string;\n toolName: string;\n argsText?: string;\n args?: ReadonlyJSONObject;\n response?: ToolResponseLike<ReadonlyJSONValue>;\n};\n\n/**\n * Imperative writer for constructing an {@link AssistantStream}.\n *\n * The controller handles part boundaries for common streaming operations. Use\n * `appendText` and `appendReasoning` for simple token streams, or open explicit\n * parts with `addTextPart` and `addToolCallPart` when you need direct control.\n */\nexport type AssistantStreamController = {\n /** Appends text to the current text part, opening one if needed. */\n appendText(textDelta: string): void;\n /** Appends reasoning text to the current reasoning part, opening one if needed. */\n appendReasoning(reasoningDelta: string): void;\n /** Appends a source citation part to the stream. */\n appendSource(options: SourcePart): void;\n /** Appends a file part to the stream. */\n appendFile(options: FilePart): void;\n /** Appends a named data part to the stream. */\n appendData(options: DataPart): void;\n /**\n * Opens a text part and returns its writer.\n *\n * Close the returned controller when the text part is complete. Opening a new\n * part through this controller closes any implicit text or reasoning append\n * part first.\n */\n addTextPart(): TextStreamController;\n /**\n * Opens a tool-call part by tool name and returns its writer.\n *\n * A tool call id is generated automatically. Use the object overload when the\n * caller already has an id, initial args, args text, or response.\n */\n addToolCallPart(options: string): ToolCallStreamController;\n /**\n * Opens a tool-call part and returns its writer.\n *\n * Use this overload to provide a stable `toolCallId`, initial arguments,\n * streamed argument text, or an immediate {@link ToolResponseLike}.\n */\n addToolCallPart(options: ToolCallPartInit): ToolCallStreamController;\n /** Enqueues a raw protocol chunk. Prefer higher-level helpers when possible. */\n enqueue(chunk: AssistantStreamChunk): void;\n /**\n * Merges another assistant stream into this stream.\n *\n * Paths from the merged stream are remapped so its parts appear at the next\n * available position in this controller's output.\n */\n merge(stream: AssistantStream): void;\n /** Closes any active part and finishes the stream. */\n close(): void;\n /**\n * Returns a controller that writes child parts with `parentId` attached.\n *\n * Use this for nested or related parts that should be associated with an\n * existing message or part in downstream renderers.\n */\n withParentId(parentId: string): AssistantStreamController;\n};\n\n// Shared state between controller instances\ntype AssistantStreamControllerState = {\n merger: ReturnType<typeof createMergeStream>;\n append?:\n | {\n controller: TextStreamController;\n kind: \"text\" | \"reasoning\";\n parentId: string | undefined;\n }\n | undefined;\n contentCounter: Counter;\n closeSubscriber?: () => void;\n};\n\nclass AssistantStreamControllerImpl implements AssistantStreamController {\n private readonly _state: AssistantStreamControllerState;\n private _parentId?: string;\n\n constructor(state?: AssistantStreamControllerState) {\n this._state = state || {\n merger: createMergeStream(),\n contentCounter: new Counter(),\n };\n }\n\n get __internal_isClosed() {\n return (\n this._state.merger.isSealed() ||\n this._state.merger.isCancelled() ||\n this._state.merger.isErrored()\n );\n }\n\n get __internal_isCancelled() {\n return this._state.merger.isCancelled();\n }\n\n __internal_getReadable() {\n return this._state.merger.readable;\n }\n\n __internal_subscribeToClose(callback: () => void) {\n this._state.closeSubscriber = callback;\n }\n\n private _addPart(part: PartInit, stream: AssistantStream) {\n if (this._state.append) {\n this._state.append.controller.close();\n this._state.append = undefined;\n }\n\n this.enqueue({\n type: \"part-start\",\n part,\n path: [],\n });\n this._state.merger.addStream(\n stream.pipeThrough(\n new PathAppendEncoder(this._state.contentCounter.value),\n ),\n );\n }\n\n merge(stream: AssistantStream) {\n this._state.merger.addStream(\n stream.pipeThrough(new PathMergeEncoder(this._state.contentCounter)),\n );\n }\n\n appendText(textDelta: string) {\n if (\n this._state.append?.kind !== \"text\" ||\n this._state.append.parentId !== this._parentId\n ) {\n this._state.append = {\n kind: \"text\",\n parentId: this._parentId,\n controller: this.addTextPart(),\n };\n }\n this._state.append.controller.append(textDelta);\n }\n\n appendReasoning(textDelta: string) {\n if (\n this._state.append?.kind !== \"reasoning\" ||\n this._state.append.parentId !== this._parentId\n ) {\n this._state.append = {\n kind: \"reasoning\",\n parentId: this._parentId,\n controller: this.addReasoningPart(),\n };\n }\n this._state.append.controller.append(textDelta);\n }\n\n addTextPart() {\n const [stream, controller] = createTextStreamController();\n this._addPart(this._withParentIdOption({ type: \"text\" }), stream);\n return controller;\n }\n\n addReasoningPart() {\n const [stream, controller] = createTextStreamController();\n this._addPart(this._withParentIdOption({ type: \"reasoning\" }), stream);\n return controller;\n }\n\n addToolCallPart(\n options: string | ToolCallPartInit,\n ): ToolCallStreamController {\n const opt = typeof options === \"string\" ? { toolName: options } : options;\n const toolName = opt.toolName;\n const toolCallId = opt.toolCallId ?? generateId();\n\n const [stream, controller] = createToolCallStreamController();\n this._addPart(\n {\n type: \"tool-call\",\n toolName,\n toolCallId,\n ...(this._parentId && { parentId: this._parentId }),\n },\n stream,\n );\n\n if (opt.argsText !== undefined) {\n controller.argsText.append(opt.argsText);\n controller.argsText.close();\n }\n if (opt.args !== undefined) {\n controller.argsText.append(JSON.stringify(opt.args));\n controller.argsText.close();\n }\n if (opt.response !== undefined) {\n controller.setResponse(opt.response);\n }\n\n return controller;\n }\n\n private _finishedPartStream(): AssistantStream {\n return new ReadableStream({\n start(controller) {\n controller.enqueue({ type: \"part-finish\", path: [] });\n controller.close();\n },\n });\n }\n\n private _withParentIdOption<T>(options: T): T {\n if (!this._parentId) return options;\n return { ...options, parentId: this._parentId };\n }\n\n appendSource(options: SourcePart) {\n this._addPart(\n this._withParentIdOption(options),\n this._finishedPartStream(),\n );\n }\n\n appendFile(options: FilePart) {\n this._addPart(\n this._withParentIdOption(options),\n this._finishedPartStream(),\n );\n }\n\n appendData(options: DataPart) {\n this._addPart(\n this._withParentIdOption(options),\n this._finishedPartStream(),\n );\n }\n\n enqueue(chunk: AssistantStreamChunk) {\n this._state.merger.enqueue(chunk);\n\n if (chunk.type === \"part-start\" && chunk.path.length === 0) {\n this._state.contentCounter.up();\n }\n }\n\n withParentId(parentId: string): AssistantStreamController {\n const controller = new AssistantStreamControllerImpl(this._state);\n controller._parentId = parentId;\n return controller;\n }\n\n close() {\n this._state.append?.controller?.close();\n this._state.merger.seal();\n\n this._state.closeSubscriber?.();\n }\n}\n\n/**\n * Creates an {@link AssistantStream} and writes to it with an\n * {@link AssistantStreamController}.\n *\n * The callback may write synchronously or asynchronously. If it throws while\n * the stream is open, an `error` chunk is emitted. Failures after an explicit\n * close are logged, while failures after consumer cancellation are discarded.\n * When the callback settles, the stream is closed automatically unless the\n * controller was already closed.\n */\nexport function createAssistantStream(\n callback: (controller: AssistantStreamController) => PromiseLike<void> | void,\n): AssistantStream {\n const controller = new AssistantStreamControllerImpl();\n\n const runTask = async () => {\n try {\n await callback(controller);\n } catch (e) {\n if (!controller.__internal_isClosed) {\n controller.enqueue({\n type: \"error\",\n path: [],\n error: String(e),\n });\n } else if (!controller.__internal_isCancelled) {\n console.error(e);\n }\n } finally {\n if (!controller.__internal_isClosed) {\n controller.close();\n }\n }\n };\n runTask();\n\n return controller.__internal_getReadable();\n}\n\n/**\n * Creates an {@link AssistantStream} together with the controller used to\n * write into it.\n *\n * Use this when the stream needs to be returned before all writers are known.\n * Closing the returned controller finishes the paired stream.\n */\nexport function createAssistantStreamController() {\n const { resolve, promise } = promiseWithResolvers<void>();\n let controller!: AssistantStreamController;\n const stream = createAssistantStream((c) => {\n controller = c;\n\n (controller as AssistantStreamControllerImpl).__internal_subscribeToClose(\n resolve,\n );\n\n return promise;\n });\n return [stream, controller] as const;\n}\n\n/**\n * Creates a `Response` whose body is an encoded {@link AssistantStream}.\n *\n * This is the HTTP-route convenience form of {@link createAssistantStream}; it\n * uses {@link DataStreamEncoder} so the response can be consumed by matching\n * assistant-ui data stream decoders.\n */\nexport function createAssistantStreamResponse(\n callback: (controller: AssistantStreamController) => PromiseLike<void> | void,\n) {\n return AssistantStream.toResponse(\n createAssistantStream(callback),\n new DataStreamEncoder(),\n );\n}\n"],"mappings":"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"}
@@ -36,8 +36,6 @@ var ToolCallStreamControllerImpl = class {
36
36
  }
37
37
  _argsTextController;
38
38
  async setResponse(response) {
39
- this._argsTextController.close();
40
- await Promise.resolve();
41
39
  this._controller.enqueue({
42
40
  type: "result",
43
41
  path: [],
@@ -47,6 +45,8 @@ var ToolCallStreamControllerImpl = class {
47
45
  ...response.modelContent !== void 0 ? { modelContent: response.modelContent } : {},
48
46
  ...response.messages !== void 0 ? { messages: response.messages } : {}
49
47
  });
48
+ this._argsTextController.close();
49
+ await Promise.resolve();
50
50
  }
51
51
  async close() {
52
52
  if (this._isClosed) return;
@@ -1 +1 @@
1
- {"version":3,"file":"tool-call.js","names":[],"sources":["../../../src/core/modules/tool-call.ts"],"sourcesContent":["import type { AssistantStream } from \"../AssistantStream\";\nimport type { AssistantStreamChunk } from \"../AssistantStreamChunk\";\nimport type { ToolResponseLike } from \"../tool/ToolResponse\";\nimport type { ReadonlyJSONValue } from \"../../utils/json/json-value\";\nimport type { UnderlyingReadable } from \"../utils/stream/UnderlyingReadable\";\nimport { createTextStream, type TextStreamController } from \"./text\";\n\nexport type ToolCallStreamController = {\n argsText: TextStreamController;\n\n setResponse(response: ToolResponseLike<ReadonlyJSONValue>): void;\n close(): void;\n};\n\nclass ToolCallStreamControllerImpl implements ToolCallStreamController {\n private _isClosed = false;\n\n private _mergeTask: Promise<void>;\n constructor(\n private _controller: ReadableStreamDefaultController<AssistantStreamChunk>,\n ) {\n const stream = createTextStream({\n start: (c) => {\n this._argsTextController = c;\n },\n });\n\n let hasArgsText = false;\n this._mergeTask = stream.pipeTo(\n new WritableStream({\n write: (chunk) => {\n switch (chunk.type) {\n case \"text-delta\":\n hasArgsText = true;\n this._controller.enqueue(chunk);\n break;\n\n case \"part-finish\":\n if (!hasArgsText) {\n // if no argsText was provided, assume empty object\n this._controller.enqueue({\n type: \"text-delta\",\n textDelta: \"{}\",\n path: [],\n });\n }\n this._controller.enqueue({\n type: \"tool-call-args-text-finish\",\n path: [],\n });\n break;\n\n default:\n throw new Error(`Unexpected chunk type: ${chunk.type}`);\n }\n },\n }),\n );\n }\n\n get argsText() {\n return this._argsTextController;\n }\n\n private _argsTextController!: TextStreamController;\n\n async setResponse(response: ToolResponseLike<ReadonlyJSONValue>) {\n this._argsTextController.close();\n await Promise.resolve(); // flush microtask queue\n // TODO switch argsTextController to be something that doesn'#t require this\n this._controller.enqueue({\n type: \"result\",\n path: [],\n ...(response.artifact !== undefined\n ? { artifact: response.artifact }\n : {}),\n result: response.result,\n isError: response.isError ?? false,\n ...(response.modelContent !== undefined\n ? { modelContent: response.modelContent }\n : {}),\n ...(response.messages !== undefined\n ? { messages: response.messages }\n : {}),\n });\n }\n\n async close() {\n if (this._isClosed) return;\n\n this._isClosed = true;\n this._argsTextController.close();\n await this._mergeTask;\n\n this._controller.enqueue({\n type: \"part-finish\",\n path: [],\n });\n this._controller.close();\n }\n}\n\nexport const createToolCallStream = (\n readable: UnderlyingReadable<ToolCallStreamController>,\n): AssistantStream => {\n return new ReadableStream({\n start(c) {\n return readable.start?.(new ToolCallStreamControllerImpl(c));\n },\n pull(c) {\n return readable.pull?.(new ToolCallStreamControllerImpl(c));\n },\n cancel(c) {\n return readable.cancel?.(c);\n },\n });\n};\n\nexport const createToolCallStreamController = () => {\n let controller!: ToolCallStreamController;\n const stream = createToolCallStream({\n start(c) {\n controller = c;\n },\n });\n return [stream, controller] as const;\n};\n"],"mappings":";;AAcA,IAAM,+BAAN,MAAuE;CAK3D;CAJV,YAAoB;CAEpB;CACA,YACE,aACA;EADQ,KAAA,cAAA;EAER,MAAM,SAAS,iBAAiB,EAC9B,QAAQ,MAAM;GACZ,KAAK,sBAAsB;EAC7B,EACF,CAAC;EAED,IAAI,cAAc;EAClB,KAAK,aAAa,OAAO,OACvB,IAAI,eAAe,EACjB,QAAQ,UAAU;GAChB,QAAQ,MAAM,MAAd;IACE,KAAK;KACH,cAAc;KACd,KAAK,YAAY,QAAQ,KAAK;KAC9B;IAEF,KAAK;KACH,IAAI,CAAC,aAEH,KAAK,YAAY,QAAQ;MACvB,MAAM;MACN,WAAW;MACX,MAAM,CAAC;KACT,CAAC;KAEH,KAAK,YAAY,QAAQ;MACvB,MAAM;MACN,MAAM,CAAC;KACT,CAAC;KACD;IAEF,SACE,MAAM,IAAI,MAAM,0BAA0B,MAAM,MAAM;GAC1D;EACF,EACF,CAAC,CACH;CACF;CAEA,IAAI,WAAW;EACb,OAAO,KAAK;CACd;CAEA;CAEA,MAAM,YAAY,UAA+C;EAC/D,KAAK,oBAAoB,MAAM;EAC/B,MAAM,QAAQ,QAAQ;EAEtB,KAAK,YAAY,QAAQ;GACvB,MAAM;GACN,MAAM,CAAC;GACP,GAAI,SAAS,aAAa,KAAA,IACtB,EAAE,UAAU,SAAS,SAAS,IAC9B,CAAC;GACL,QAAQ,SAAS;GACjB,SAAS,SAAS,WAAW;GAC7B,GAAI,SAAS,iBAAiB,KAAA,IAC1B,EAAE,cAAc,SAAS,aAAa,IACtC,CAAC;GACL,GAAI,SAAS,aAAa,KAAA,IACtB,EAAE,UAAU,SAAS,SAAS,IAC9B,CAAC;EACP,CAAC;CACH;CAEA,MAAM,QAAQ;EACZ,IAAI,KAAK,WAAW;EAEpB,KAAK,YAAY;EACjB,KAAK,oBAAoB,MAAM;EAC/B,MAAM,KAAK;EAEX,KAAK,YAAY,QAAQ;GACvB,MAAM;GACN,MAAM,CAAC;EACT,CAAC;EACD,KAAK,YAAY,MAAM;CACzB;AACF;AAEA,MAAa,wBACX,aACoB;CACpB,OAAO,IAAI,eAAe;EACxB,MAAM,GAAG;GACP,OAAO,SAAS,QAAQ,IAAI,6BAA6B,CAAC,CAAC;EAC7D;EACA,KAAK,GAAG;GACN,OAAO,SAAS,OAAO,IAAI,6BAA6B,CAAC,CAAC;EAC5D;EACA,OAAO,GAAG;GACR,OAAO,SAAS,SAAS,CAAC;EAC5B;CACF,CAAC;AACH;AAEA,MAAa,uCAAuC;CAClD,IAAI;CAMJ,OAAO,CALQ,qBAAqB,EAClC,MAAM,GAAG;EACP,aAAa;CACf,EACF,CACa,GAAG,UAAU;AAC5B"}
1
+ {"version":3,"file":"tool-call.js","names":[],"sources":["../../../src/core/modules/tool-call.ts"],"sourcesContent":["import type { AssistantStream } from \"../AssistantStream\";\nimport type { AssistantStreamChunk } from \"../AssistantStreamChunk\";\nimport type { ToolResponseLike } from \"../tool/ToolResponse\";\nimport type { ReadonlyJSONValue } from \"../../utils/json/json-value\";\nimport type { UnderlyingReadable } from \"../utils/stream/UnderlyingReadable\";\nimport { createTextStream, type TextStreamController } from \"./text\";\n\nexport type ToolCallStreamController = {\n argsText: TextStreamController;\n\n setResponse(response: ToolResponseLike<ReadonlyJSONValue>): void;\n close(): void;\n};\n\nclass ToolCallStreamControllerImpl implements ToolCallStreamController {\n private _isClosed = false;\n\n private _mergeTask: Promise<void>;\n constructor(\n private _controller: ReadableStreamDefaultController<AssistantStreamChunk>,\n ) {\n const stream = createTextStream({\n start: (c) => {\n this._argsTextController = c;\n },\n });\n\n let hasArgsText = false;\n this._mergeTask = stream.pipeTo(\n new WritableStream({\n write: (chunk) => {\n switch (chunk.type) {\n case \"text-delta\":\n hasArgsText = true;\n this._controller.enqueue(chunk);\n break;\n\n case \"part-finish\":\n if (!hasArgsText) {\n // if no argsText was provided, assume empty object\n this._controller.enqueue({\n type: \"text-delta\",\n textDelta: \"{}\",\n path: [],\n });\n }\n this._controller.enqueue({\n type: \"tool-call-args-text-finish\",\n path: [],\n });\n break;\n\n default:\n throw new Error(`Unexpected chunk type: ${chunk.type}`);\n }\n },\n }),\n );\n }\n\n get argsText() {\n return this._argsTextController;\n }\n\n private _argsTextController!: TextStreamController;\n\n async setResponse(response: ToolResponseLike<ReadonlyJSONValue>) {\n this._controller.enqueue({\n type: \"result\",\n path: [],\n ...(response.artifact !== undefined\n ? { artifact: response.artifact }\n : {}),\n result: response.result,\n isError: response.isError ?? false,\n ...(response.modelContent !== undefined\n ? { modelContent: response.modelContent }\n : {}),\n ...(response.messages !== undefined\n ? { messages: response.messages }\n : {}),\n });\n this._argsTextController.close();\n await Promise.resolve(); // flush microtask queue\n // TODO switch argsTextController to be something that doesn'#t require this\n }\n\n async close() {\n if (this._isClosed) return;\n\n this._isClosed = true;\n this._argsTextController.close();\n await this._mergeTask;\n\n this._controller.enqueue({\n type: \"part-finish\",\n path: [],\n });\n this._controller.close();\n }\n}\n\nexport const createToolCallStream = (\n readable: UnderlyingReadable<ToolCallStreamController>,\n): AssistantStream => {\n return new ReadableStream({\n start(c) {\n return readable.start?.(new ToolCallStreamControllerImpl(c));\n },\n pull(c) {\n return readable.pull?.(new ToolCallStreamControllerImpl(c));\n },\n cancel(c) {\n return readable.cancel?.(c);\n },\n });\n};\n\nexport const createToolCallStreamController = () => {\n let controller!: ToolCallStreamController;\n const stream = createToolCallStream({\n start(c) {\n controller = c;\n },\n });\n return [stream, controller] as const;\n};\n"],"mappings":";;AAcA,IAAM,+BAAN,MAAuE;CAK3D;CAJV,YAAoB;CAEpB;CACA,YACE,aACA;EADQ,KAAA,cAAA;EAER,MAAM,SAAS,iBAAiB,EAC9B,QAAQ,MAAM;GACZ,KAAK,sBAAsB;EAC7B,EACF,CAAC;EAED,IAAI,cAAc;EAClB,KAAK,aAAa,OAAO,OACvB,IAAI,eAAe,EACjB,QAAQ,UAAU;GAChB,QAAQ,MAAM,MAAd;IACE,KAAK;KACH,cAAc;KACd,KAAK,YAAY,QAAQ,KAAK;KAC9B;IAEF,KAAK;KACH,IAAI,CAAC,aAEH,KAAK,YAAY,QAAQ;MACvB,MAAM;MACN,WAAW;MACX,MAAM,CAAC;KACT,CAAC;KAEH,KAAK,YAAY,QAAQ;MACvB,MAAM;MACN,MAAM,CAAC;KACT,CAAC;KACD;IAEF,SACE,MAAM,IAAI,MAAM,0BAA0B,MAAM,MAAM;GAC1D;EACF,EACF,CAAC,CACH;CACF;CAEA,IAAI,WAAW;EACb,OAAO,KAAK;CACd;CAEA;CAEA,MAAM,YAAY,UAA+C;EAC/D,KAAK,YAAY,QAAQ;GACvB,MAAM;GACN,MAAM,CAAC;GACP,GAAI,SAAS,aAAa,KAAA,IACtB,EAAE,UAAU,SAAS,SAAS,IAC9B,CAAC;GACL,QAAQ,SAAS;GACjB,SAAS,SAAS,WAAW;GAC7B,GAAI,SAAS,iBAAiB,KAAA,IAC1B,EAAE,cAAc,SAAS,aAAa,IACtC,CAAC;GACL,GAAI,SAAS,aAAa,KAAA,IACtB,EAAE,UAAU,SAAS,SAAS,IAC9B,CAAC;EACP,CAAC;EACD,KAAK,oBAAoB,MAAM;EAC/B,MAAM,QAAQ,QAAQ;CAExB;CAEA,MAAM,QAAQ;EACZ,IAAI,KAAK,WAAW;EAEpB,KAAK,YAAY;EACjB,KAAK,oBAAoB,MAAM;EAC/B,MAAM,KAAK;EAEX,KAAK,YAAY,QAAQ;GACvB,MAAM;GACN,MAAM,CAAC;EACT,CAAC;EACD,KAAK,YAAY,MAAM;CACzB;AACF;AAEA,MAAa,wBACX,aACoB;CACpB,OAAO,IAAI,eAAe;EACxB,MAAM,GAAG;GACP,OAAO,SAAS,QAAQ,IAAI,6BAA6B,CAAC,CAAC;EAC7D;EACA,KAAK,GAAG;GACN,OAAO,SAAS,OAAO,IAAI,6BAA6B,CAAC,CAAC;EAC5D;EACA,OAAO,GAAG;GACR,OAAO,SAAS,SAAS,CAAC;EAC5B;CACF,CAAC;AACH;AAEA,MAAa,uCAAuC;CAClD,IAAI;CAMJ,OAAO,CALQ,qBAAqB,EAClC,MAAM,GAAG;EACP,aAAa;CACf,EACF,CACa,GAAG,UAAU;AAC5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantTransport.d.ts","names":[],"sources":["../../../../src/core/serialization/assistant-transport/AssistantTransport.ts"],"mappings":";;;;;;;;cAYa,kCACH,wBAAwB,sBAAsB,WAAW,yBACtD;EAEX,SAAO;;;;;;;cA4BI,kCAAkC,wBAC7C,WAAW,cACX"}
1
+ {"version":3,"file":"AssistantTransport.d.ts","names":[],"sources":["../../../../src/core/serialization/assistant-transport/AssistantTransport.ts"],"mappings":";;;;;;;;cA6Ea,kCACH,wBAAwB,sBAAsB,WAAW,yBACtD;EAEX,SAAO;;;;;;;cA4BI,kCAAkC,wBAC7C,WAAW,cACX"}
@@ -1,6 +1,87 @@
1
1
  import { PipeableTransformStream } from "../../utils/stream/PipeableTransformStream.js";
2
2
  import { SSEEventDecoderStream } from "../../utils/stream/SSEEventDecoderStream.js";
3
+ import sjson from "secure-json-parse";
3
4
  //#region src/core/serialization/assistant-transport/AssistantTransport.ts
5
+ const noFields = () => true;
6
+ const requiredObject = (key) => (c) => {
7
+ const value = c[key];
8
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9
+ };
10
+ const requiredString = (key) => (c) => typeof c[key] === "string";
11
+ const requiredArray = (key) => (c) => Array.isArray(c[key]);
12
+ const optionalBoolean = (key) => (c) => c[key] === void 0 || typeof c[key] === "boolean";
13
+ const KNOWN_CHUNK_TYPES = {
14
+ "part-start": {
15
+ kind: "message",
16
+ valid: requiredObject("part")
17
+ },
18
+ "part-finish": {
19
+ kind: "part-addressed",
20
+ valid: noFields
21
+ },
22
+ "tool-call-args-text-finish": {
23
+ kind: "part-addressed",
24
+ valid: noFields
25
+ },
26
+ "text-delta": {
27
+ kind: "part-addressed",
28
+ valid: requiredString("textDelta")
29
+ },
30
+ annotations: {
31
+ kind: "message",
32
+ valid: requiredArray("annotations")
33
+ },
34
+ data: {
35
+ kind: "message",
36
+ valid: requiredArray("data")
37
+ },
38
+ "step-start": {
39
+ kind: "message",
40
+ valid: noFields
41
+ },
42
+ "step-finish": {
43
+ kind: "message",
44
+ valid: requiredString("finishReason")
45
+ },
46
+ "message-finish": {
47
+ kind: "message",
48
+ valid: requiredString("finishReason")
49
+ },
50
+ result: {
51
+ kind: "part-addressed",
52
+ valid: optionalBoolean("isError")
53
+ },
54
+ error: {
55
+ kind: "message",
56
+ valid: noFields
57
+ },
58
+ "update-state": {
59
+ kind: "message",
60
+ valid: requiredArray("operations")
61
+ }
62
+ };
63
+ const parseChunk = (data) => {
64
+ let value;
65
+ try {
66
+ value = sjson.parse(data);
67
+ } catch {
68
+ return "unparseable";
69
+ }
70
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return "not-an-object";
71
+ const { type, path } = value;
72
+ if (typeof type !== "string" || !Object.prototype.hasOwnProperty.call(KNOWN_CHUNK_TYPES, type)) return "unknown-type";
73
+ const rule = KNOWN_CHUNK_TYPES[type];
74
+ if (!rule.valid(value)) return `invalid-fields:${type}`;
75
+ if (path === void 0) {
76
+ if (rule.kind !== "message") return `missing-path:${type}`;
77
+ return {
78
+ ...value,
79
+ path: []
80
+ };
81
+ }
82
+ if (!Array.isArray(path) || !path.every((entry) => Number.isInteger(entry) && entry >= 0)) return "invalid-path";
83
+ return value;
84
+ };
4
85
  /**
5
86
  * AssistantTransportEncoder encodes AssistantStreamChunks into SSE format
6
87
  * and emits [DONE] when the stream completes.
@@ -32,6 +113,7 @@ var AssistantTransportDecoder = class extends PipeableTransformStream {
32
113
  constructor() {
33
114
  super((readable) => {
34
115
  let receivedDone = false;
116
+ const warnedReasons = /* @__PURE__ */ new Set();
35
117
  return readable.pipeThrough(new TextDecoderStream()).pipeThrough(new SSEEventDecoderStream()).pipeThrough(new TransformStream({
36
118
  transform(event, controller) {
37
119
  switch (event.event) {
@@ -39,7 +121,15 @@ var AssistantTransportDecoder = class extends PipeableTransformStream {
39
121
  if (event.data === "[DONE]") {
40
122
  receivedDone = true;
41
123
  controller.terminate();
42
- } else controller.enqueue(JSON.parse(event.data));
124
+ } else {
125
+ const chunk = parseChunk(event.data);
126
+ if (typeof chunk === "string") {
127
+ if (!warnedReasons.has(chunk)) {
128
+ warnedReasons.add(chunk);
129
+ console.warn(`Dropped invalid assistant-transport chunk (${chunk}): ${event.data.slice(0, 200)}`);
130
+ }
131
+ } else controller.enqueue(chunk);
132
+ }
43
133
  break;
44
134
  default: throw new Error(`Unknown SSE event type: ${event.event}`);
45
135
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantTransport.js","names":[],"sources":["../../../../src/core/serialization/assistant-transport/AssistantTransport.ts"],"sourcesContent":["import type { AssistantStreamChunk } from \"../../AssistantStreamChunk\";\nimport { PipeableTransformStream } from \"../../utils/stream/PipeableTransformStream\";\nimport {\n SSEEventDecoderStream,\n type PipelineSSEEvent,\n} from \"../../utils/stream/SSEEventDecoderStream\";\nimport type { AssistantStreamEncoder } from \"../../AssistantStream\";\n\n/**\n * AssistantTransportEncoder encodes AssistantStreamChunks into SSE format\n * and emits [DONE] when the stream completes.\n */\nexport class AssistantTransportEncoder\n extends PipeableTransformStream<AssistantStreamChunk, Uint8Array<ArrayBuffer>>\n implements AssistantStreamEncoder\n{\n headers = new Headers({\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n\n constructor() {\n super((readable) => {\n return readable\n .pipeThrough(\n new TransformStream<AssistantStreamChunk, string>({\n transform(chunk, controller) {\n controller.enqueue(`data: ${JSON.stringify(chunk)}\\n\\n`);\n },\n flush(controller) {\n controller.enqueue(\"data: [DONE]\\n\\n\");\n },\n }),\n )\n .pipeThrough(new TextEncoderStream());\n });\n }\n}\n\n/**\n * AssistantTransportDecoder decodes SSE format into AssistantStreamChunks.\n * It stops decoding when it encounters [DONE].\n */\nexport class AssistantTransportDecoder extends PipeableTransformStream<\n Uint8Array<ArrayBuffer>,\n AssistantStreamChunk\n> {\n constructor() {\n super((readable) => {\n let receivedDone = false;\n\n return readable\n .pipeThrough(new TextDecoderStream())\n .pipeThrough(new SSEEventDecoderStream())\n .pipeThrough(\n new TransformStream<PipelineSSEEvent, AssistantStreamChunk>({\n transform(event, controller) {\n switch (event.event) {\n case \"message\":\n if (event.data === \"[DONE]\") {\n // Mark that we received [DONE]\n receivedDone = true;\n // Stop processing when we encounter [DONE]\n controller.terminate();\n } else {\n controller.enqueue(JSON.parse(event.data));\n }\n break;\n default:\n throw new Error(`Unknown SSE event type: ${event.event}`);\n }\n },\n flush() {\n if (!receivedDone) {\n throw new Error(\n \"Stream ended abruptly without receiving [DONE] marker\",\n );\n }\n },\n }),\n );\n });\n }\n}\n"],"mappings":";;;;;;;AAYA,IAAa,4BAAb,cACU,wBAEV;CACE,UAAU,IAAI,QAAQ;EACpB,gBAAgB;EAChB,iBAAiB;EACjB,YAAY;CACd,CAAC;CAED,cAAc;EACZ,OAAO,aAAa;GAClB,OAAO,SACJ,YACC,IAAI,gBAA8C;IAChD,UAAU,OAAO,YAAY;KAC3B,WAAW,QAAQ,SAAS,KAAK,UAAU,KAAK,EAAE,KAAK;IACzD;IACA,MAAM,YAAY;KAChB,WAAW,QAAQ,kBAAkB;IACvC;GACF,CAAC,CACH,CAAC,CACA,YAAY,IAAI,kBAAkB,CAAC;EACxC,CAAC;CACH;AACF;;;;;AAMA,IAAa,4BAAb,cAA+C,wBAG7C;CACA,cAAc;EACZ,OAAO,aAAa;GAClB,IAAI,eAAe;GAEnB,OAAO,SACJ,YAAY,IAAI,kBAAkB,CAAC,CAAC,CACpC,YAAY,IAAI,sBAAsB,CAAC,CAAC,CACxC,YACC,IAAI,gBAAwD;IAC1D,UAAU,OAAO,YAAY;KAC3B,QAAQ,MAAM,OAAd;MACE,KAAK;OACH,IAAI,MAAM,SAAS,UAAU;QAE3B,eAAe;QAEf,WAAW,UAAU;OACvB,OACE,WAAW,QAAQ,KAAK,MAAM,MAAM,IAAI,CAAC;OAE3C;MACF,SACE,MAAM,IAAI,MAAM,2BAA2B,MAAM,OAAO;KAC5D;IACF;IACA,QAAQ;KACN,IAAI,CAAC,cACH,MAAM,IAAI,MACR,uDACF;IAEJ;GACF,CAAC,CACH;EACJ,CAAC;CACH;AACF"}
1
+ {"version":3,"file":"AssistantTransport.js","names":[],"sources":["../../../../src/core/serialization/assistant-transport/AssistantTransport.ts"],"sourcesContent":["import sjson from \"secure-json-parse\";\nimport type { AssistantStreamChunk } from \"../../AssistantStreamChunk\";\nimport { PipeableTransformStream } from \"../../utils/stream/PipeableTransformStream\";\nimport {\n SSEEventDecoderStream,\n type PipelineSSEEvent,\n} from \"../../utils/stream/SSEEventDecoderStream\";\nimport type { AssistantStreamEncoder } from \"../../AssistantStream\";\n\ntype ChunkFields = Record<string, unknown>;\n\ntype ChunkRule = {\n kind: \"message\" | \"part-addressed\";\n valid: (chunk: ChunkFields) => boolean;\n};\n\nconst noFields = () => true;\nconst requiredObject = (key: string) => (c: ChunkFields) => {\n const value = c[key];\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n};\nconst requiredString = (key: string) => (c: ChunkFields) =>\n typeof c[key] === \"string\";\nconst requiredArray = (key: string) => (c: ChunkFields) =>\n Array.isArray(c[key]);\nconst optionalBoolean = (key: string) => (c: ChunkFields) =>\n c[key] === undefined || typeof c[key] === \"boolean\";\n\nconst KNOWN_CHUNK_TYPES: Record<AssistantStreamChunk[\"type\"], ChunkRule> = {\n \"part-start\": { kind: \"message\", valid: requiredObject(\"part\") },\n \"part-finish\": { kind: \"part-addressed\", valid: noFields },\n \"tool-call-args-text-finish\": { kind: \"part-addressed\", valid: noFields },\n \"text-delta\": { kind: \"part-addressed\", valid: requiredString(\"textDelta\") },\n annotations: { kind: \"message\", valid: requiredArray(\"annotations\") },\n data: { kind: \"message\", valid: requiredArray(\"data\") },\n \"step-start\": { kind: \"message\", valid: noFields },\n \"step-finish\": { kind: \"message\", valid: requiredString(\"finishReason\") },\n \"message-finish\": { kind: \"message\", valid: requiredString(\"finishReason\") },\n result: { kind: \"part-addressed\", valid: optionalBoolean(\"isError\") },\n error: { kind: \"message\", valid: noFields },\n \"update-state\": { kind: \"message\", valid: requiredArray(\"operations\") },\n};\n\nconst parseChunk = (data: string): AssistantStreamChunk | string => {\n let value: unknown;\n try {\n value = sjson.parse(data);\n } catch {\n return \"unparseable\";\n }\n if (typeof value !== \"object\" || value === null || Array.isArray(value))\n return \"not-an-object\";\n const { type, path } = value as { type?: unknown; path?: unknown };\n if (\n typeof type !== \"string\" ||\n !Object.prototype.hasOwnProperty.call(KNOWN_CHUNK_TYPES, type)\n )\n return \"unknown-type\";\n const rule = KNOWN_CHUNK_TYPES[type as AssistantStreamChunk[\"type\"]];\n if (!rule.valid(value as Record<string, unknown>))\n return `invalid-fields:${type}`;\n if (path === undefined) {\n if (rule.kind !== \"message\") return `missing-path:${type}`;\n return { ...value, path: [] } as unknown as AssistantStreamChunk;\n }\n if (\n !Array.isArray(path) ||\n !path.every((entry) => Number.isInteger(entry) && entry >= 0)\n )\n return \"invalid-path\";\n return value as AssistantStreamChunk;\n};\n\n/**\n * AssistantTransportEncoder encodes AssistantStreamChunks into SSE format\n * and emits [DONE] when the stream completes.\n */\nexport class AssistantTransportEncoder\n extends PipeableTransformStream<AssistantStreamChunk, Uint8Array<ArrayBuffer>>\n implements AssistantStreamEncoder\n{\n headers = new Headers({\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n\n constructor() {\n super((readable) => {\n return readable\n .pipeThrough(\n new TransformStream<AssistantStreamChunk, string>({\n transform(chunk, controller) {\n controller.enqueue(`data: ${JSON.stringify(chunk)}\\n\\n`);\n },\n flush(controller) {\n controller.enqueue(\"data: [DONE]\\n\\n\");\n },\n }),\n )\n .pipeThrough(new TextEncoderStream());\n });\n }\n}\n\n/**\n * AssistantTransportDecoder decodes SSE format into AssistantStreamChunks.\n * It stops decoding when it encounters [DONE].\n */\nexport class AssistantTransportDecoder extends PipeableTransformStream<\n Uint8Array<ArrayBuffer>,\n AssistantStreamChunk\n> {\n constructor() {\n super((readable) => {\n let receivedDone = false;\n const warnedReasons = new Set<string>();\n\n return readable\n .pipeThrough(new TextDecoderStream())\n .pipeThrough(new SSEEventDecoderStream())\n .pipeThrough(\n new TransformStream<PipelineSSEEvent, AssistantStreamChunk>({\n transform(event, controller) {\n switch (event.event) {\n case \"message\":\n if (event.data === \"[DONE]\") {\n // Mark that we received [DONE]\n receivedDone = true;\n // Stop processing when we encounter [DONE]\n controller.terminate();\n } else {\n const chunk = parseChunk(event.data);\n if (typeof chunk === \"string\") {\n if (!warnedReasons.has(chunk)) {\n warnedReasons.add(chunk);\n console.warn(\n `Dropped invalid assistant-transport chunk (${chunk}): ${event.data.slice(0, 200)}`,\n );\n }\n } else {\n controller.enqueue(chunk);\n }\n }\n break;\n default:\n throw new Error(`Unknown SSE event type: ${event.event}`);\n }\n },\n flush() {\n if (!receivedDone) {\n throw new Error(\n \"Stream ended abruptly without receiving [DONE] marker\",\n );\n }\n },\n }),\n );\n });\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { ReadonlyJSONObject, ReadonlyJSONValue } from "../../../utils/json/json-value.js";
2
- import { ObjectStreamOperation } from "../../object/types.js";
2
+ import { GorpStreamOperation } from "../../gorp/types.js";
3
3
  //#region src/core/serialization/data-stream/chunk-types.d.ts
4
4
  type DataStreamChunk = { [K in DataStreamStreamChunkType]: {
5
5
  type: K;
@@ -87,7 +87,7 @@ type DataStreamStreamChunkValue = {
87
87
  data: string;
88
88
  mimeType: string;
89
89
  };
90
- [DataStreamStreamChunkType.AuiUpdateStateOperations]: ObjectStreamOperation[];
90
+ [DataStreamStreamChunkType.AuiUpdateStateOperations]: GorpStreamOperation[];
91
91
  [DataStreamStreamChunkType.AuiTextDelta]: {
92
92
  textDelta: string;
93
93
  parentId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-types.js","names":[],"sources":["../../../../src/core/serialization/data-stream/chunk-types.ts"],"sourcesContent":["import type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"../../../utils/json/json-value\";\nimport type { ObjectStreamOperation } from \"../../object/types\";\n\nexport type DataStreamChunk = {\n [K in DataStreamStreamChunkType]: {\n type: K;\n value: DataStreamStreamChunkValue[K];\n };\n}[DataStreamStreamChunkType];\n\ntype LanguageModelV1FinishReason =\n | \"stop\"\n | \"length\"\n | \"content-filter\"\n | \"tool-calls\"\n | \"error\"\n | \"other\"\n | \"unknown\";\n\ntype LanguageModelV1Usage = {\n inputTokens: number;\n outputTokens: number;\n};\n\nexport enum DataStreamStreamChunkType {\n TextDelta = \"0\",\n Data = \"2\",\n Error = \"3\",\n Annotation = \"8\",\n ToolCall = \"9\",\n ToolCallResult = \"a\",\n StartToolCall = \"b\",\n ToolCallArgsTextDelta = \"c\",\n FinishMessage = \"d\",\n FinishStep = \"e\",\n StartStep = \"f\",\n ReasoningDelta = \"g\",\n Source = \"h\",\n RedactedReasoning = \"i\",\n ReasoningSignature = \"j\",\n File = \"k\",\n\n AuiUpdateStateOperations = \"aui-state\",\n AuiTextDelta = \"aui-text-delta\",\n AuiReasoningDelta = \"aui-reasoning-delta\",\n AuiDataPart = \"aui-data\",\n}\ntype DataStreamStreamChunkValue = {\n [DataStreamStreamChunkType.TextDelta]: string;\n [DataStreamStreamChunkType.Data]: ReadonlyJSONValue[];\n [DataStreamStreamChunkType.Annotation]: ReadonlyJSONValue[];\n [DataStreamStreamChunkType.ToolCall]: {\n toolCallId: string;\n toolName: string;\n args: ReadonlyJSONObject;\n };\n [DataStreamStreamChunkType.StartToolCall]: {\n toolCallId: string;\n toolName: string;\n parentId?: string;\n };\n [DataStreamStreamChunkType.ToolCallArgsTextDelta]: {\n toolCallId: string;\n argsTextDelta: string;\n };\n [DataStreamStreamChunkType.ToolCallResult]: {\n toolCallId: string;\n result: ReadonlyJSONValue;\n\n // aui-extensions\n artifact?: ReadonlyJSONValue | undefined;\n isError?: boolean;\n };\n [DataStreamStreamChunkType.Error]: string;\n [DataStreamStreamChunkType.FinishStep]: {\n finishReason: LanguageModelV1FinishReason;\n usage: LanguageModelV1Usage;\n isContinued: boolean;\n };\n [DataStreamStreamChunkType.FinishMessage]: {\n finishReason: LanguageModelV1FinishReason;\n usage: LanguageModelV1Usage;\n };\n [DataStreamStreamChunkType.StartStep]: {\n messageId: string;\n };\n [DataStreamStreamChunkType.ReasoningDelta]: string;\n [DataStreamStreamChunkType.Source]: {\n sourceType: \"url\";\n id: string;\n url: string;\n title?: string;\n parentId?: string;\n };\n [DataStreamStreamChunkType.RedactedReasoning]: { data: string };\n [DataStreamStreamChunkType.ReasoningSignature]: { signature: string };\n [DataStreamStreamChunkType.File]: { data: string; mimeType: string };\n\n // aui-extensions\n [DataStreamStreamChunkType.AuiUpdateStateOperations]: ObjectStreamOperation[];\n [DataStreamStreamChunkType.AuiTextDelta]: {\n textDelta: string;\n parentId: string;\n };\n [DataStreamStreamChunkType.AuiReasoningDelta]: {\n reasoningDelta: string;\n parentId: string;\n };\n [DataStreamStreamChunkType.AuiDataPart]: {\n name: string;\n data: ReadonlyJSONValue;\n parentId?: string;\n };\n};\n"],"mappings":";AA2BA,IAAY,4BAAL,yBAAA,2BAAA;CACL,0BAAA,eAAA;CACA,0BAAA,UAAA;CACA,0BAAA,WAAA;CACA,0BAAA,gBAAA;CACA,0BAAA,cAAA;CACA,0BAAA,oBAAA;CACA,0BAAA,mBAAA;CACA,0BAAA,2BAAA;CACA,0BAAA,mBAAA;CACA,0BAAA,gBAAA;CACA,0BAAA,eAAA;CACA,0BAAA,oBAAA;CACA,0BAAA,YAAA;CACA,0BAAA,uBAAA;CACA,0BAAA,wBAAA;CACA,0BAAA,UAAA;CAEA,0BAAA,8BAAA;CACA,0BAAA,kBAAA;CACA,0BAAA,uBAAA;CACA,0BAAA,iBAAA;;AACF,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"chunk-types.js","names":[],"sources":["../../../../src/core/serialization/data-stream/chunk-types.ts"],"sourcesContent":["import type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"../../../utils/json/json-value\";\nimport type { GorpStreamOperation } from \"../../gorp/types\";\n\nexport type DataStreamChunk = {\n [K in DataStreamStreamChunkType]: {\n type: K;\n value: DataStreamStreamChunkValue[K];\n };\n}[DataStreamStreamChunkType];\n\ntype LanguageModelV1FinishReason =\n | \"stop\"\n | \"length\"\n | \"content-filter\"\n | \"tool-calls\"\n | \"error\"\n | \"other\"\n | \"unknown\";\n\ntype LanguageModelV1Usage = {\n inputTokens: number;\n outputTokens: number;\n};\n\nexport enum DataStreamStreamChunkType {\n TextDelta = \"0\",\n Data = \"2\",\n Error = \"3\",\n Annotation = \"8\",\n ToolCall = \"9\",\n ToolCallResult = \"a\",\n StartToolCall = \"b\",\n ToolCallArgsTextDelta = \"c\",\n FinishMessage = \"d\",\n FinishStep = \"e\",\n StartStep = \"f\",\n ReasoningDelta = \"g\",\n Source = \"h\",\n RedactedReasoning = \"i\",\n ReasoningSignature = \"j\",\n File = \"k\",\n\n AuiUpdateStateOperations = \"aui-state\",\n AuiTextDelta = \"aui-text-delta\",\n AuiReasoningDelta = \"aui-reasoning-delta\",\n AuiDataPart = \"aui-data\",\n}\ntype DataStreamStreamChunkValue = {\n [DataStreamStreamChunkType.TextDelta]: string;\n [DataStreamStreamChunkType.Data]: ReadonlyJSONValue[];\n [DataStreamStreamChunkType.Annotation]: ReadonlyJSONValue[];\n [DataStreamStreamChunkType.ToolCall]: {\n toolCallId: string;\n toolName: string;\n args: ReadonlyJSONObject;\n };\n [DataStreamStreamChunkType.StartToolCall]: {\n toolCallId: string;\n toolName: string;\n parentId?: string;\n };\n [DataStreamStreamChunkType.ToolCallArgsTextDelta]: {\n toolCallId: string;\n argsTextDelta: string;\n };\n [DataStreamStreamChunkType.ToolCallResult]: {\n toolCallId: string;\n result: ReadonlyJSONValue;\n\n // aui-extensions\n artifact?: ReadonlyJSONValue | undefined;\n isError?: boolean;\n };\n [DataStreamStreamChunkType.Error]: string;\n [DataStreamStreamChunkType.FinishStep]: {\n finishReason: LanguageModelV1FinishReason;\n usage: LanguageModelV1Usage;\n isContinued: boolean;\n };\n [DataStreamStreamChunkType.FinishMessage]: {\n finishReason: LanguageModelV1FinishReason;\n usage: LanguageModelV1Usage;\n };\n [DataStreamStreamChunkType.StartStep]: {\n messageId: string;\n };\n [DataStreamStreamChunkType.ReasoningDelta]: string;\n [DataStreamStreamChunkType.Source]: {\n sourceType: \"url\";\n id: string;\n url: string;\n title?: string;\n parentId?: string;\n };\n [DataStreamStreamChunkType.RedactedReasoning]: { data: string };\n [DataStreamStreamChunkType.ReasoningSignature]: { signature: string };\n [DataStreamStreamChunkType.File]: { data: string; mimeType: string };\n\n // aui-extensions\n [DataStreamStreamChunkType.AuiUpdateStateOperations]: GorpStreamOperation[];\n [DataStreamStreamChunkType.AuiTextDelta]: {\n textDelta: string;\n parentId: string;\n };\n [DataStreamStreamChunkType.AuiReasoningDelta]: {\n reasoningDelta: string;\n parentId: string;\n };\n [DataStreamStreamChunkType.AuiDataPart]: {\n name: string;\n data: ReadonlyJSONValue;\n parentId?: string;\n };\n};\n"],"mappings":";AA2BA,IAAY,4BAAL,yBAAA,2BAAA;CACL,0BAAA,eAAA;CACA,0BAAA,UAAA;CACA,0BAAA,WAAA;CACA,0BAAA,gBAAA;CACA,0BAAA,cAAA;CACA,0BAAA,oBAAA;CACA,0BAAA,mBAAA;CACA,0BAAA,2BAAA;CACA,0BAAA,mBAAA;CACA,0BAAA,gBAAA;CACA,0BAAA,eAAA;CACA,0BAAA,oBAAA;CACA,0BAAA,YAAA;CACA,0BAAA,uBAAA;CACA,0BAAA,wBAAA;CACA,0BAAA,UAAA;CAEA,0BAAA,8BAAA;CACA,0BAAA,kBAAA;CACA,0BAAA,uBAAA;CACA,0BAAA,iBAAA;;AACF,EAAA,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"UIMessageStream.d.ts","names":[],"sources":["../../../../src/core/serialization/ui-message-stream/UIMessageStream.ts"],"mappings":";;;;KAiBY;EACV,UAAU;IACR;IACA;IACA;IACA;;;;;;cAWS,+BAA+B,wBAC1C,WAAW,cACX;cAEY,UAAS"}
1
+ {"version":3,"file":"UIMessageStream.d.ts","names":[],"sources":["../../../../src/core/serialization/ui-message-stream/UIMessageStream.ts"],"mappings":";;;;KAiBY;EACV,UAAU;IACR;IACA;IACA;IACA;;;;;;cAWS,+BAA+B,wBAC1C,WAAW,cACX;EAEY,YAAA,UAAS"}