assistant-stream 0.0.21 → 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.js CHANGED
@@ -30,12 +30,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ AssistantMessageAccumulator: () => AssistantMessageAccumulator,
33
34
  AssistantMessageStream: () => AssistantMessageStream,
34
35
  AssistantStream: () => AssistantStream,
35
36
  DataStreamDecoder: () => DataStreamDecoder,
36
37
  DataStreamEncoder: () => DataStreamEncoder,
37
38
  PlainTextDecoder: () => PlainTextDecoder,
38
39
  PlainTextEncoder: () => PlainTextEncoder,
40
+ ToolExecutionStream: () => ToolExecutionStream,
39
41
  createAssistantStream: () => createAssistantStream,
40
42
  createAssistantStreamResponse: () => createAssistantStreamResponse
41
43
  });
@@ -44,7 +46,9 @@ module.exports = __toCommonJS(index_exports);
44
46
  // src/core/AssistantStream.ts
45
47
  var AssistantStream = {
46
48
  toResponse(stream, transformer) {
47
- return new Response(AssistantStream.toByteStream(stream, transformer));
49
+ return new Response(AssistantStream.toByteStream(stream, transformer), {
50
+ headers: transformer.headers ?? {}
51
+ });
48
52
  },
49
53
  fromResponse(response, transformer) {
50
54
  return AssistantStream.fromByteStream(response.body, transformer);
@@ -57,202 +61,118 @@ var AssistantStream = {
57
61
  }
58
62
  };
59
63
 
60
- // src/core/utils/PipeableTransformStream.ts
61
- var PipeableTransformStream = class extends TransformStream {
62
- constructor(transform) {
63
- super();
64
- const readable = transform(super.readable);
65
- Object.defineProperty(this, "readable", {
66
- value: readable,
67
- writable: false
68
- });
69
- }
64
+ // src/core/utils/stream/merge.ts
65
+ var promiseWithResolvers = () => {
66
+ let resolve;
67
+ let reject;
68
+ const promise = new Promise((res, rej) => {
69
+ resolve = res;
70
+ reject = rej;
71
+ });
72
+ return { promise, resolve, reject };
70
73
  };
71
-
72
- // src/core/serialization/DataStream.ts
73
- var DataStreamEncoder = class {
74
- _transformStream;
75
- get writable() {
76
- return this._transformStream.writable;
77
- }
78
- get readable() {
79
- return this._transformStream.readable;
80
- }
81
- constructor() {
82
- this._transformStream = new PipeableTransformStream((readable) => {
83
- const transform = new TransformStream({
84
- transform(chunk, controller) {
85
- const type = chunk.type;
86
- switch (type) {
87
- case "text-delta":
88
- controller.enqueue("0:" + JSON.stringify(chunk.textDelta) + "\n");
89
- break;
90
- case "tool-call-begin":
91
- controller.enqueue(
92
- "b:" + JSON.stringify({
93
- toolCallId: chunk.toolCallId,
94
- toolName: chunk.toolName
95
- }) + "\n"
96
- );
97
- break;
98
- case "tool-call-delta":
99
- controller.enqueue(
100
- "c:" + JSON.stringify({
101
- toolCallId: chunk.toolCallId,
102
- argsTextDelta: chunk.argsTextDelta
103
- }) + "\n"
104
- );
105
- break;
106
- case "tool-result":
107
- controller.enqueue(
108
- "a:" + JSON.stringify({
109
- toolCallId: chunk.toolCallId,
110
- result: chunk.result
111
- }) + "\n"
112
- );
113
- break;
114
- case "error":
115
- controller.enqueue(`3:${JSON.stringify(chunk.error)}
116
- `);
117
- break;
118
- default:
119
- const exhaustiveCheck = type;
120
- throw new Error(`unsupported chunk type: ${exhaustiveCheck}`);
74
+ var createMergeStream = () => {
75
+ const list = [];
76
+ let sealed = false;
77
+ let controller;
78
+ let currentPull;
79
+ const handlePull = (item) => {
80
+ if (!item.promise) {
81
+ item.promise = item.reader.read().then(({ done, value }) => {
82
+ item.promise = void 0;
83
+ if (done) {
84
+ list.splice(list.indexOf(item), 1);
85
+ if (sealed && list.length === 0) {
86
+ controller.close();
121
87
  }
88
+ } else {
89
+ controller.enqueue(value);
122
90
  }
91
+ currentPull?.resolve();
92
+ currentPull = void 0;
93
+ }).catch((e) => {
94
+ console.error(e);
95
+ list.forEach((item2) => {
96
+ item2.reader.cancel();
97
+ });
98
+ list.length = 0;
99
+ controller.error(e);
100
+ currentPull?.reject(e);
101
+ currentPull = void 0;
123
102
  });
124
- return readable.pipeThrough(transform).pipeThrough(new TextEncoderStream());
125
- });
126
- }
127
- };
128
- var decodeStreamPart = (part) => {
129
- const index = part.indexOf(":");
130
- if (index === -1) throw new Error("Invalid stream part");
131
- return {
132
- type: part.slice(0, index),
133
- value: JSON.parse(part.slice(index + 1))
103
+ }
134
104
  };
135
- };
136
- var DataStreamDecoder = class {
137
- _transformStream;
138
- get writable() {
139
- return this._transformStream.writable;
140
- }
141
- get readable() {
142
- return this._transformStream.readable;
143
- }
144
- constructor() {
145
- this._transformStream = new PipeableTransformStream((readable) => {
146
- const transform = new TransformStream({
147
- transform(chunk, controller) {
148
- const { type, value } = decodeStreamPart(chunk);
149
- switch (type) {
150
- case "0":
151
- controller.enqueue({
152
- type: "text-delta",
153
- textDelta: value
154
- });
155
- break;
156
- case "b": {
157
- const { toolCallId, toolName } = value;
158
- controller.enqueue({
159
- type: "tool-call-begin",
160
- toolCallId,
161
- toolName
162
- });
163
- break;
164
- }
165
- case "c": {
166
- const { toolCallId, argsTextDelta } = value;
167
- controller.enqueue({
168
- type: "tool-call-delta",
169
- toolCallId,
170
- argsTextDelta
171
- });
172
- break;
173
- }
174
- case "a": {
175
- const { toolCallId, result } = value;
176
- controller.enqueue({
177
- type: "tool-result",
178
- toolCallId,
179
- result
180
- });
181
- break;
182
- }
183
- case "9": {
184
- const { toolCallId, args } = value;
185
- controller.enqueue({
186
- type: "tool-call-begin",
187
- toolCallId,
188
- toolName: toolCallId
189
- });
190
- controller.enqueue({
191
- type: "tool-call-delta",
192
- toolCallId,
193
- argsTextDelta: JSON.stringify(args)
194
- });
195
- break;
196
- }
197
- case "2":
198
- case "3":
199
- case "8":
200
- case "d":
201
- case "e": {
202
- break;
203
- }
204
- default:
205
- const exhaustiveCheck = type;
206
- throw new Error(`unsupported chunk type: ${exhaustiveCheck}`);
207
- }
208
- }
105
+ const readable = new ReadableStream({
106
+ start(c) {
107
+ controller = c;
108
+ },
109
+ pull() {
110
+ currentPull = promiseWithResolvers();
111
+ list.forEach((item) => {
112
+ handlePull(item);
209
113
  });
210
- return readable.pipeThrough(new TextDecoderStream()).pipeThrough(new ChunkByLineStream()).pipeThrough(transform);
211
- });
212
- }
213
- };
214
- var ChunkByLineStream = class extends TransformStream {
215
- buffer = "";
216
- constructor() {
217
- super({
218
- transform: (chunk, controller) => {
219
- this.buffer += chunk;
220
- const lines = this.buffer.split("\n");
221
- for (let i = 0; i < lines.length - 1; i++) {
222
- controller.enqueue(lines[i]);
223
- }
224
- this.buffer = lines[lines.length - 1];
225
- },
226
- flush: (controller) => {
227
- if (this.buffer) {
228
- controller.enqueue(this.buffer);
229
- }
230
- }
231
- });
232
- }
114
+ return currentPull.promise;
115
+ },
116
+ cancel() {
117
+ list.forEach((item) => {
118
+ item.reader.cancel();
119
+ });
120
+ list.length = 0;
121
+ }
122
+ });
123
+ return {
124
+ readable,
125
+ isSealed() {
126
+ return sealed;
127
+ },
128
+ seal() {
129
+ sealed = true;
130
+ if (list.length === 0) controller.close();
131
+ },
132
+ addStream(stream) {
133
+ if (sealed)
134
+ throw new Error(
135
+ "Cannot add streams after the run callback has settled."
136
+ );
137
+ const item = { reader: stream.getReader() };
138
+ list.push(item);
139
+ handlePull(item);
140
+ },
141
+ enqueue(chunk) {
142
+ this.addStream(
143
+ new ReadableStream({
144
+ start(c) {
145
+ c.enqueue(chunk);
146
+ c.close();
147
+ }
148
+ })
149
+ );
150
+ }
151
+ };
233
152
  };
234
153
 
235
- // src/core/utils/generateId.tsx
236
- var import_non_secure = require("nanoid/non-secure");
237
- var generateId = (0, import_non_secure.customAlphabet)(
238
- "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
239
- 7
240
- );
241
-
242
154
  // src/core/modules/text.ts
243
155
  var TextStreamControllerImpl = class {
244
156
  _controller;
157
+ _isClosed = false;
245
158
  constructor(controller) {
246
159
  this._controller = controller;
247
160
  }
248
161
  append(textDelta) {
249
162
  this._controller.enqueue({
250
163
  type: "text-delta",
164
+ path: [],
251
165
  textDelta
252
166
  });
253
167
  return this;
254
168
  }
255
169
  close() {
170
+ if (this._isClosed) return;
171
+ this._isClosed = true;
172
+ this._controller.enqueue({
173
+ type: "part-finish",
174
+ path: []
175
+ });
256
176
  this._controller.close();
257
177
  }
258
178
  };
@@ -269,17 +189,20 @@ var createTextStream = (readable) => {
269
189
  }
270
190
  });
271
191
  };
192
+ var createTextStreamController = () => {
193
+ let controller;
194
+ const stream = createTextStream({
195
+ start(c) {
196
+ controller = c;
197
+ }
198
+ });
199
+ return [stream, controller];
200
+ };
272
201
 
273
202
  // src/core/modules/tool-call.ts
274
203
  var ToolCallStreamControllerImpl = class {
275
- constructor(_controller, _options) {
204
+ constructor(_controller) {
276
205
  this._controller = _controller;
277
- this._options = _options;
278
- this._controller.enqueue({
279
- type: "tool-call-begin",
280
- toolCallId: this._options.toolCallId,
281
- toolName: this._options.toolName
282
- });
283
206
  const stream = createTextStream({
284
207
  start: (c) => {
285
208
  this._argsTextController = c;
@@ -288,215 +211,750 @@ var ToolCallStreamControllerImpl = class {
288
211
  stream.pipeTo(
289
212
  new WritableStream({
290
213
  write: (chunk) => {
291
- if (chunk.type !== "text-delta")
292
- throw new Error("Unexpected chunk type");
293
- this._controller.enqueue({
294
- type: "tool-call-delta",
295
- toolCallId: this._options.toolCallId,
296
- argsTextDelta: chunk.textDelta
297
- });
214
+ switch (chunk.type) {
215
+ case "text-delta":
216
+ this._controller.enqueue(chunk);
217
+ break;
218
+ case "part-finish":
219
+ this._controller.enqueue({
220
+ type: "tool-call-args-text-finish",
221
+ path: []
222
+ });
223
+ break;
224
+ default:
225
+ throw new Error(`Unexpected chunk type: ${chunk.type}`);
226
+ }
298
227
  }
299
228
  })
300
229
  );
301
230
  }
302
- get toolCallId() {
303
- return this._options.toolCallId;
304
- }
305
- get toolName() {
306
- return this._options.toolName;
307
- }
231
+ _isClosed = false;
308
232
  get argsText() {
309
233
  return this._argsTextController;
310
234
  }
311
235
  _argsTextController;
312
- setResult(result) {
236
+ setResult(result, isError) {
313
237
  this._controller.enqueue({
314
- type: "tool-result",
315
- toolCallId: this._options.toolCallId,
316
- result
238
+ type: "result",
239
+ path: [],
240
+ result,
241
+ isError: isError ?? false
317
242
  });
318
243
  }
319
244
  close() {
245
+ if (this._isClosed) return;
246
+ this._isClosed = true;
247
+ this._argsTextController.close();
248
+ this._controller.enqueue({
249
+ type: "part-finish",
250
+ path: []
251
+ });
320
252
  this._controller.close();
321
253
  }
322
254
  };
323
255
  var createToolCallStream = (readable) => {
324
- const options = {
325
- toolCallId: readable.toolCallId,
326
- toolName: readable.toolName
327
- };
328
256
  return new ReadableStream({
329
257
  start(c) {
330
- return readable.start?.(new ToolCallStreamControllerImpl(c, options));
258
+ return readable.start?.(new ToolCallStreamControllerImpl(c));
331
259
  },
332
260
  pull(c) {
333
- return readable.pull?.(new ToolCallStreamControllerImpl(c, options));
261
+ return readable.pull?.(new ToolCallStreamControllerImpl(c));
334
262
  },
335
263
  cancel(c) {
336
264
  return readable.cancel?.(c);
337
265
  }
338
266
  });
339
267
  };
340
-
341
- // src/core/modules/runs.ts
342
- var promiseWithResolvers = () => {
343
- let resolve;
344
- let reject;
345
- const promise = new Promise((res, rej) => {
346
- resolve = res;
347
- reject = rej;
348
- });
349
- return { promise, resolve, reject };
350
- };
351
- var createMergeStream = () => {
352
- const list = [];
353
- let sealed = false;
268
+ var createToolCallStreamController = () => {
354
269
  let controller;
355
- let currentPull;
356
- const handlePull = (item) => {
357
- if (!item.promise) {
358
- item.promise = item.reader.read().then(({ done, value }) => {
359
- item.promise = void 0;
360
- if (done) {
361
- list.splice(list.indexOf(item), 1);
362
- if (sealed && list.length === 0) {
363
- controller.close();
364
- }
365
- } else {
366
- controller.enqueue(value);
367
- }
368
- currentPull?.resolve();
369
- currentPull = void 0;
370
- }).catch((e) => {
371
- list.forEach((item2) => {
372
- item2.reader.cancel();
373
- });
374
- list.length = 0;
375
- controller.error(e);
376
- currentPull?.reject(e);
377
- currentPull = void 0;
378
- });
379
- }
380
- };
381
- const readable = new ReadableStream({
270
+ const stream = createToolCallStream({
382
271
  start(c) {
383
272
  controller = c;
384
- },
385
- async pull() {
386
- list.map((item) => {
387
- handlePull(item);
388
- return item.promise;
389
- });
390
- currentPull = promiseWithResolvers();
391
- return currentPull.promise;
392
- },
393
- cancel() {
394
- list.forEach((item) => {
395
- item.reader.cancel();
396
- });
397
- list.length = 0;
398
273
  }
399
274
  });
400
- return {
401
- stream: readable,
402
- seal() {
403
- sealed = true;
404
- if (list.length === 0) controller.close();
405
- },
406
- addStream(stream) {
407
- if (sealed)
408
- throw new Error(
409
- "Cannot add streams after the run callback has settled."
410
- );
411
- const item = { reader: stream.getReader() };
412
- list.push(item);
413
- if (list.length === 1) {
414
- handlePull(item);
275
+ return [stream, controller];
276
+ };
277
+
278
+ // src/core/utils/Counter.ts
279
+ var Counter = class {
280
+ value = -1;
281
+ up() {
282
+ return ++this.value;
283
+ }
284
+ };
285
+
286
+ // src/core/utils/stream/path-utils.ts
287
+ var PathAppendEncoder = class extends TransformStream {
288
+ constructor(idx) {
289
+ super({
290
+ transform(chunk, controller) {
291
+ controller.enqueue({
292
+ ...chunk,
293
+ path: [idx, ...chunk.path]
294
+ });
415
295
  }
416
- }
417
- };
296
+ });
297
+ }
298
+ };
299
+ var PathAppendDecoder = class extends TransformStream {
300
+ constructor(idx) {
301
+ super({
302
+ transform(chunk, controller) {
303
+ const {
304
+ path: [idx2, ...path]
305
+ } = chunk;
306
+ if (idx !== idx2)
307
+ throw new Error(`Path mismatch: expected ${idx}, got ${idx2}`);
308
+ controller.enqueue({
309
+ ...chunk,
310
+ path
311
+ });
312
+ }
313
+ });
314
+ }
315
+ };
316
+ var PathMergeEncoder = class extends TransformStream {
317
+ constructor(counter) {
318
+ const innerCounter = new Counter();
319
+ const mapping = /* @__PURE__ */ new Map();
320
+ super({
321
+ transform(chunk, controller) {
322
+ if (chunk.type === "part-start" && chunk.path.length === 0) {
323
+ mapping.set(innerCounter.up(), counter.up());
324
+ }
325
+ const [idx, ...path] = chunk.path;
326
+ if (idx === void 0) {
327
+ controller.enqueue(chunk);
328
+ return;
329
+ }
330
+ const mappedIdx = mapping.get(idx);
331
+ if (mappedIdx === void 0) throw new Error("Path not found");
332
+ controller.enqueue({
333
+ ...chunk,
334
+ path: [mappedIdx, ...path]
335
+ });
336
+ }
337
+ });
338
+ }
339
+ };
340
+
341
+ // src/core/utils/stream/AssistantTransformStream.ts
342
+ var AssistantTransformStream = class extends TransformStream {
343
+ constructor(transformer, writableStrategy, readableStrategy) {
344
+ const [stream, runController] = createAssistantStreamController();
345
+ let runPipeTask;
346
+ super(
347
+ {
348
+ start(controller) {
349
+ runPipeTask = stream.pipeTo(
350
+ new WritableStream({
351
+ write(chunk) {
352
+ controller.enqueue(chunk);
353
+ },
354
+ abort(reason) {
355
+ controller.error(reason);
356
+ },
357
+ close() {
358
+ controller.terminate();
359
+ }
360
+ })
361
+ ).catch((error) => {
362
+ controller.error(error);
363
+ });
364
+ return transformer.start?.(runController);
365
+ },
366
+ transform(chunk) {
367
+ return transformer.transform?.(chunk, runController);
368
+ },
369
+ async flush() {
370
+ await transformer.flush?.(runController);
371
+ runController.close();
372
+ await runPipeTask;
373
+ }
374
+ },
375
+ writableStrategy,
376
+ readableStrategy
377
+ );
378
+ }
379
+ };
380
+
381
+ // src/core/utils/stream/PipeableTransformStream.ts
382
+ var PipeableTransformStream = class extends TransformStream {
383
+ constructor(transform) {
384
+ super();
385
+ const readable = transform(super.readable);
386
+ Object.defineProperty(this, "readable", {
387
+ value: readable,
388
+ writable: false
389
+ });
390
+ }
391
+ };
392
+
393
+ // src/core/utils/stream/LineDecoderStream.ts
394
+ var LineDecoderStream = class extends TransformStream {
395
+ buffer = "";
396
+ constructor() {
397
+ super({
398
+ transform: (chunk, controller) => {
399
+ this.buffer += chunk;
400
+ const lines = this.buffer.split("\n");
401
+ for (let i = 0; i < lines.length - 1; i++) {
402
+ controller.enqueue(lines[i]);
403
+ }
404
+ this.buffer = lines[lines.length - 1] || "";
405
+ },
406
+ flush: (controller) => {
407
+ if (this.buffer) {
408
+ controller.enqueue(this.buffer);
409
+ }
410
+ }
411
+ });
412
+ }
413
+ };
414
+
415
+ // src/core/serialization/data-stream/serialization.ts
416
+ var DataStreamChunkEncoder = class extends TransformStream {
417
+ constructor() {
418
+ super({
419
+ transform: (chunk, controller) => {
420
+ controller.enqueue(`${chunk.type}:${JSON.stringify(chunk.value)}
421
+ `);
422
+ }
423
+ });
424
+ }
425
+ };
426
+ var DataStreamChunkDecoder = class extends TransformStream {
427
+ constructor() {
428
+ super({
429
+ transform: (chunk, controller) => {
430
+ const index = chunk.indexOf(":");
431
+ if (index === -1) throw new Error("Invalid stream part");
432
+ controller.enqueue({
433
+ type: chunk.slice(0, index),
434
+ value: JSON.parse(chunk.slice(index + 1))
435
+ });
436
+ }
437
+ });
438
+ }
439
+ };
440
+
441
+ // src/core/utils/stream/AssistantMetaTransformStream.ts
442
+ var AssistantMetaTransformStream = class extends TransformStream {
443
+ constructor() {
444
+ const parts = [];
445
+ super({
446
+ transform(chunk, controller) {
447
+ if (chunk.type === "part-start") {
448
+ if (chunk.path.length !== 0) {
449
+ controller.error(new Error("Nested parts are not supported"));
450
+ return;
451
+ }
452
+ parts.push(chunk.part);
453
+ controller.enqueue(chunk);
454
+ return;
455
+ }
456
+ if (chunk.type === "text-delta" || chunk.type === "result" || chunk.type === "part-finish" || chunk.type === "tool-call-args-text-finish") {
457
+ if (chunk.path.length !== 1) {
458
+ controller.error(
459
+ new Error(`${chunk.type} chunks must have a path of length 1`)
460
+ );
461
+ return;
462
+ }
463
+ const idx = chunk.path[0];
464
+ if (idx < 0 || idx >= parts.length) {
465
+ controller.error(new Error(`Invalid path index: ${idx}`));
466
+ return;
467
+ }
468
+ const part = parts[idx];
469
+ controller.enqueue({
470
+ ...chunk,
471
+ meta: part
472
+ // TODO
473
+ });
474
+ return;
475
+ }
476
+ controller.enqueue(chunk);
477
+ }
478
+ });
479
+ }
480
+ };
481
+
482
+ // src/core/serialization/data-stream/DataStream.ts
483
+ var DataStreamEncoder = class extends PipeableTransformStream {
484
+ headers = new Headers({
485
+ "Content-Type": "text/plain; charset=utf-8",
486
+ "x-vercel-ai-data-stream": "v1"
487
+ });
488
+ constructor() {
489
+ super((readable) => {
490
+ const transform = new TransformStream({
491
+ transform(chunk, controller) {
492
+ const type = chunk.type;
493
+ switch (type) {
494
+ case "part-start": {
495
+ const part = chunk.part;
496
+ if (part.type === "tool-call") {
497
+ const { type: type2, ...value } = part;
498
+ controller.enqueue({
499
+ type: "b" /* StartToolCall */,
500
+ value
501
+ });
502
+ }
503
+ if (part.type === "source") {
504
+ const { type: type2, ...value } = part;
505
+ controller.enqueue({
506
+ type: "h" /* Source */,
507
+ value
508
+ });
509
+ }
510
+ break;
511
+ }
512
+ case "text-delta": {
513
+ const part = chunk.meta;
514
+ switch (part.type) {
515
+ case "text": {
516
+ controller.enqueue({
517
+ type: "0" /* TextDelta */,
518
+ value: chunk.textDelta
519
+ });
520
+ break;
521
+ }
522
+ case "reasoning": {
523
+ controller.enqueue({
524
+ type: "g" /* ReasoningDelta */,
525
+ value: chunk.textDelta
526
+ });
527
+ break;
528
+ }
529
+ case "tool-call": {
530
+ controller.enqueue({
531
+ type: "c" /* ToolCallDelta */,
532
+ value: {
533
+ toolCallId: part.toolCallId,
534
+ argsTextDelta: chunk.textDelta
535
+ }
536
+ });
537
+ break;
538
+ }
539
+ default:
540
+ throw new Error(
541
+ `Unsupported part type for text-delta: ${part.type}`
542
+ );
543
+ }
544
+ break;
545
+ }
546
+ case "result": {
547
+ const part = chunk.meta;
548
+ if (part.type !== "tool-call") {
549
+ throw new Error(
550
+ `Result chunk on non-tool-call part not supported: ${part.type}`
551
+ );
552
+ }
553
+ controller.enqueue({
554
+ type: "a" /* ToolCallResult */,
555
+ value: {
556
+ toolCallId: part.toolCallId,
557
+ result: chunk.result
558
+ }
559
+ });
560
+ break;
561
+ }
562
+ case "step-start": {
563
+ const { type: type2, ...value } = chunk;
564
+ controller.enqueue({
565
+ type: "f" /* StartStep */,
566
+ value
567
+ });
568
+ break;
569
+ }
570
+ case "step-finish": {
571
+ const { type: type2, ...value } = chunk;
572
+ controller.enqueue({
573
+ type: "e" /* FinishStep */,
574
+ value
575
+ });
576
+ break;
577
+ }
578
+ case "message-finish": {
579
+ const { type: type2, ...value } = chunk;
580
+ controller.enqueue({
581
+ type: "d" /* FinishMessage */,
582
+ value
583
+ });
584
+ break;
585
+ }
586
+ case "error": {
587
+ controller.enqueue({
588
+ type: "3" /* Error */,
589
+ value: chunk.error
590
+ });
591
+ break;
592
+ }
593
+ case "annotations": {
594
+ controller.enqueue({
595
+ type: "8" /* Annotation */,
596
+ value: chunk.annotations
597
+ });
598
+ break;
599
+ }
600
+ case "data": {
601
+ controller.enqueue({
602
+ type: "2" /* Data */,
603
+ value: chunk.data
604
+ });
605
+ break;
606
+ }
607
+ // TODO ignore for now
608
+ // in the future, we should create a handler that waits for text parts to finish before continuing
609
+ case "tool-call-args-text-finish":
610
+ case "part-finish":
611
+ break;
612
+ default: {
613
+ const exhaustiveCheck = type;
614
+ throw new Error(`Unsupported chunk type: ${exhaustiveCheck}`);
615
+ }
616
+ }
617
+ }
618
+ });
619
+ return readable.pipeThrough(new AssistantMetaTransformStream()).pipeThrough(transform).pipeThrough(new DataStreamChunkEncoder()).pipeThrough(new TextEncoderStream());
620
+ });
621
+ }
622
+ };
623
+ var TOOL_CALL_ARGS_CLOSING_CHUNKS = [
624
+ "b" /* StartToolCall */,
625
+ "9" /* ToolCall */,
626
+ "0" /* TextDelta */,
627
+ "g" /* ReasoningDelta */,
628
+ "h" /* Source */,
629
+ "3" /* Error */,
630
+ "e" /* FinishStep */,
631
+ "d" /* FinishMessage */
632
+ ];
633
+ var DataStreamDecoder = class extends PipeableTransformStream {
634
+ constructor() {
635
+ super((readable) => {
636
+ const toolCallControllers = /* @__PURE__ */ new Map();
637
+ let activeToolCallArgsText;
638
+ const transform = new AssistantTransformStream({
639
+ transform(chunk, controller) {
640
+ const { type, value } = chunk;
641
+ if (TOOL_CALL_ARGS_CLOSING_CHUNKS.includes(type)) {
642
+ activeToolCallArgsText?.close();
643
+ activeToolCallArgsText = void 0;
644
+ }
645
+ switch (type) {
646
+ case "g" /* ReasoningDelta */:
647
+ controller.appendReasoning(value);
648
+ break;
649
+ case "0" /* TextDelta */:
650
+ controller.appendText(value);
651
+ break;
652
+ case "b" /* StartToolCall */: {
653
+ const { toolCallId, toolName } = value;
654
+ const toolCallController = controller.addToolCallPart({
655
+ toolCallId,
656
+ toolName
657
+ });
658
+ toolCallControllers.set(toolCallId, toolCallController);
659
+ activeToolCallArgsText = toolCallController.argsText;
660
+ break;
661
+ }
662
+ case "c" /* ToolCallDelta */: {
663
+ const { toolCallId, argsTextDelta } = value;
664
+ const toolCallController = toolCallControllers.get(toolCallId);
665
+ if (!toolCallController)
666
+ throw new Error(
667
+ "Encountered tool call with unknown id: " + toolCallId
668
+ );
669
+ toolCallController.argsText.append(argsTextDelta);
670
+ break;
671
+ }
672
+ case "a" /* ToolCallResult */: {
673
+ const { toolCallId, result } = value;
674
+ const toolCallController = toolCallControllers.get(toolCallId);
675
+ if (!toolCallController)
676
+ throw new Error(
677
+ "Encountered tool call result with unknown id: " + toolCallId
678
+ );
679
+ toolCallController.setResult(result);
680
+ break;
681
+ }
682
+ case "9" /* ToolCall */: {
683
+ const { toolCallId, toolName, args } = value;
684
+ const toolCallController = controller.addToolCallPart({
685
+ toolCallId,
686
+ toolName
687
+ });
688
+ toolCallControllers.set(toolCallId, toolCallController);
689
+ toolCallController.argsText.append(JSON.stringify(args));
690
+ toolCallController.argsText.close();
691
+ break;
692
+ }
693
+ case "d" /* FinishMessage */:
694
+ controller.enqueue({
695
+ type: "message-finish",
696
+ path: [],
697
+ ...value
698
+ });
699
+ break;
700
+ case "f" /* StartStep */:
701
+ controller.enqueue({
702
+ type: "step-start",
703
+ path: [],
704
+ ...value
705
+ });
706
+ break;
707
+ case "e" /* FinishStep */:
708
+ controller.enqueue({
709
+ type: "step-finish",
710
+ path: [],
711
+ ...value
712
+ });
713
+ break;
714
+ case "2" /* Data */:
715
+ controller.enqueue({
716
+ type: "data",
717
+ path: [],
718
+ data: value
719
+ });
720
+ break;
721
+ case "8" /* Annotation */:
722
+ controller.enqueue({
723
+ type: "annotations",
724
+ path: [],
725
+ annotations: value
726
+ });
727
+ break;
728
+ case "h" /* Source */:
729
+ controller.appendSource({
730
+ type: "source",
731
+ ...value
732
+ });
733
+ break;
734
+ case "3" /* Error */:
735
+ controller.enqueue({
736
+ type: "error",
737
+ path: [],
738
+ error: value
739
+ });
740
+ break;
741
+ case "k" /* File */:
742
+ controller.appendFile({
743
+ type: "file",
744
+ ...value
745
+ });
746
+ break;
747
+ case "j" /* ReasoningSignature */:
748
+ case "i" /* RedactedReasoning */:
749
+ break;
750
+ default: {
751
+ const exhaustiveCheck = type;
752
+ throw new Error(`unsupported chunk type: ${exhaustiveCheck}`);
753
+ }
754
+ }
755
+ },
756
+ flush() {
757
+ activeToolCallArgsText?.close();
758
+ activeToolCallArgsText = void 0;
759
+ toolCallControllers.forEach((controller) => controller.close());
760
+ toolCallControllers.clear();
761
+ }
762
+ });
763
+ return readable.pipeThrough(new TextDecoderStream()).pipeThrough(new LineDecoderStream()).pipeThrough(new DataStreamChunkDecoder()).pipeThrough(transform);
764
+ });
765
+ }
418
766
  };
419
- var RunControllerImpl = class {
420
- _merge = createMergeStream();
421
- _textPartController;
422
- getReadable() {
423
- return this._merge.stream;
767
+
768
+ // src/core/utils/generateId.tsx
769
+ var import_non_secure = require("nanoid/non-secure");
770
+ var generateId = (0, import_non_secure.customAlphabet)(
771
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
772
+ 7
773
+ );
774
+
775
+ // src/core/modules/assistant-stream.ts
776
+ var AssistantStreamControllerImpl = class {
777
+ _merger = createMergeStream();
778
+ _append;
779
+ _contentCounter = new Counter();
780
+ get __internal_isClosed() {
781
+ return this._merger.isSealed();
424
782
  }
425
- close() {
426
- this._merge.seal();
427
- this._textPartController?.close();
783
+ __internal_getReadable() {
784
+ return this._merger.readable;
785
+ }
786
+ _closeSubscriber;
787
+ __internal_subscribeToClose(callback) {
788
+ this._closeSubscriber = callback;
789
+ }
790
+ _addPart(part, stream) {
791
+ this.enqueue({
792
+ type: "part-start",
793
+ part,
794
+ path: []
795
+ });
796
+ this._merger.addStream(
797
+ stream.pipeThrough(new PathAppendEncoder(this._contentCounter.value))
798
+ );
428
799
  }
429
800
  merge(stream) {
430
- this._merge.addStream(stream);
801
+ this._merger.addStream(
802
+ stream.pipeThrough(new PathMergeEncoder(this._contentCounter))
803
+ );
431
804
  }
432
805
  appendText(textDelta) {
433
- if (!this._textPartController) {
434
- this._textPartController = this.addTextPart();
806
+ if (this._append?.kind !== "text") {
807
+ if (this._append) {
808
+ this._append.controller.close();
809
+ }
810
+ this._append = {
811
+ kind: "text",
812
+ controller: this.addTextPart()
813
+ };
435
814
  }
436
- this._textPartController.append(textDelta);
815
+ this._append.controller.append(textDelta);
437
816
  }
438
- addTextPart() {
439
- let controller;
440
- const textStream = createTextStream({
441
- start(c) {
442
- controller = c;
817
+ appendReasoning(textDelta) {
818
+ if (this._append?.kind !== "reasoning") {
819
+ if (this._append) {
820
+ this._append.controller.close();
443
821
  }
444
- });
445
- this.merge(textStream);
822
+ this._append = {
823
+ kind: "reasoning",
824
+ controller: this.addReasoningPart()
825
+ };
826
+ }
827
+ this._append.controller.append(textDelta);
828
+ }
829
+ addTextPart() {
830
+ const [stream, controller] = createTextStreamController();
831
+ this._addPart({ type: "text" }, stream);
832
+ return controller;
833
+ }
834
+ addReasoningPart() {
835
+ const [stream, controller] = createTextStreamController();
836
+ this._addPart({ type: "reasoning" }, stream);
446
837
  return controller;
447
838
  }
448
839
  addToolCallPart(options) {
449
840
  const opt = typeof options === "string" ? { toolName: options } : options;
450
- let controller;
451
- const toolCallStream = createToolCallStream({
452
- toolCallId: opt.toolCallId ?? generateId(),
453
- toolName: opt.toolName,
454
- start(c) {
455
- controller = c;
456
- }
457
- });
458
- this.merge(toolCallStream);
841
+ const toolName = opt.toolName;
842
+ const toolCallId = opt.toolCallId ?? generateId();
843
+ const [stream, controller] = createToolCallStreamController();
844
+ this._addPart({ type: "tool-call", toolName, toolCallId }, stream);
459
845
  if (opt.args !== void 0) {
460
846
  controller.argsText.append(JSON.stringify(opt.args));
461
847
  controller.argsText.close();
462
848
  }
463
- if (opt !== void 0) {
464
- controller.setResult(opt.result);
849
+ if (opt.result !== void 0) {
850
+ controller.setResult(opt.result, opt.isError);
465
851
  }
466
852
  return controller;
467
853
  }
468
- addError(error) {
469
- this._merge.addStream(
854
+ appendSource(options) {
855
+ this._addPart(
856
+ options,
470
857
  new ReadableStream({
471
- start(c) {
472
- c.enqueue({
473
- type: "error",
474
- error
858
+ start(controller) {
859
+ controller.enqueue({
860
+ type: "part-finish",
861
+ path: []
475
862
  });
863
+ controller.close();
476
864
  }
477
865
  })
478
866
  );
479
867
  }
868
+ appendFile(options) {
869
+ this._addPart(
870
+ options,
871
+ new ReadableStream({
872
+ start(controller) {
873
+ controller.enqueue({
874
+ type: "part-finish",
875
+ path: []
876
+ });
877
+ controller.close();
878
+ }
879
+ })
880
+ );
881
+ }
882
+ enqueue(chunk) {
883
+ this._merger.enqueue(chunk);
884
+ if (chunk.type === "part-start" && chunk.path.length === 0) {
885
+ this._contentCounter.up();
886
+ }
887
+ }
888
+ close() {
889
+ this._merger.seal();
890
+ this._append?.controller?.close();
891
+ this._closeSubscriber?.();
892
+ }
480
893
  };
481
894
  function createAssistantStream(callback) {
482
- const controller = new RunControllerImpl();
483
- const promiseOrVoid = callback(controller);
895
+ const controller = new AssistantStreamControllerImpl();
896
+ let promiseOrVoid;
897
+ try {
898
+ promiseOrVoid = callback(controller);
899
+ } catch (e) {
900
+ if (!controller.__internal_isClosed) {
901
+ controller.enqueue({
902
+ type: "error",
903
+ path: [],
904
+ error: String(e)
905
+ });
906
+ controller.close();
907
+ }
908
+ throw e;
909
+ }
484
910
  if (promiseOrVoid instanceof Promise) {
485
911
  const runTask = async () => {
486
912
  try {
487
913
  await promiseOrVoid;
488
914
  } catch (e) {
489
- controller.addError(e instanceof Error ? e.message : String(e));
915
+ if (!controller.__internal_isClosed) {
916
+ controller.enqueue({
917
+ type: "error",
918
+ path: [],
919
+ error: String(e)
920
+ });
921
+ }
490
922
  throw e;
491
923
  } finally {
492
- controller.close();
924
+ if (!controller.__internal_isClosed) {
925
+ controller.close();
926
+ }
493
927
  }
494
928
  };
495
929
  runTask();
496
930
  } else {
497
- controller.close();
931
+ if (!controller.__internal_isClosed) {
932
+ controller.close();
933
+ }
498
934
  }
499
- return controller.getReadable();
935
+ return controller.__internal_getReadable();
936
+ }
937
+ var promiseWithResolvers2 = function() {
938
+ let resolve;
939
+ let reject;
940
+ const promise = new Promise((res, rej) => {
941
+ resolve = res;
942
+ reject = rej;
943
+ });
944
+ if (!resolve || !reject) throw new Error("Failed to create promise");
945
+ return { promise, resolve, reject };
946
+ };
947
+ function createAssistantStreamController() {
948
+ const { resolve, promise } = promiseWithResolvers2();
949
+ let controller;
950
+ const stream = createAssistantStream((c) => {
951
+ controller = c;
952
+ controller.__internal_subscribeToClose(
953
+ resolve
954
+ );
955
+ return promise;
956
+ });
957
+ return [stream, controller];
500
958
  }
501
959
  function createAssistantStreamResponse(callback) {
502
960
  return AssistantStream.toResponse(
@@ -505,61 +963,119 @@ function createAssistantStreamResponse(callback) {
505
963
  );
506
964
  }
507
965
 
508
- // src/core/serialization/PlainText.ts
509
- var PlainTextEncoder = class {
510
- _transformStream;
511
- get writable() {
512
- return this._transformStream.writable;
513
- }
514
- get readable() {
515
- return this._transformStream.readable;
516
- }
517
- constructor() {
518
- this._transformStream = new PipeableTransformStream((readable) => {
966
+ // src/core/effects/ToolExecutionStream.ts
967
+ var import_secure_json_parse = __toESM(require("secure-json-parse"));
968
+ var ToolExecutionStream = class extends PipeableTransformStream {
969
+ constructor(toolCallback) {
970
+ const toolCallPromises = /* @__PURE__ */ new Map();
971
+ const toolCallArgsText = {};
972
+ super((readable) => {
519
973
  const transform = new TransformStream({
520
974
  transform(chunk, controller) {
975
+ if (chunk.type !== "part-finish" || chunk.meta.type !== "tool-call") {
976
+ controller.enqueue(chunk);
977
+ }
521
978
  const type = chunk.type;
522
979
  switch (type) {
523
- case "text-delta":
524
- controller.enqueue(chunk.textDelta);
980
+ case "text-delta": {
981
+ if (chunk.meta.type === "tool-call") {
982
+ const toolCallId = chunk.meta.toolCallId;
983
+ if (toolCallArgsText[toolCallId] === void 0) {
984
+ toolCallArgsText[toolCallId] = chunk.textDelta;
985
+ } else {
986
+ toolCallArgsText[toolCallId] += chunk.textDelta;
987
+ }
988
+ }
525
989
  break;
526
- default:
527
- const unsupportedType = type;
528
- throw new Error(`unsupported chunk type: ${unsupportedType}`);
990
+ }
991
+ case "tool-call-args-text-finish": {
992
+ if (chunk.meta.type !== "tool-call") break;
993
+ const { toolCallId, toolName } = chunk.meta;
994
+ const argsText = toolCallArgsText[toolCallId];
995
+ if (!argsText)
996
+ throw new Error("Unexpected tool call without args");
997
+ const executeTool = () => {
998
+ let args;
999
+ try {
1000
+ args = import_secure_json_parse.default.parse(argsText);
1001
+ } catch (e) {
1002
+ throw new Error(
1003
+ `Function parameter parsing failed. ${JSON.stringify(e.message)}`
1004
+ );
1005
+ }
1006
+ return toolCallback({
1007
+ toolCallId,
1008
+ toolName,
1009
+ args
1010
+ });
1011
+ };
1012
+ let promiseOrUndefined;
1013
+ try {
1014
+ promiseOrUndefined = executeTool();
1015
+ } catch (e) {
1016
+ controller.enqueue({
1017
+ type: "result",
1018
+ path: chunk.path,
1019
+ result: String(e),
1020
+ isError: true
1021
+ });
1022
+ break;
1023
+ }
1024
+ if (promiseOrUndefined instanceof Promise) {
1025
+ const toolCallPromise = promiseOrUndefined.then((c) => {
1026
+ if (c === void 0) return;
1027
+ controller.enqueue({
1028
+ type: "result",
1029
+ path: chunk.path,
1030
+ result: c,
1031
+ isError: false
1032
+ });
1033
+ }).catch((e) => {
1034
+ controller.enqueue({
1035
+ type: "result",
1036
+ path: chunk.path,
1037
+ result: String(e),
1038
+ isError: true
1039
+ });
1040
+ });
1041
+ toolCallPromises.set(toolCallId, toolCallPromise);
1042
+ } else if (promiseOrUndefined !== void 0) {
1043
+ controller.enqueue({
1044
+ type: "result",
1045
+ path: chunk.path,
1046
+ result: promiseOrUndefined,
1047
+ isError: false
1048
+ });
1049
+ }
1050
+ break;
1051
+ }
1052
+ case "part-finish": {
1053
+ if (chunk.meta.type !== "tool-call") break;
1054
+ const { toolCallId } = chunk.meta;
1055
+ const toolCallPromise = toolCallPromises.get(toolCallId);
1056
+ if (toolCallPromise) {
1057
+ toolCallPromise.then(() => {
1058
+ controller.enqueue(chunk);
1059
+ });
1060
+ } else {
1061
+ controller.enqueue(chunk);
1062
+ }
1063
+ }
529
1064
  }
1065
+ },
1066
+ async flush() {
1067
+ await Promise.all(toolCallPromises);
530
1068
  }
531
1069
  });
532
- return readable.pipeThrough(transform).pipeThrough(new TextEncoderStream());
533
- });
534
- }
535
- };
536
- var PlainTextDecoder = class {
537
- _transformStream;
538
- get writable() {
539
- return this._transformStream.writable;
540
- }
541
- get readable() {
542
- return this._transformStream.readable;
543
- }
544
- constructor() {
545
- this._transformStream = new PipeableTransformStream((readable) => {
546
- const transform = new TransformStream({
547
- transform(chunk, controller) {
548
- controller.enqueue({
549
- type: "text-delta",
550
- textDelta: chunk
551
- });
552
- }
553
- });
554
- return readable.pipeThrough(new TextDecoderStream()).pipeThrough(transform);
1070
+ return readable.pipeThrough(new AssistantMetaTransformStream()).pipeThrough(transform);
555
1071
  });
556
1072
  }
557
1073
  };
558
1074
 
559
- // src/core/accumulators/partial-json/parse-partial-json.ts
560
- var import_secure_json_parse = __toESM(require("secure-json-parse"));
1075
+ // src/core/utils/json/parse-partial-json.ts
1076
+ var import_secure_json_parse2 = __toESM(require("secure-json-parse"));
561
1077
 
562
- // src/core/accumulators/partial-json/fix-json.ts
1078
+ // src/core/utils/json/fix-json.ts
563
1079
  function fixJson(input) {
564
1080
  const stack = ["ROOT"];
565
1081
  let lastValidIndex = -1;
@@ -877,176 +1393,354 @@ function fixJson(input) {
877
1393
  return result;
878
1394
  }
879
1395
 
880
- // src/core/accumulators/partial-json/parse-partial-json.ts
1396
+ // src/core/utils/json/parse-partial-json.ts
881
1397
  var parsePartialJson = (json) => {
882
1398
  try {
883
- return import_secure_json_parse.default.parse(json);
1399
+ return import_secure_json_parse2.default.parse(json);
884
1400
  } catch {
885
1401
  try {
886
- return import_secure_json_parse.default.parse(fixJson(json));
1402
+ return import_secure_json_parse2.default.parse(fixJson(json));
887
1403
  } catch {
888
1404
  return void 0;
889
1405
  }
890
1406
  }
891
1407
  };
892
1408
 
893
- // src/core/accumulators/assistantMessageAccumulator.ts
894
- var assistantMessageAccumulator = () => {
895
- let message = {
896
- role: "assistant",
897
- content: [],
898
- status: { type: "running" },
899
- metadata: {
900
- steps: [],
901
- custom: {}
1409
+ // src/core/accumulators/assistant-message-accumulator.ts
1410
+ var createInitialMessage = () => ({
1411
+ role: "assistant",
1412
+ status: { type: "running" },
1413
+ parts: [],
1414
+ get content() {
1415
+ return this.parts;
1416
+ },
1417
+ metadata: {
1418
+ unstable_data: [],
1419
+ unstable_annotations: [],
1420
+ steps: [],
1421
+ custom: {}
1422
+ }
1423
+ });
1424
+ var updatePartForPath = (message, chunk, updater) => {
1425
+ if (message.parts.length === 0) {
1426
+ throw new Error("No parts available to update.");
1427
+ }
1428
+ if (chunk.path.length !== 1)
1429
+ throw new Error("Nested paths are not supported yet.");
1430
+ const partIndex = chunk.path[0];
1431
+ const updatedPart = updater(message.parts[partIndex]);
1432
+ return {
1433
+ ...message,
1434
+ parts: [
1435
+ ...message.parts.slice(0, partIndex),
1436
+ updatedPart,
1437
+ ...message.parts.slice(partIndex + 1)
1438
+ ],
1439
+ get content() {
1440
+ return this.parts;
902
1441
  }
903
1442
  };
904
- const transformer = new TransformStream({
905
- transform(chunk, controller) {
906
- const { type } = chunk;
907
- switch (type) {
908
- case "text-delta": {
909
- message = appendOrUpdateText(message, chunk.textDelta);
910
- controller.enqueue(message);
911
- break;
912
- }
913
- case "tool-call-begin": {
914
- const { toolCallId, toolName } = chunk;
915
- message = appendToolCall(message, toolCallId, toolName);
916
- controller.enqueue(message);
917
- break;
918
- }
919
- case "tool-call-delta": {
920
- const { toolCallId, argsTextDelta } = chunk;
921
- message = appendToolArgsTextDelta(message, toolCallId, argsTextDelta);
922
- controller.enqueue(message);
923
- break;
924
- }
925
- case "tool-result": {
926
- const { toolCallId, result } = chunk;
927
- message = setToolResult(message, toolCallId, result);
928
- controller.enqueue(message);
929
- break;
930
- }
931
- case "error": {
932
- const { error } = chunk;
933
- message = setError(message, error);
934
- controller.enqueue(message);
935
- break;
936
- }
937
- default: {
938
- const _exhaustiveCheck = type;
939
- throw new Error(`Unsupported chunk type: ${_exhaustiveCheck}`);
940
- }
1443
+ };
1444
+ var handlePartStart = (message, chunk) => {
1445
+ const partInit = chunk.part;
1446
+ if (partInit.type === "text" || partInit.type === "reasoning") {
1447
+ const newTextPart = {
1448
+ type: partInit.type,
1449
+ text: "",
1450
+ status: { type: "running" }
1451
+ };
1452
+ return {
1453
+ ...message,
1454
+ parts: [...message.parts, newTextPart],
1455
+ get content() {
1456
+ return this.parts;
941
1457
  }
942
- },
943
- flush(controller) {
944
- message = appendOrUpdateFinish(message);
945
- controller.enqueue(message);
1458
+ };
1459
+ } else if (partInit.type === "tool-call") {
1460
+ const newToolCallPart = {
1461
+ type: "tool-call",
1462
+ state: "partial-call",
1463
+ status: { type: "running", isArgsComplete: false },
1464
+ toolCallId: partInit.toolCallId,
1465
+ toolName: partInit.toolName,
1466
+ argsText: "",
1467
+ args: {}
1468
+ };
1469
+ return {
1470
+ ...message,
1471
+ parts: [...message.parts, newToolCallPart],
1472
+ get content() {
1473
+ return this.parts;
1474
+ }
1475
+ };
1476
+ } else if (partInit.type === "source") {
1477
+ const newSourcePart = {
1478
+ type: "source",
1479
+ sourceType: partInit.sourceType,
1480
+ id: partInit.id,
1481
+ url: partInit.url,
1482
+ ...partInit.title ? { title: partInit.title } : void 0
1483
+ };
1484
+ return {
1485
+ ...message,
1486
+ parts: [...message.parts, newSourcePart],
1487
+ get content() {
1488
+ return this.parts;
1489
+ }
1490
+ };
1491
+ } else if (partInit.type === "file") {
1492
+ const newFilePart = {
1493
+ type: "file",
1494
+ mimeType: partInit.mimeType,
1495
+ data: partInit.data
1496
+ };
1497
+ return {
1498
+ ...message,
1499
+ parts: [...message.parts, newFilePart],
1500
+ get content() {
1501
+ return this.parts;
1502
+ }
1503
+ };
1504
+ } else {
1505
+ throw new Error(`Unsupported part type: ${partInit.type}`);
1506
+ }
1507
+ };
1508
+ var handleToolCallArgsTextFinish = (message, chunk) => {
1509
+ return updatePartForPath(message, chunk, (lastPart) => {
1510
+ if (lastPart.type !== "tool-call") {
1511
+ throw new Error("Last part is not a tool call");
946
1512
  }
1513
+ return {
1514
+ ...lastPart,
1515
+ state: "call"
1516
+ };
947
1517
  });
948
- return transformer;
949
1518
  };
950
- var appendOrUpdateText = (message, textDelta) => {
951
- let contentParts = message.content ?? [];
952
- let contentPart = message.content?.at(-1);
953
- if (contentPart?.type !== "text") {
954
- contentPart = {
955
- type: "text",
956
- text: textDelta,
957
- status: { type: "running" }
1519
+ var handlePartFinish = (message, chunk) => {
1520
+ return updatePartForPath(message, chunk, (lastPart) => ({
1521
+ ...lastPart,
1522
+ status: { type: "complete", reason: "unknown" }
1523
+ }));
1524
+ };
1525
+ var handleTextDelta = (message, chunk) => {
1526
+ return updatePartForPath(message, chunk, (lastPart) => {
1527
+ if (lastPart.type === "text") {
1528
+ return { ...lastPart, text: lastPart.text + chunk.textDelta };
1529
+ } else if (lastPart.type === "tool-call") {
1530
+ const newArgsText = lastPart.argsText + chunk.textDelta;
1531
+ let newArgs;
1532
+ try {
1533
+ newArgs = parsePartialJson(newArgsText);
1534
+ } catch (err) {
1535
+ newArgs = lastPart.args;
1536
+ }
1537
+ return { ...lastPart, argsText: newArgsText, args: newArgs };
1538
+ } else {
1539
+ throw new Error(
1540
+ "text-delta received but last part is neither text nor tool-call"
1541
+ );
1542
+ }
1543
+ });
1544
+ };
1545
+ var handleResult = (message, chunk) => {
1546
+ return updatePartForPath(message, chunk, (lastPart) => {
1547
+ if (lastPart.type === "tool-call") {
1548
+ return {
1549
+ ...lastPart,
1550
+ state: "result",
1551
+ result: chunk.result,
1552
+ isError: chunk.isError ?? false,
1553
+ status: { type: "complete", reason: "stop" }
1554
+ };
1555
+ } else {
1556
+ throw new Error("Result chunk received but last part is not a tool-call");
1557
+ }
1558
+ });
1559
+ };
1560
+ var handleMessageFinish = (message, chunk) => {
1561
+ const newStatus = getStatus(chunk);
1562
+ return { ...message, status: newStatus };
1563
+ };
1564
+ var getStatus = (chunk) => {
1565
+ if (chunk.finishReason === "tool-calls") {
1566
+ return {
1567
+ type: "requires-action",
1568
+ reason: "tool-calls"
1569
+ };
1570
+ } else if (chunk.finishReason === "stop" || chunk.finishReason === "unknown") {
1571
+ return {
1572
+ type: "complete",
1573
+ reason: chunk.finishReason
958
1574
  };
959
1575
  } else {
960
- contentParts = contentParts.slice(0, -1);
961
- contentPart = {
962
- type: "text",
963
- text: contentPart.text + textDelta,
964
- status: { type: "running" }
1576
+ return {
1577
+ type: "incomplete",
1578
+ reason: chunk.finishReason
965
1579
  };
966
1580
  }
967
- return {
968
- ...message,
969
- content: contentParts.concat([contentPart])
970
- };
971
1581
  };
972
- var appendToolCall = (message, toolCallId, toolName) => {
1582
+ var handleAnnotations = (message, chunk) => {
973
1583
  return {
974
1584
  ...message,
975
- content: [
976
- ...message.content,
977
- {
978
- type: "tool-call",
979
- toolCallId,
980
- toolName,
981
- argsText: "",
982
- args: {},
983
- status: { type: "running", isArgsComplete: false }
984
- }
985
- ]
1585
+ metadata: {
1586
+ ...message.metadata,
1587
+ unstable_annotations: [
1588
+ ...message.metadata.unstable_annotations,
1589
+ ...chunk.annotations
1590
+ ]
1591
+ }
986
1592
  };
987
1593
  };
988
- var appendToolArgsTextDelta = (message, toolCallId, argsTextDelta) => {
989
- const contentPartIdx = message.content.findIndex(
990
- (part) => part.type === "tool-call" && part.toolCallId === toolCallId
991
- );
992
- if (contentPartIdx === -1)
993
- throw new Error(
994
- `Received tool call delta for unknown tool call "${toolCallId}".`
995
- );
996
- const contentPart = message.content[contentPartIdx];
997
- const newArgsText = contentPart.argsText + argsTextDelta;
1594
+ var handleData = (message, chunk) => {
998
1595
  return {
999
1596
  ...message,
1000
- content: [
1001
- ...message.content.slice(0, contentPartIdx),
1002
- {
1003
- ...contentPart,
1004
- argsText: newArgsText,
1005
- args: parsePartialJson(newArgsText)
1006
- },
1007
- ...message.content.slice(contentPartIdx + 1)
1008
- ]
1597
+ metadata: {
1598
+ ...message.metadata,
1599
+ unstable_data: [...message.metadata.unstable_data, ...chunk.data]
1600
+ }
1009
1601
  };
1010
1602
  };
1011
- var setToolResult = (message, toolCallId, result) => {
1012
- let found = false;
1013
- const newContentParts = message.content?.map((part) => {
1014
- if (part.type !== "tool-call" || part.toolCallId !== toolCallId)
1015
- return part;
1016
- found = true;
1017
- return {
1018
- ...part,
1019
- result
1020
- };
1021
- });
1022
- if (!found)
1023
- throw new Error(
1024
- `Received tool result for unknown tool call "${toolCallId}". This is likely an internal bug in assistant-ui.`
1025
- );
1603
+ var handleStepStart = (message, chunk) => {
1026
1604
  return {
1027
1605
  ...message,
1028
- content: newContentParts
1606
+ metadata: {
1607
+ ...message.metadata,
1608
+ steps: [
1609
+ ...message.metadata.steps,
1610
+ { state: "started", messageId: chunk.messageId }
1611
+ ]
1612
+ }
1029
1613
  };
1030
1614
  };
1031
- var appendOrUpdateFinish = (message) => {
1615
+ var handleStepFinish = (message, chunk) => {
1616
+ const steps = message.metadata.steps.slice();
1617
+ const lastIndex = steps.length - 1;
1618
+ if (steps.length > 0 && steps[lastIndex]?.state === "started") {
1619
+ steps[lastIndex] = {
1620
+ ...steps[lastIndex],
1621
+ state: "finished",
1622
+ finishReason: chunk.finishReason,
1623
+ usage: chunk.usage,
1624
+ isContinued: chunk.isContinued
1625
+ };
1626
+ } else {
1627
+ steps.push({
1628
+ state: "finished",
1629
+ messageId: generateId(),
1630
+ finishReason: chunk.finishReason,
1631
+ usage: chunk.usage,
1632
+ isContinued: chunk.isContinued
1633
+ });
1634
+ }
1032
1635
  return {
1033
1636
  ...message,
1034
- status: {
1035
- type: "complete",
1036
- reason: "unknown"
1637
+ metadata: {
1638
+ ...message.metadata,
1639
+ steps
1037
1640
  }
1038
1641
  };
1039
1642
  };
1040
- var setError = (message, error) => {
1643
+ var handleErrorChunk = (message, chunk) => {
1041
1644
  return {
1042
1645
  ...message,
1043
- status: {
1044
- type: "incomplete",
1045
- reason: "error",
1046
- error
1047
- }
1646
+ status: { type: "incomplete", reason: "error", error: chunk.error }
1048
1647
  };
1049
1648
  };
1649
+ var AssistantMessageAccumulator = class extends TransformStream {
1650
+ constructor() {
1651
+ let message = createInitialMessage();
1652
+ let hadChunks = false;
1653
+ super({
1654
+ transform(chunk, controller) {
1655
+ const type = chunk.type;
1656
+ switch (type) {
1657
+ case "part-start":
1658
+ message = handlePartStart(message, chunk);
1659
+ break;
1660
+ case "tool-call-args-text-finish":
1661
+ message = handleToolCallArgsTextFinish(message, chunk);
1662
+ break;
1663
+ case "part-finish":
1664
+ message = handlePartFinish(message, chunk);
1665
+ break;
1666
+ case "text-delta":
1667
+ message = handleTextDelta(message, chunk);
1668
+ break;
1669
+ case "result":
1670
+ message = handleResult(message, chunk);
1671
+ break;
1672
+ case "message-finish":
1673
+ message = handleMessageFinish(message, chunk);
1674
+ break;
1675
+ case "annotations":
1676
+ message = handleAnnotations(message, chunk);
1677
+ break;
1678
+ case "data":
1679
+ message = handleData(message, chunk);
1680
+ break;
1681
+ case "step-start":
1682
+ message = handleStepStart(message, chunk);
1683
+ break;
1684
+ case "step-finish":
1685
+ message = handleStepFinish(message, chunk);
1686
+ break;
1687
+ case "error":
1688
+ message = handleErrorChunk(message, chunk);
1689
+ break;
1690
+ default: {
1691
+ const unhandledType = type;
1692
+ throw new Error(`Unsupported chunk type: ${unhandledType}`);
1693
+ }
1694
+ }
1695
+ controller.enqueue(message);
1696
+ hadChunks = true;
1697
+ },
1698
+ flush(controller) {
1699
+ if (!hadChunks) {
1700
+ controller.enqueue(message);
1701
+ }
1702
+ }
1703
+ });
1704
+ }
1705
+ };
1706
+
1707
+ // src/core/serialization/PlainText.ts
1708
+ var PlainTextEncoder = class extends PipeableTransformStream {
1709
+ headers = new Headers({
1710
+ "Content-Type": "text/plain; charset=utf-8",
1711
+ "x-vercel-ai-data-stream": "v1"
1712
+ });
1713
+ constructor() {
1714
+ super((readable) => {
1715
+ const transform = new TransformStream({
1716
+ transform(chunk, controller) {
1717
+ const type = chunk.type;
1718
+ switch (type) {
1719
+ case "text-delta":
1720
+ controller.enqueue(chunk.textDelta);
1721
+ break;
1722
+ default:
1723
+ const unsupportedType = type;
1724
+ throw new Error(`unsupported chunk type: ${unsupportedType}`);
1725
+ }
1726
+ }
1727
+ });
1728
+ return readable.pipeThrough(transform).pipeThrough(new TextEncoderStream());
1729
+ });
1730
+ }
1731
+ };
1732
+ var PlainTextDecoder = class extends PipeableTransformStream {
1733
+ constructor() {
1734
+ super((readable) => {
1735
+ const transform = new AssistantTransformStream({
1736
+ transform(chunk, controller) {
1737
+ controller.appendText(chunk);
1738
+ }
1739
+ });
1740
+ return readable.pipeThrough(new TextDecoderStream()).pipeThrough(transform);
1741
+ });
1742
+ }
1743
+ };
1050
1744
 
1051
1745
  // src/core/accumulators/AssistantMessageStream.ts
1052
1746
  var AssistantMessageStream = class _AssistantMessageStream {
@@ -1056,7 +1750,7 @@ var AssistantMessageStream = class _AssistantMessageStream {
1056
1750
  }
1057
1751
  static fromAssistantStream(stream) {
1058
1752
  return new _AssistantMessageStream(
1059
- stream.pipeThrough(assistantMessageAccumulator())
1753
+ stream.pipeThrough(new AssistantMessageAccumulator())
1060
1754
  );
1061
1755
  }
1062
1756
  async unstable_result() {
@@ -1068,8 +1762,11 @@ var AssistantMessageStream = class _AssistantMessageStream {
1068
1762
  return {
1069
1763
  role: "assistant",
1070
1764
  status: { type: "complete", reason: "unknown" },
1765
+ parts: [],
1071
1766
  content: [],
1072
1767
  metadata: {
1768
+ unstable_data: [],
1769
+ unstable_annotations: [],
1073
1770
  steps: [],
1074
1771
  custom: {}
1075
1772
  }
@@ -1096,12 +1793,14 @@ var AssistantMessageStream = class _AssistantMessageStream {
1096
1793
  };
1097
1794
  // Annotate the CommonJS export names for ESM import in node:
1098
1795
  0 && (module.exports = {
1796
+ AssistantMessageAccumulator,
1099
1797
  AssistantMessageStream,
1100
1798
  AssistantStream,
1101
1799
  DataStreamDecoder,
1102
1800
  DataStreamEncoder,
1103
1801
  PlainTextDecoder,
1104
1802
  PlainTextEncoder,
1803
+ ToolExecutionStream,
1105
1804
  createAssistantStream,
1106
1805
  createAssistantStreamResponse
1107
1806
  });