assistant-stream 0.0.20 → 0.0.22

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.
package/dist/index.mjs CHANGED
@@ -1,519 +1,128 @@
1
1
  import {
2
+ AssistantMetaTransformStream,
3
+ AssistantStream,
4
+ AssistantTransformStream,
5
+ DataStreamDecoder,
6
+ DataStreamEncoder,
7
+ PipeableTransformStream,
8
+ createAssistantStream,
9
+ createAssistantStreamResponse,
2
10
  generateId
3
- } from "./chunk-ZSSWV6GU.mjs";
4
-
5
- // src/core/AssistantStream.ts
6
- var AssistantStream = {
7
- toResponse(stream, transformer) {
8
- return new Response(AssistantStream.toByteStream(stream, transformer));
9
- },
10
- fromResponse(response, transformer) {
11
- return AssistantStream.fromByteStream(response.body, transformer);
12
- },
13
- toByteStream(stream, transformer) {
14
- return stream.pipeThrough(transformer);
15
- },
16
- fromByteStream(readable, transformer) {
17
- return readable.pipeThrough(transformer);
18
- }
19
- };
11
+ } from "./chunk-DISBVUTK.mjs";
20
12
 
21
- // src/core/utils/PipeableTransformStream.ts
22
- var PipeableTransformStream = class extends TransformStream {
23
- constructor(transform) {
24
- super();
25
- const readable = transform(super.readable);
26
- Object.defineProperty(this, "readable", {
27
- value: readable,
28
- writable: false
29
- });
30
- }
31
- };
32
-
33
- // src/core/serialization/DataStream.ts
34
- var DataStreamEncoder = class {
35
- _transformStream;
36
- get writable() {
37
- return this._transformStream.writable;
38
- }
39
- get readable() {
40
- return this._transformStream.readable;
41
- }
42
- constructor() {
43
- this._transformStream = new PipeableTransformStream((readable) => {
13
+ // src/core/effects/ToolExecutionStream.ts
14
+ import sjson from "secure-json-parse";
15
+ var ToolExecutionStream = class extends PipeableTransformStream {
16
+ constructor(toolCallback) {
17
+ const toolCallPromises = /* @__PURE__ */ new Map();
18
+ const toolCallArgsText = {};
19
+ super((readable) => {
44
20
  const transform = new TransformStream({
45
21
  transform(chunk, controller) {
46
- const type = chunk.type;
47
- switch (type) {
48
- case "text-delta":
49
- controller.enqueue("0:" + JSON.stringify(chunk.textDelta) + "\n");
50
- break;
51
- case "tool-call-begin":
52
- controller.enqueue(
53
- "b:" + JSON.stringify({
54
- toolCallId: chunk.toolCallId,
55
- toolName: chunk.toolName
56
- }) + "\n"
57
- );
58
- break;
59
- case "tool-call-delta":
60
- controller.enqueue(
61
- "c:" + JSON.stringify({
62
- toolCallId: chunk.toolCallId,
63
- argsTextDelta: chunk.argsTextDelta
64
- }) + "\n"
65
- );
66
- break;
67
- case "tool-result":
68
- controller.enqueue(
69
- "a:" + JSON.stringify({
70
- toolCallId: chunk.toolCallId,
71
- result: chunk.result
72
- }) + "\n"
73
- );
74
- break;
75
- case "error":
76
- controller.enqueue(`3:${JSON.stringify(chunk.error)}
77
- `);
78
- break;
79
- default:
80
- const exhaustiveCheck = type;
81
- throw new Error(`unsupported chunk type: ${exhaustiveCheck}`);
22
+ if (chunk.type !== "part-finish" || chunk.meta.type !== "tool-call") {
23
+ controller.enqueue(chunk);
82
24
  }
83
- }
84
- });
85
- return readable.pipeThrough(transform).pipeThrough(new TextEncoderStream());
86
- });
87
- }
88
- };
89
- var decodeStreamPart = (part) => {
90
- const index = part.indexOf(":");
91
- if (index === -1) throw new Error("Invalid stream part");
92
- return {
93
- type: part.slice(0, index),
94
- value: JSON.parse(part.slice(index + 1))
95
- };
96
- };
97
- var DataStreamDecoder = class {
98
- _transformStream;
99
- get writable() {
100
- return this._transformStream.writable;
101
- }
102
- get readable() {
103
- return this._transformStream.readable;
104
- }
105
- constructor() {
106
- this._transformStream = new PipeableTransformStream((readable) => {
107
- const transform = new TransformStream({
108
- transform(chunk, controller) {
109
- const { type, value } = decodeStreamPart(chunk);
25
+ const type = chunk.type;
110
26
  switch (type) {
111
- case "0":
112
- controller.enqueue({
113
- type: "text-delta",
114
- textDelta: value
115
- });
116
- break;
117
- case "b": {
118
- const { toolCallId, toolName } = value;
119
- controller.enqueue({
120
- type: "tool-call-begin",
121
- toolCallId,
122
- toolName
123
- });
27
+ case "text-delta": {
28
+ if (chunk.meta.type === "tool-call") {
29
+ const toolCallId = chunk.meta.toolCallId;
30
+ if (toolCallArgsText[toolCallId] === void 0) {
31
+ toolCallArgsText[toolCallId] = chunk.textDelta;
32
+ } else {
33
+ toolCallArgsText[toolCallId] += chunk.textDelta;
34
+ }
35
+ }
124
36
  break;
125
37
  }
126
- case "c": {
127
- const { toolCallId, argsTextDelta } = value;
128
- controller.enqueue({
129
- type: "tool-call-delta",
130
- toolCallId,
131
- argsTextDelta
132
- });
38
+ case "tool-call-args-text-finish": {
39
+ if (chunk.meta.type !== "tool-call") break;
40
+ const { toolCallId, toolName } = chunk.meta;
41
+ const argsText = toolCallArgsText[toolCallId];
42
+ if (!argsText)
43
+ throw new Error("Unexpected tool call without args");
44
+ const executeTool = () => {
45
+ let args;
46
+ try {
47
+ args = sjson.parse(argsText);
48
+ } catch (e) {
49
+ throw new Error(
50
+ `Function parameter parsing failed. ${JSON.stringify(e.message)}`
51
+ );
52
+ }
53
+ return toolCallback({
54
+ toolCallId,
55
+ toolName,
56
+ args
57
+ });
58
+ };
59
+ let promiseOrUndefined;
60
+ try {
61
+ promiseOrUndefined = executeTool();
62
+ } catch (e) {
63
+ controller.enqueue({
64
+ type: "result",
65
+ path: chunk.path,
66
+ result: String(e),
67
+ isError: true
68
+ });
69
+ break;
70
+ }
71
+ if (promiseOrUndefined instanceof Promise) {
72
+ const toolCallPromise = promiseOrUndefined.then((c) => {
73
+ if (c === void 0) return;
74
+ controller.enqueue({
75
+ type: "result",
76
+ path: chunk.path,
77
+ result: c,
78
+ isError: false
79
+ });
80
+ }).catch((e) => {
81
+ controller.enqueue({
82
+ type: "result",
83
+ path: chunk.path,
84
+ result: String(e),
85
+ isError: true
86
+ });
87
+ });
88
+ toolCallPromises.set(toolCallId, toolCallPromise);
89
+ } else if (promiseOrUndefined !== void 0) {
90
+ controller.enqueue({
91
+ type: "result",
92
+ path: chunk.path,
93
+ result: promiseOrUndefined,
94
+ isError: false
95
+ });
96
+ }
133
97
  break;
134
98
  }
135
- case "a": {
136
- const { toolCallId, result } = value;
137
- controller.enqueue({
138
- type: "tool-result",
139
- toolCallId,
140
- result
141
- });
142
- break;
143
- }
144
- case "9": {
145
- const { toolCallId, args } = value;
146
- controller.enqueue({
147
- type: "tool-call-begin",
148
- toolCallId,
149
- toolName: toolCallId
150
- });
151
- controller.enqueue({
152
- type: "tool-call-delta",
153
- toolCallId,
154
- argsTextDelta: JSON.stringify(args)
155
- });
156
- break;
157
- }
158
- case "2":
159
- case "3":
160
- case "8":
161
- case "d":
162
- case "e": {
163
- break;
99
+ case "part-finish": {
100
+ if (chunk.meta.type !== "tool-call") break;
101
+ const { toolCallId } = chunk.meta;
102
+ const toolCallPromise = toolCallPromises.get(toolCallId);
103
+ if (toolCallPromise) {
104
+ toolCallPromise.then(() => {
105
+ controller.enqueue(chunk);
106
+ });
107
+ } else {
108
+ controller.enqueue(chunk);
109
+ }
164
110
  }
165
- default:
166
- const exhaustiveCheck = type;
167
- throw new Error(`unsupported chunk type: ${exhaustiveCheck}`);
168
111
  }
112
+ },
113
+ async flush() {
114
+ await Promise.all(toolCallPromises);
169
115
  }
170
116
  });
171
- return readable.pipeThrough(new TextDecoderStream()).pipeThrough(new ChunkByLineStream()).pipeThrough(transform);
172
- });
173
- }
174
- };
175
- var ChunkByLineStream = class extends TransformStream {
176
- buffer = "";
177
- constructor() {
178
- super({
179
- transform: (chunk, controller) => {
180
- this.buffer += chunk;
181
- const lines = this.buffer.split("\n");
182
- for (let i = 0; i < lines.length - 1; i++) {
183
- controller.enqueue(lines[i]);
184
- }
185
- this.buffer = lines[lines.length - 1];
186
- },
187
- flush: (controller) => {
188
- if (this.buffer) {
189
- controller.enqueue(this.buffer);
190
- }
191
- }
192
- });
193
- }
194
- };
195
-
196
- // src/core/modules/text.ts
197
- var TextStreamControllerImpl = class {
198
- _controller;
199
- constructor(controller) {
200
- this._controller = controller;
201
- }
202
- append(textDelta) {
203
- this._controller.enqueue({
204
- type: "text-delta",
205
- textDelta
206
- });
207
- return this;
208
- }
209
- close() {
210
- this._controller.close();
211
- }
212
- };
213
- var createTextStream = (readable) => {
214
- return new ReadableStream({
215
- start(c) {
216
- return readable.start?.(new TextStreamControllerImpl(c));
217
- },
218
- pull(c) {
219
- return readable.pull?.(new TextStreamControllerImpl(c));
220
- },
221
- cancel(c) {
222
- return readable.cancel?.(c);
223
- }
224
- });
225
- };
226
-
227
- // src/core/modules/tool-call.ts
228
- var ToolCallStreamControllerImpl = class {
229
- constructor(_controller, _options) {
230
- this._controller = _controller;
231
- this._options = _options;
232
- this._controller.enqueue({
233
- type: "tool-call-begin",
234
- toolCallId: this._options.toolCallId,
235
- toolName: this._options.toolName
236
- });
237
- const stream = createTextStream({
238
- start: (c) => {
239
- this._argsTextController = c;
240
- }
241
- });
242
- stream.pipeTo(
243
- new WritableStream({
244
- write: (chunk) => {
245
- if (chunk.type !== "text-delta")
246
- throw new Error("Unexpected chunk type");
247
- this._controller.enqueue({
248
- type: "tool-call-delta",
249
- toolCallId: this._options.toolCallId,
250
- argsTextDelta: chunk.textDelta
251
- });
252
- }
253
- })
254
- );
255
- }
256
- get toolCallId() {
257
- return this._options.toolCallId;
258
- }
259
- get toolName() {
260
- return this._options.toolName;
261
- }
262
- get argsText() {
263
- return this._argsTextController;
264
- }
265
- _argsTextController;
266
- setResult(result) {
267
- this._controller.enqueue({
268
- type: "tool-result",
269
- toolCallId: this._options.toolCallId,
270
- result
117
+ return readable.pipeThrough(new AssistantMetaTransformStream()).pipeThrough(transform);
271
118
  });
272
119
  }
273
- close() {
274
- this._controller.close();
275
- }
276
- };
277
- var createToolCallStream = (readable) => {
278
- const options = {
279
- toolCallId: readable.toolCallId,
280
- toolName: readable.toolName
281
- };
282
- return new ReadableStream({
283
- start(c) {
284
- return readable.start?.(new ToolCallStreamControllerImpl(c, options));
285
- },
286
- pull(c) {
287
- return readable.pull?.(new ToolCallStreamControllerImpl(c, options));
288
- },
289
- cancel(c) {
290
- return readable.cancel?.(c);
291
- }
292
- });
293
120
  };
294
121
 
295
- // src/core/modules/runs.ts
296
- var promiseWithResolvers = () => {
297
- let resolve;
298
- let reject;
299
- const promise = new Promise((res, rej) => {
300
- resolve = res;
301
- reject = rej;
302
- });
303
- return { promise, resolve, reject };
304
- };
305
- var createMergeStream = () => {
306
- const list = [];
307
- let sealed = false;
308
- let controller;
309
- let currentPull;
310
- const handlePull = (item) => {
311
- if (!item.promise) {
312
- item.promise = item.reader.read().then(({ done, value }) => {
313
- item.promise = void 0;
314
- if (done) {
315
- list.splice(list.indexOf(item), 1);
316
- if (sealed && list.length === 0) {
317
- controller.close();
318
- }
319
- } else {
320
- controller.enqueue(value);
321
- }
322
- currentPull?.resolve();
323
- currentPull = void 0;
324
- }).catch((e) => {
325
- list.forEach((item2) => {
326
- item2.reader.cancel();
327
- });
328
- list.length = 0;
329
- controller.error(e);
330
- currentPull?.reject(e);
331
- currentPull = void 0;
332
- });
333
- }
334
- };
335
- const readable = new ReadableStream({
336
- start(c) {
337
- controller = c;
338
- },
339
- async pull() {
340
- list.map((item) => {
341
- handlePull(item);
342
- return item.promise;
343
- });
344
- currentPull = promiseWithResolvers();
345
- return currentPull.promise;
346
- },
347
- cancel() {
348
- list.forEach((item) => {
349
- item.reader.cancel();
350
- });
351
- list.length = 0;
352
- }
353
- });
354
- return {
355
- stream: readable,
356
- seal() {
357
- sealed = true;
358
- if (list.length === 0) controller.close();
359
- },
360
- addStream(stream) {
361
- if (sealed)
362
- throw new Error(
363
- "Cannot add streams after the run callback has settled."
364
- );
365
- const item = { reader: stream.getReader() };
366
- list.push(item);
367
- if (list.length === 1) {
368
- handlePull(item);
369
- }
370
- }
371
- };
372
- };
373
- var RunControllerImpl = class {
374
- _merge = createMergeStream();
375
- _textPartController;
376
- getReadable() {
377
- return this._merge.stream;
378
- }
379
- close() {
380
- this._merge.seal();
381
- this._textPartController?.close();
382
- }
383
- merge(stream) {
384
- this._merge.addStream(stream);
385
- }
386
- appendText(textDelta) {
387
- if (!this._textPartController) {
388
- this._textPartController = this.addTextPart();
389
- }
390
- this._textPartController.append(textDelta);
391
- }
392
- addTextPart() {
393
- let controller;
394
- const textStream = createTextStream({
395
- start(c) {
396
- controller = c;
397
- }
398
- });
399
- this.merge(textStream);
400
- return controller;
401
- }
402
- addToolCallPart(options) {
403
- const opt = typeof options === "string" ? { toolName: options } : options;
404
- let controller;
405
- const toolCallStream = createToolCallStream({
406
- toolCallId: opt.toolCallId ?? generateId(),
407
- toolName: opt.toolName,
408
- start(c) {
409
- controller = c;
410
- }
411
- });
412
- this.merge(toolCallStream);
413
- if (opt.args !== void 0) {
414
- controller.argsText.append(JSON.stringify(opt.args));
415
- controller.argsText.close();
416
- }
417
- if (opt !== void 0) {
418
- controller.setResult(opt.result);
419
- }
420
- return controller;
421
- }
422
- addError(error) {
423
- this._merge.addStream(
424
- new ReadableStream({
425
- start(c) {
426
- c.enqueue({
427
- type: "error",
428
- error
429
- });
430
- }
431
- })
432
- );
433
- }
434
- };
435
- function createAssistantStream(callback) {
436
- const controller = new RunControllerImpl();
437
- const promiseOrVoid = callback(controller);
438
- if (promiseOrVoid instanceof Promise) {
439
- const runTask = async () => {
440
- try {
441
- await promiseOrVoid;
442
- } catch (e) {
443
- controller.addError(e instanceof Error ? e.message : String(e));
444
- throw e;
445
- } finally {
446
- controller.close();
447
- }
448
- };
449
- runTask();
450
- } else {
451
- controller.close();
452
- }
453
- return controller.getReadable();
454
- }
455
- function createAssistantStreamResponse(callback) {
456
- return AssistantStream.toResponse(
457
- createAssistantStream(callback),
458
- new DataStreamEncoder()
459
- );
460
- }
122
+ // src/core/utils/json/parse-partial-json.ts
123
+ import sjson2 from "secure-json-parse";
461
124
 
462
- // src/core/serialization/PlainText.ts
463
- var PlainTextEncoder = class {
464
- _transformStream;
465
- get writable() {
466
- return this._transformStream.writable;
467
- }
468
- get readable() {
469
- return this._transformStream.readable;
470
- }
471
- constructor() {
472
- this._transformStream = new PipeableTransformStream((readable) => {
473
- const transform = new TransformStream({
474
- transform(chunk, controller) {
475
- const type = chunk.type;
476
- switch (type) {
477
- case "text-delta":
478
- controller.enqueue(chunk.textDelta);
479
- break;
480
- default:
481
- const unsupportedType = type;
482
- throw new Error(`unsupported chunk type: ${unsupportedType}`);
483
- }
484
- }
485
- });
486
- return readable.pipeThrough(transform).pipeThrough(new TextEncoderStream());
487
- });
488
- }
489
- };
490
- var PlainTextDecoder = class {
491
- _transformStream;
492
- get writable() {
493
- return this._transformStream.writable;
494
- }
495
- get readable() {
496
- return this._transformStream.readable;
497
- }
498
- constructor() {
499
- this._transformStream = new PipeableTransformStream((readable) => {
500
- const transform = new TransformStream({
501
- transform(chunk, controller) {
502
- controller.enqueue({
503
- type: "text-delta",
504
- textDelta: chunk
505
- });
506
- }
507
- });
508
- return readable.pipeThrough(new TextDecoderStream()).pipeThrough(transform);
509
- });
510
- }
511
- };
512
-
513
- // src/core/accumulators/partial-json/parse-partial-json.ts
514
- import sjson from "secure-json-parse";
515
-
516
- // src/core/accumulators/partial-json/fix-json.ts
125
+ // src/core/utils/json/fix-json.ts
517
126
  function fixJson(input) {
518
127
  const stack = ["ROOT"];
519
128
  let lastValidIndex = -1;
@@ -831,176 +440,354 @@ function fixJson(input) {
831
440
  return result;
832
441
  }
833
442
 
834
- // src/core/accumulators/partial-json/parse-partial-json.ts
443
+ // src/core/utils/json/parse-partial-json.ts
835
444
  var parsePartialJson = (json) => {
836
445
  try {
837
- return sjson.parse(json);
446
+ return sjson2.parse(json);
838
447
  } catch {
839
448
  try {
840
- return sjson.parse(fixJson(json));
449
+ return sjson2.parse(fixJson(json));
841
450
  } catch {
842
451
  return void 0;
843
452
  }
844
453
  }
845
454
  };
846
455
 
847
- // src/core/accumulators/assistantMessageAccumulator.ts
848
- var assistantMessageAccumulator = () => {
849
- let message = {
850
- role: "assistant",
851
- content: [],
852
- status: { type: "running" },
853
- metadata: {
854
- steps: [],
855
- custom: {}
456
+ // src/core/accumulators/assistant-message-accumulator.ts
457
+ var createInitialMessage = () => ({
458
+ role: "assistant",
459
+ status: { type: "running" },
460
+ parts: [],
461
+ get content() {
462
+ return this.parts;
463
+ },
464
+ metadata: {
465
+ unstable_data: [],
466
+ unstable_annotations: [],
467
+ steps: [],
468
+ custom: {}
469
+ }
470
+ });
471
+ var updatePartForPath = (message, chunk, updater) => {
472
+ if (message.parts.length === 0) {
473
+ throw new Error("No parts available to update.");
474
+ }
475
+ if (chunk.path.length !== 1)
476
+ throw new Error("Nested paths are not supported yet.");
477
+ const partIndex = chunk.path[0];
478
+ const updatedPart = updater(message.parts[partIndex]);
479
+ return {
480
+ ...message,
481
+ parts: [
482
+ ...message.parts.slice(0, partIndex),
483
+ updatedPart,
484
+ ...message.parts.slice(partIndex + 1)
485
+ ],
486
+ get content() {
487
+ return this.parts;
856
488
  }
857
489
  };
858
- const transformer = new TransformStream({
859
- transform(chunk, controller) {
860
- const { type } = chunk;
861
- switch (type) {
862
- case "text-delta": {
863
- message = appendOrUpdateText(message, chunk.textDelta);
864
- controller.enqueue(message);
865
- break;
866
- }
867
- case "tool-call-begin": {
868
- const { toolCallId, toolName } = chunk;
869
- message = appendToolCall(message, toolCallId, toolName);
870
- controller.enqueue(message);
871
- break;
872
- }
873
- case "tool-call-delta": {
874
- const { toolCallId, argsTextDelta } = chunk;
875
- message = appendToolArgsTextDelta(message, toolCallId, argsTextDelta);
876
- controller.enqueue(message);
877
- break;
878
- }
879
- case "tool-result": {
880
- const { toolCallId, result } = chunk;
881
- message = setToolResult(message, toolCallId, result);
882
- controller.enqueue(message);
883
- break;
884
- }
885
- case "error": {
886
- const { error } = chunk;
887
- message = setError(message, error);
888
- controller.enqueue(message);
889
- break;
890
- }
891
- default: {
892
- const _exhaustiveCheck = type;
893
- throw new Error(`Unsupported chunk type: ${_exhaustiveCheck}`);
894
- }
490
+ };
491
+ var handlePartStart = (message, chunk) => {
492
+ const partInit = chunk.part;
493
+ if (partInit.type === "text" || partInit.type === "reasoning") {
494
+ const newTextPart = {
495
+ type: partInit.type,
496
+ text: "",
497
+ status: { type: "running" }
498
+ };
499
+ return {
500
+ ...message,
501
+ parts: [...message.parts, newTextPart],
502
+ get content() {
503
+ return this.parts;
895
504
  }
896
- },
897
- flush(controller) {
898
- message = appendOrUpdateFinish(message);
899
- controller.enqueue(message);
505
+ };
506
+ } else if (partInit.type === "tool-call") {
507
+ const newToolCallPart = {
508
+ type: "tool-call",
509
+ state: "partial-call",
510
+ status: { type: "running", isArgsComplete: false },
511
+ toolCallId: partInit.toolCallId,
512
+ toolName: partInit.toolName,
513
+ argsText: "",
514
+ args: {}
515
+ };
516
+ return {
517
+ ...message,
518
+ parts: [...message.parts, newToolCallPart],
519
+ get content() {
520
+ return this.parts;
521
+ }
522
+ };
523
+ } else if (partInit.type === "source") {
524
+ const newSourcePart = {
525
+ type: "source",
526
+ sourceType: partInit.sourceType,
527
+ id: partInit.id,
528
+ url: partInit.url,
529
+ ...partInit.title ? { title: partInit.title } : void 0
530
+ };
531
+ return {
532
+ ...message,
533
+ parts: [...message.parts, newSourcePart],
534
+ get content() {
535
+ return this.parts;
536
+ }
537
+ };
538
+ } else if (partInit.type === "file") {
539
+ const newFilePart = {
540
+ type: "file",
541
+ mimeType: partInit.mimeType,
542
+ data: partInit.data
543
+ };
544
+ return {
545
+ ...message,
546
+ parts: [...message.parts, newFilePart],
547
+ get content() {
548
+ return this.parts;
549
+ }
550
+ };
551
+ } else {
552
+ throw new Error(`Unsupported part type: ${partInit.type}`);
553
+ }
554
+ };
555
+ var handleToolCallArgsTextFinish = (message, chunk) => {
556
+ return updatePartForPath(message, chunk, (lastPart) => {
557
+ if (lastPart.type !== "tool-call") {
558
+ throw new Error("Last part is not a tool call");
900
559
  }
560
+ return {
561
+ ...lastPart,
562
+ state: "call"
563
+ };
901
564
  });
902
- return transformer;
903
565
  };
904
- var appendOrUpdateText = (message, textDelta) => {
905
- let contentParts = message.content ?? [];
906
- let contentPart = message.content?.at(-1);
907
- if (contentPart?.type !== "text") {
908
- contentPart = {
909
- type: "text",
910
- text: textDelta,
911
- status: { type: "running" }
566
+ var handlePartFinish = (message, chunk) => {
567
+ return updatePartForPath(message, chunk, (lastPart) => ({
568
+ ...lastPart,
569
+ status: { type: "complete", reason: "unknown" }
570
+ }));
571
+ };
572
+ var handleTextDelta = (message, chunk) => {
573
+ return updatePartForPath(message, chunk, (lastPart) => {
574
+ if (lastPart.type === "text") {
575
+ return { ...lastPart, text: lastPart.text + chunk.textDelta };
576
+ } else if (lastPart.type === "tool-call") {
577
+ const newArgsText = lastPart.argsText + chunk.textDelta;
578
+ let newArgs;
579
+ try {
580
+ newArgs = parsePartialJson(newArgsText);
581
+ } catch (err) {
582
+ newArgs = lastPart.args;
583
+ }
584
+ return { ...lastPart, argsText: newArgsText, args: newArgs };
585
+ } else {
586
+ throw new Error(
587
+ "text-delta received but last part is neither text nor tool-call"
588
+ );
589
+ }
590
+ });
591
+ };
592
+ var handleResult = (message, chunk) => {
593
+ return updatePartForPath(message, chunk, (lastPart) => {
594
+ if (lastPart.type === "tool-call") {
595
+ return {
596
+ ...lastPart,
597
+ state: "result",
598
+ result: chunk.result,
599
+ isError: chunk.isError ?? false,
600
+ status: { type: "complete", reason: "stop" }
601
+ };
602
+ } else {
603
+ throw new Error("Result chunk received but last part is not a tool-call");
604
+ }
605
+ });
606
+ };
607
+ var handleMessageFinish = (message, chunk) => {
608
+ const newStatus = getStatus(chunk);
609
+ return { ...message, status: newStatus };
610
+ };
611
+ var getStatus = (chunk) => {
612
+ if (chunk.finishReason === "tool-calls") {
613
+ return {
614
+ type: "requires-action",
615
+ reason: "tool-calls"
616
+ };
617
+ } else if (chunk.finishReason === "stop" || chunk.finishReason === "unknown") {
618
+ return {
619
+ type: "complete",
620
+ reason: chunk.finishReason
912
621
  };
913
622
  } else {
914
- contentParts = contentParts.slice(0, -1);
915
- contentPart = {
916
- type: "text",
917
- text: contentPart.text + textDelta,
918
- status: { type: "running" }
623
+ return {
624
+ type: "incomplete",
625
+ reason: chunk.finishReason
919
626
  };
920
627
  }
921
- return {
922
- ...message,
923
- content: contentParts.concat([contentPart])
924
- };
925
628
  };
926
- var appendToolCall = (message, toolCallId, toolName) => {
629
+ var handleAnnotations = (message, chunk) => {
927
630
  return {
928
631
  ...message,
929
- content: [
930
- ...message.content,
931
- {
932
- type: "tool-call",
933
- toolCallId,
934
- toolName,
935
- argsText: "",
936
- args: {},
937
- status: { type: "running", isArgsComplete: false }
938
- }
939
- ]
632
+ metadata: {
633
+ ...message.metadata,
634
+ unstable_annotations: [
635
+ ...message.metadata.unstable_annotations,
636
+ ...chunk.annotations
637
+ ]
638
+ }
940
639
  };
941
640
  };
942
- var appendToolArgsTextDelta = (message, toolCallId, argsTextDelta) => {
943
- const contentPartIdx = message.content.findIndex(
944
- (part) => part.type === "tool-call" && part.toolCallId === toolCallId
945
- );
946
- if (contentPartIdx === -1)
947
- throw new Error(
948
- `Received tool call delta for unknown tool call "${toolCallId}".`
949
- );
950
- const contentPart = message.content[contentPartIdx];
951
- const newArgsText = contentPart.argsText + argsTextDelta;
641
+ var handleData = (message, chunk) => {
952
642
  return {
953
643
  ...message,
954
- content: [
955
- ...message.content.slice(0, contentPartIdx),
956
- {
957
- ...contentPart,
958
- argsText: newArgsText,
959
- args: parsePartialJson(newArgsText)
960
- },
961
- ...message.content.slice(contentPartIdx + 1)
962
- ]
644
+ metadata: {
645
+ ...message.metadata,
646
+ unstable_data: [...message.metadata.unstable_data, ...chunk.data]
647
+ }
963
648
  };
964
649
  };
965
- var setToolResult = (message, toolCallId, result) => {
966
- let found = false;
967
- const newContentParts = message.content?.map((part) => {
968
- if (part.type !== "tool-call" || part.toolCallId !== toolCallId)
969
- return part;
970
- found = true;
971
- return {
972
- ...part,
973
- result
974
- };
975
- });
976
- if (!found)
977
- throw new Error(
978
- `Received tool result for unknown tool call "${toolCallId}". This is likely an internal bug in assistant-ui.`
979
- );
650
+ var handleStepStart = (message, chunk) => {
980
651
  return {
981
652
  ...message,
982
- content: newContentParts
653
+ metadata: {
654
+ ...message.metadata,
655
+ steps: [
656
+ ...message.metadata.steps,
657
+ { state: "started", messageId: chunk.messageId }
658
+ ]
659
+ }
983
660
  };
984
661
  };
985
- var appendOrUpdateFinish = (message) => {
662
+ var handleStepFinish = (message, chunk) => {
663
+ const steps = message.metadata.steps.slice();
664
+ const lastIndex = steps.length - 1;
665
+ if (steps.length > 0 && steps[lastIndex]?.state === "started") {
666
+ steps[lastIndex] = {
667
+ ...steps[lastIndex],
668
+ state: "finished",
669
+ finishReason: chunk.finishReason,
670
+ usage: chunk.usage,
671
+ isContinued: chunk.isContinued
672
+ };
673
+ } else {
674
+ steps.push({
675
+ state: "finished",
676
+ messageId: generateId(),
677
+ finishReason: chunk.finishReason,
678
+ usage: chunk.usage,
679
+ isContinued: chunk.isContinued
680
+ });
681
+ }
986
682
  return {
987
683
  ...message,
988
- status: {
989
- type: "complete",
990
- reason: "unknown"
684
+ metadata: {
685
+ ...message.metadata,
686
+ steps
991
687
  }
992
688
  };
993
689
  };
994
- var setError = (message, error) => {
690
+ var handleErrorChunk = (message, chunk) => {
995
691
  return {
996
692
  ...message,
997
- status: {
998
- type: "incomplete",
999
- reason: "error",
1000
- error
1001
- }
693
+ status: { type: "incomplete", reason: "error", error: chunk.error }
1002
694
  };
1003
695
  };
696
+ var AssistantMessageAccumulator = class extends TransformStream {
697
+ constructor() {
698
+ let message = createInitialMessage();
699
+ let hadChunks = false;
700
+ super({
701
+ transform(chunk, controller) {
702
+ const type = chunk.type;
703
+ switch (type) {
704
+ case "part-start":
705
+ message = handlePartStart(message, chunk);
706
+ break;
707
+ case "tool-call-args-text-finish":
708
+ message = handleToolCallArgsTextFinish(message, chunk);
709
+ break;
710
+ case "part-finish":
711
+ message = handlePartFinish(message, chunk);
712
+ break;
713
+ case "text-delta":
714
+ message = handleTextDelta(message, chunk);
715
+ break;
716
+ case "result":
717
+ message = handleResult(message, chunk);
718
+ break;
719
+ case "message-finish":
720
+ message = handleMessageFinish(message, chunk);
721
+ break;
722
+ case "annotations":
723
+ message = handleAnnotations(message, chunk);
724
+ break;
725
+ case "data":
726
+ message = handleData(message, chunk);
727
+ break;
728
+ case "step-start":
729
+ message = handleStepStart(message, chunk);
730
+ break;
731
+ case "step-finish":
732
+ message = handleStepFinish(message, chunk);
733
+ break;
734
+ case "error":
735
+ message = handleErrorChunk(message, chunk);
736
+ break;
737
+ default: {
738
+ const unhandledType = type;
739
+ throw new Error(`Unsupported chunk type: ${unhandledType}`);
740
+ }
741
+ }
742
+ controller.enqueue(message);
743
+ hadChunks = true;
744
+ },
745
+ flush(controller) {
746
+ if (!hadChunks) {
747
+ controller.enqueue(message);
748
+ }
749
+ }
750
+ });
751
+ }
752
+ };
753
+
754
+ // src/core/serialization/PlainText.ts
755
+ var PlainTextEncoder = class extends PipeableTransformStream {
756
+ headers = new Headers({
757
+ "Content-Type": "text/plain; charset=utf-8",
758
+ "x-vercel-ai-data-stream": "v1"
759
+ });
760
+ constructor() {
761
+ super((readable) => {
762
+ const transform = new TransformStream({
763
+ transform(chunk, controller) {
764
+ const type = chunk.type;
765
+ switch (type) {
766
+ case "text-delta":
767
+ controller.enqueue(chunk.textDelta);
768
+ break;
769
+ default:
770
+ const unsupportedType = type;
771
+ throw new Error(`unsupported chunk type: ${unsupportedType}`);
772
+ }
773
+ }
774
+ });
775
+ return readable.pipeThrough(transform).pipeThrough(new TextEncoderStream());
776
+ });
777
+ }
778
+ };
779
+ var PlainTextDecoder = class extends PipeableTransformStream {
780
+ constructor() {
781
+ super((readable) => {
782
+ const transform = new AssistantTransformStream({
783
+ transform(chunk, controller) {
784
+ controller.appendText(chunk);
785
+ }
786
+ });
787
+ return readable.pipeThrough(new TextDecoderStream()).pipeThrough(transform);
788
+ });
789
+ }
790
+ };
1004
791
 
1005
792
  // src/core/accumulators/AssistantMessageStream.ts
1006
793
  var AssistantMessageStream = class _AssistantMessageStream {
@@ -1010,7 +797,7 @@ var AssistantMessageStream = class _AssistantMessageStream {
1010
797
  }
1011
798
  static fromAssistantStream(stream) {
1012
799
  return new _AssistantMessageStream(
1013
- stream.pipeThrough(assistantMessageAccumulator())
800
+ stream.pipeThrough(new AssistantMessageAccumulator())
1014
801
  );
1015
802
  }
1016
803
  async unstable_result() {
@@ -1022,8 +809,11 @@ var AssistantMessageStream = class _AssistantMessageStream {
1022
809
  return {
1023
810
  role: "assistant",
1024
811
  status: { type: "complete", reason: "unknown" },
812
+ parts: [],
1025
813
  content: [],
1026
814
  metadata: {
815
+ unstable_data: [],
816
+ unstable_annotations: [],
1027
817
  steps: [],
1028
818
  custom: {}
1029
819
  }
@@ -1049,12 +839,14 @@ var AssistantMessageStream = class _AssistantMessageStream {
1049
839
  }
1050
840
  };
1051
841
  export {
842
+ AssistantMessageAccumulator,
1052
843
  AssistantMessageStream,
1053
844
  AssistantStream,
1054
845
  DataStreamDecoder,
1055
846
  DataStreamEncoder,
1056
847
  PlainTextDecoder,
1057
848
  PlainTextEncoder,
849
+ ToolExecutionStream,
1058
850
  createAssistantStream,
1059
851
  createAssistantStreamResponse
1060
852
  };