assistant-stream 0.0.21 → 0.0.23

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