assistant-stream 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/dist/core/AssistantStreamChunk.d.ts +5 -1
  2. package/dist/core/AssistantStreamChunk.d.ts.map +1 -1
  3. package/dist/core/accumulators/AssistantMessageStream.d.ts.map +1 -1
  4. package/dist/core/accumulators/AssistantMessageStream.js +1 -0
  5. package/dist/core/accumulators/AssistantMessageStream.js.map +1 -1
  6. package/dist/core/accumulators/assistant-message-accumulator.d.ts.map +1 -1
  7. package/dist/core/accumulators/assistant-message-accumulator.js +19 -1
  8. package/dist/core/accumulators/assistant-message-accumulator.js.map +1 -1
  9. package/dist/core/index.d.ts +3 -0
  10. package/dist/core/index.d.ts.map +1 -1
  11. package/dist/core/index.js +9 -1
  12. package/dist/core/index.js.map +1 -1
  13. package/dist/core/modules/tool-call.d.ts.map +1 -1
  14. package/dist/core/modules/tool-call.js +1 -1
  15. package/dist/core/modules/tool-call.js.map +1 -1
  16. package/dist/core/object/ObjectStream.test.d.ts +2 -0
  17. package/dist/core/object/ObjectStream.test.d.ts.map +1 -0
  18. package/dist/core/object/ObjectStreamAccumulator.d.ts +11 -0
  19. package/dist/core/object/ObjectStreamAccumulator.d.ts.map +1 -0
  20. package/dist/core/object/ObjectStreamAccumulator.js +64 -0
  21. package/dist/core/object/ObjectStreamAccumulator.js.map +1 -0
  22. package/dist/core/object/ObjectStreamResponse.d.ts +13 -0
  23. package/dist/core/object/ObjectStreamResponse.d.ts.map +1 -0
  24. package/dist/core/object/ObjectStreamResponse.js +66 -0
  25. package/dist/core/object/ObjectStreamResponse.js.map +1 -0
  26. package/dist/core/object/createObjectStream.d.ts +13 -0
  27. package/dist/core/object/createObjectStream.d.ts.map +1 -0
  28. package/dist/core/object/createObjectStream.js +63 -0
  29. package/dist/core/object/createObjectStream.js.map +1 -0
  30. package/dist/core/object/types.d.ts +15 -0
  31. package/dist/core/object/types.d.ts.map +1 -0
  32. package/dist/core/object/types.js +1 -0
  33. package/dist/core/object/types.js.map +1 -0
  34. package/dist/core/serialization/PlainText.d.ts.map +1 -1
  35. package/dist/core/serialization/PlainText.js.map +1 -1
  36. package/dist/core/serialization/data-stream/DataStream.d.ts.map +1 -1
  37. package/dist/core/serialization/data-stream/DataStream.js +14 -0
  38. package/dist/core/serialization/data-stream/DataStream.js.map +1 -1
  39. package/dist/core/serialization/data-stream/chunk-types.d.ts +4 -1
  40. package/dist/core/serialization/data-stream/chunk-types.d.ts.map +1 -1
  41. package/dist/core/serialization/data-stream/chunk-types.js +1 -0
  42. package/dist/core/serialization/data-stream/chunk-types.js.map +1 -1
  43. package/dist/core/tool/ToolCallReader.d.ts +8 -7
  44. package/dist/core/tool/ToolCallReader.d.ts.map +1 -1
  45. package/dist/core/tool/ToolCallReader.js +11 -4
  46. package/dist/core/tool/ToolCallReader.js.map +1 -1
  47. package/dist/core/tool/ToolExecutionStream.d.ts +3 -3
  48. package/dist/core/tool/ToolExecutionStream.d.ts.map +1 -1
  49. package/dist/core/tool/ToolExecutionStream.js.map +1 -1
  50. package/dist/core/tool/ToolResponse.d.ts +2 -2
  51. package/dist/core/tool/ToolResponse.d.ts.map +1 -1
  52. package/dist/core/tool/ToolResponse.js +3 -1
  53. package/dist/core/tool/ToolResponse.js.map +1 -1
  54. package/dist/core/tool/tool-types.d.ts +4 -5
  55. package/dist/core/tool/tool-types.d.ts.map +1 -1
  56. package/dist/core/tool/toolResultStream.d.ts +2 -2
  57. package/dist/core/tool/toolResultStream.d.ts.map +1 -1
  58. package/dist/core/tool/toolResultStream.js +3 -2
  59. package/dist/core/tool/toolResultStream.js.map +1 -1
  60. package/dist/core/utils/stream/SSE.d.ts +10 -0
  61. package/dist/core/utils/stream/SSE.d.ts.map +1 -0
  62. package/dist/core/utils/stream/SSE.js +102 -0
  63. package/dist/core/utils/stream/SSE.js.map +1 -0
  64. package/dist/core/utils/types.d.ts +14 -3
  65. package/dist/core/utils/types.d.ts.map +1 -1
  66. package/dist/utils/index.d.ts +3 -0
  67. package/dist/utils/index.d.ts.map +1 -0
  68. package/dist/utils/index.js +8 -0
  69. package/dist/utils/index.js.map +1 -0
  70. package/dist/utils/json/index.d.ts +2 -0
  71. package/dist/utils/json/index.d.ts.map +1 -0
  72. package/dist/utils/json/index.js +1 -0
  73. package/dist/utils/json/index.js.map +1 -0
  74. package/package.json +7 -7
  75. package/src/core/AssistantStreamChunk.ts +6 -1
  76. package/src/core/accumulators/AssistantMessageStream.ts +1 -0
  77. package/src/core/accumulators/assistant-message-accumulator.ts +25 -1
  78. package/src/core/index.ts +7 -0
  79. package/src/core/modules/tool-call.ts +3 -1
  80. package/src/core/object/ObjectStream.test.ts +376 -0
  81. package/src/core/object/ObjectStreamAccumulator.ts +80 -0
  82. package/src/core/object/ObjectStreamResponse.ts +81 -0
  83. package/src/core/object/createObjectStream.ts +87 -0
  84. package/src/core/object/types.ts +18 -0
  85. package/src/core/serialization/PlainText.ts +2 -1
  86. package/src/core/serialization/data-stream/DataStream.ts +16 -0
  87. package/src/core/serialization/data-stream/chunk-types.ts +6 -0
  88. package/src/core/tool/ToolCallReader.ts +57 -36
  89. package/src/core/tool/ToolExecutionStream.ts +14 -5
  90. package/src/core/tool/ToolResponse.ts +7 -3
  91. package/src/core/tool/tool-types.ts +10 -5
  92. package/src/core/tool/toolResultStream.ts +19 -13
  93. package/src/core/utils/stream/SSE.ts +116 -0
  94. package/src/core/utils/types.ts +18 -3
  95. package/src/utils/index.ts +5 -0
  96. package/src/utils/json/index.ts +1 -0
@@ -2,6 +2,7 @@ import {
2
2
  ReadonlyJSONObject,
3
3
  ReadonlyJSONValue,
4
4
  } from "../../../utils/json/json-value";
5
+ import { ObjectStreamOperation } from "../../object/types";
5
6
 
6
7
  export type DataStreamChunk = {
7
8
  [K in DataStreamStreamChunkType]: {
@@ -41,6 +42,8 @@ export enum DataStreamStreamChunkType {
41
42
  RedactedReasoning = "i",
42
43
  ReasoningSignature = "j",
43
44
  File = "k",
45
+
46
+ AuiUpdateStateOperations = "aui-state",
44
47
  }
45
48
  type DataStreamStreamChunkValue = {
46
49
  [DataStreamStreamChunkType.TextDelta]: string;
@@ -90,4 +93,7 @@ type DataStreamStreamChunkValue = {
90
93
  [DataStreamStreamChunkType.RedactedReasoning]: { data: string };
91
94
  [DataStreamStreamChunkType.ReasoningSignature]: { signature: string };
92
95
  [DataStreamStreamChunkType.File]: { data: string; mimeType: string };
96
+
97
+ // aui-extensions
98
+ [DataStreamStreamChunkType.AuiUpdateStateOperations]: ObjectStreamOperation[];
93
99
  };
@@ -8,18 +8,24 @@ import {
8
8
  ToolCallReader,
9
9
  ToolCallResponseReader,
10
10
  } from "./tool-types";
11
- import { TypeAtPath, TypePath } from "./type-path-utils";
11
+ import { DeepPartial, TypeAtPath, TypePath } from "./type-path-utils";
12
12
  import { ToolResponse } from "./ToolResponse";
13
+ import {
14
+ asAsyncIterableStream,
15
+ AsyncIterableStream,
16
+ ReadonlyJSONObject,
17
+ ReadonlyJSONValue,
18
+ } from "../../utils";
13
19
 
14
20
  // TODO: remove dispose
15
21
 
16
- function getField<T>(obj: T, fieldPath: (string | number)[]): any {
17
- let current: any = obj;
22
+ function getField<T>(obj: T, fieldPath: (string | number)[]): unknown {
23
+ let current: unknown = obj;
18
24
  for (const key of fieldPath) {
19
25
  if (current === undefined || current === null) {
20
26
  return undefined;
21
27
  }
22
- current = current[key as string | number];
28
+ current = current[key as keyof typeof current];
23
29
  }
24
30
  return current;
25
31
  }
@@ -29,14 +35,14 @@ interface Handle {
29
35
  dispose(): void;
30
36
  }
31
37
 
32
- class GetHandle<T> implements Handle {
33
- private resolve: (value: any) => void;
38
+ class GetHandle<T, TValue> implements Handle {
39
+ private resolve: (value: TValue) => void;
34
40
  private reject: (reason: unknown) => void;
35
41
  private disposed = false;
36
42
  private fieldPath: (string | number)[];
37
43
 
38
44
  constructor(
39
- resolve: (value: any) => void,
45
+ resolve: (value: TValue) => void,
40
46
  reject: (reason: unknown) => void,
41
47
  fieldPath: (string | number)[],
42
48
  ) {
@@ -58,7 +64,7 @@ class GetHandle<T> implements Handle {
58
64
  ) {
59
65
  const value = getField(args as T, this.fieldPath);
60
66
  if (value !== undefined) {
61
- this.resolve(value);
67
+ this.resolve(value as TValue);
62
68
  this.dispose();
63
69
  }
64
70
  }
@@ -74,12 +80,12 @@ class GetHandle<T> implements Handle {
74
80
  }
75
81
 
76
82
  class StreamValuesHandle<T> implements Handle {
77
- private controller: ReadableStreamDefaultController<any>;
83
+ private controller: ReadableStreamDefaultController<unknown>;
78
84
  private disposed = false;
79
85
  private fieldPath: (string | number)[];
80
86
 
81
87
  constructor(
82
- controller: ReadableStreamDefaultController<any>,
88
+ controller: ReadableStreamDefaultController<unknown>,
83
89
  fieldPath: (string | number)[],
84
90
  ) {
85
91
  this.controller = controller;
@@ -118,13 +124,13 @@ class StreamValuesHandle<T> implements Handle {
118
124
  }
119
125
 
120
126
  class StreamTextHandle<T> implements Handle {
121
- private controller: ReadableStreamDefaultController<any>;
127
+ private controller: ReadableStreamDefaultController<unknown>;
122
128
  private disposed = false;
123
129
  private fieldPath: (string | number)[];
124
- private lastValue: any = undefined;
130
+ private lastValue: string | undefined = undefined;
125
131
 
126
132
  constructor(
127
- controller: ReadableStreamDefaultController<any>,
133
+ controller: ReadableStreamDefaultController<unknown>,
128
134
  fieldPath: (string | number)[],
129
135
  ) {
130
136
  this.controller = controller;
@@ -165,13 +171,13 @@ class StreamTextHandle<T> implements Handle {
165
171
  }
166
172
 
167
173
  class ForEachHandle<T> implements Handle {
168
- private controller: ReadableStreamDefaultController<any>;
174
+ private controller: ReadableStreamDefaultController<unknown>;
169
175
  private disposed = false;
170
176
  private fieldPath: (string | number)[];
171
177
  private processedIndexes = new Set<number>();
172
178
 
173
179
  constructor(
174
- controller: ReadableStreamDefaultController<any>,
180
+ controller: ReadableStreamDefaultController<unknown>,
175
181
  fieldPath: (string | number)[],
176
182
  ) {
177
183
  this.controller = controller;
@@ -182,7 +188,7 @@ class ForEachHandle<T> implements Handle {
182
188
  if (this.disposed) return;
183
189
 
184
190
  try {
185
- const array = getField(args as T, this.fieldPath) as unknown as any[];
191
+ const array = getField(args as T, this.fieldPath);
186
192
 
187
193
  if (!Array.isArray(array)) {
188
194
  return;
@@ -226,10 +232,12 @@ class ForEachHandle<T> implements Handle {
226
232
  }
227
233
 
228
234
  // Implementation of ToolCallReader that uses stream of partial JSON
229
- export class ToolCallArgsReaderImpl<T> implements ToolCallArgsReader<T> {
235
+ export class ToolCallArgsReaderImpl<T extends ReadonlyJSONObject>
236
+ implements ToolCallArgsReader<T>
237
+ {
230
238
  private argTextDeltas: ReadableStream<string>;
231
239
  private handles: Set<Handle> = new Set();
232
- private args: any = parsePartialJsonObject("");
240
+ private args: unknown = parsePartialJsonObject("");
233
241
 
234
242
  constructor(argTextDeltas: ReadableStream<string>) {
235
243
  this.argTextDeltas = argTextDeltas;
@@ -268,8 +276,12 @@ export class ToolCallArgsReaderImpl<T> implements ToolCallArgsReader<T> {
268
276
  get<PathT extends TypePath<T>>(
269
277
  ...fieldPath: PathT
270
278
  ): Promise<TypeAtPath<T, PathT>> {
271
- return new Promise<any>((resolve, reject) => {
272
- const handle = new GetHandle<T>(resolve, reject, fieldPath);
279
+ return new Promise<TypeAtPath<T, PathT>>((resolve, reject) => {
280
+ const handle = new GetHandle<T, TypeAtPath<T, PathT>>(
281
+ resolve,
282
+ reject,
283
+ fieldPath,
284
+ );
273
285
 
274
286
  // Check if the field is already complete in current args
275
287
  if (
@@ -281,7 +293,7 @@ export class ToolCallArgsReaderImpl<T> implements ToolCallArgsReader<T> {
281
293
  ) {
282
294
  const value = getField(this.args as T, fieldPath);
283
295
  if (value !== undefined) {
284
- resolve(value);
296
+ resolve(value as TypeAtPath<T, PathT>);
285
297
  return;
286
298
  }
287
299
  }
@@ -291,11 +303,13 @@ export class ToolCallArgsReaderImpl<T> implements ToolCallArgsReader<T> {
291
303
  });
292
304
  }
293
305
 
294
- streamValues<PathT extends TypePath<T>>(...fieldPath: PathT): any {
306
+ streamValues<PathT extends TypePath<T>>(
307
+ ...fieldPath: PathT
308
+ ): AsyncIterableStream<DeepPartial<TypeAtPath<T, PathT>>> {
295
309
  // Use a type assertion to convert the complex TypePath to a simple array
296
310
  const simplePath = fieldPath as unknown as (string | number)[];
297
311
 
298
- const stream = new ReadableStream<any>({
312
+ const stream = new ReadableStream<DeepPartial<TypeAtPath<T, PathT>>>({
299
313
  start: (controller) => {
300
314
  const handle = new StreamValuesHandle<T>(controller, simplePath);
301
315
  this.handles.add(handle);
@@ -315,15 +329,18 @@ export class ToolCallArgsReaderImpl<T> implements ToolCallArgsReader<T> {
315
329
  },
316
330
  });
317
331
 
318
- // For type compatibility, cast the stream to the required type
319
- return stream as any;
332
+ return asAsyncIterableStream(stream) as any;
320
333
  }
321
334
 
322
- streamText<PathT extends TypePath<T>>(...fieldPath: PathT): any {
335
+ streamText<PathT extends TypePath<T>>(
336
+ ...fieldPath: PathT
337
+ ): TypeAtPath<T, PathT> extends string & infer U
338
+ ? AsyncIterableStream<U>
339
+ : never {
323
340
  // Use a type assertion to convert the complex TypePath to a simple array
324
341
  const simplePath = fieldPath as unknown as (string | number)[];
325
342
 
326
- const stream = new ReadableStream<any>({
343
+ const stream = new ReadableStream<unknown>({
327
344
  start: (controller) => {
328
345
  const handle = new StreamTextHandle<T>(controller, simplePath);
329
346
  this.handles.add(handle);
@@ -343,15 +360,18 @@ export class ToolCallArgsReaderImpl<T> implements ToolCallArgsReader<T> {
343
360
  },
344
361
  });
345
362
 
346
- // For type compatibility, cast the stream to the required type
347
- return stream as any;
363
+ return asAsyncIterableStream(stream) as any;
348
364
  }
349
365
 
350
- forEach<PathT extends TypePath<T>>(...fieldPath: PathT): any {
366
+ forEach<PathT extends TypePath<T>>(
367
+ ...fieldPath: PathT
368
+ ): TypeAtPath<T, PathT> extends Array<infer U>
369
+ ? AsyncIterableStream<U>
370
+ : never {
351
371
  // Use a type assertion to convert the complex TypePath to a simple array
352
372
  const simplePath = fieldPath as unknown as (string | number)[];
353
373
 
354
- const stream = new ReadableStream<any>({
374
+ const stream = new ReadableStream<unknown>({
355
375
  start: (controller) => {
356
376
  const handle = new ForEachHandle<T>(controller, simplePath);
357
377
  this.handles.add(handle);
@@ -371,12 +391,11 @@ export class ToolCallArgsReaderImpl<T> implements ToolCallArgsReader<T> {
371
391
  },
372
392
  });
373
393
 
374
- // For type compatibility, cast the stream to the required type
375
- return stream as any;
394
+ return asAsyncIterableStream(stream) as any;
376
395
  }
377
396
  }
378
397
 
379
- export class ToolCallResponseReaderImpl<TResult>
398
+ export class ToolCallResponseReaderImpl<TResult extends ReadonlyJSONValue>
380
399
  implements ToolCallResponseReader<TResult>
381
400
  {
382
401
  constructor(private readonly promise: Promise<ToolResponse<TResult>>) {}
@@ -386,8 +405,10 @@ export class ToolCallResponseReaderImpl<TResult>
386
405
  }
387
406
  }
388
407
 
389
- export class ToolCallReaderImpl<TArgs, TResult>
390
- implements ToolCallReader<TArgs, TResult>
408
+ export class ToolCallReaderImpl<
409
+ TArgs extends ReadonlyJSONObject,
410
+ TResult extends ReadonlyJSONValue,
411
+ > implements ToolCallReader<TArgs, TResult>
391
412
  {
392
413
  public readonly args: ToolCallArgsReaderImpl<TArgs>;
393
414
  public readonly response: ToolCallResponseReaderImpl<TResult>;
@@ -5,7 +5,10 @@ import {
5
5
  AssistantMetaTransformStream,
6
6
  } from "../utils/stream/AssistantMetaTransformStream";
7
7
  import { PipeableTransformStream } from "../utils/stream/PipeableTransformStream";
8
- import { ReadonlyJSONValue } from "../../utils/json/json-value";
8
+ import {
9
+ ReadonlyJSONObject,
10
+ ReadonlyJSONValue,
11
+ } from "../../utils/json/json-value";
9
12
  import { ToolResponse } from "./ToolResponse";
10
13
  import { withPromiseOrValue } from "../utils/withPromiseOrValue";
11
14
  import { ToolCallReaderImpl } from "./ToolCallReader";
@@ -14,13 +17,16 @@ import { ToolCallReader } from "./tool-types";
14
17
  type ToolCallback = (toolCall: {
15
18
  toolCallId: string;
16
19
  toolName: string;
17
- args: unknown;
20
+ args: ReadonlyJSONObject;
18
21
  }) =>
19
22
  | Promise<ToolResponse<ReadonlyJSONValue>>
20
23
  | ToolResponse<ReadonlyJSONValue>
21
24
  | undefined;
22
25
 
23
- type ToolStreamCallback = <TArgs, TResult>(toolCall: {
26
+ type ToolStreamCallback = <
27
+ TArgs extends ReadonlyJSONObject = ReadonlyJSONObject,
28
+ TResult extends ReadonlyJSONValue = ReadonlyJSONValue,
29
+ >(toolCall: {
24
30
  reader: ToolCallReader<TArgs, TResult>;
25
31
  toolCallId: string;
26
32
  toolName: string;
@@ -39,7 +45,7 @@ export class ToolExecutionStream extends PipeableTransformStream<
39
45
  const toolCallPromises = new Map<string, PromiseLike<void>>();
40
46
  const toolCallControllers = new Map<
41
47
  string,
42
- ToolCallReaderImpl<unknown, unknown>
48
+ ToolCallReaderImpl<ReadonlyJSONObject, ReadonlyJSONValue>
43
49
  >();
44
50
 
45
51
  super((readable) => {
@@ -58,7 +64,10 @@ export class ToolExecutionStream extends PipeableTransformStream<
58
64
  switch (type) {
59
65
  case "part-start":
60
66
  if (chunk.part.type === "tool-call") {
61
- const reader = new ToolCallReaderImpl<unknown, unknown>();
67
+ const reader = new ToolCallReaderImpl<
68
+ ReadonlyJSONObject,
69
+ ReadonlyJSONValue
70
+ >();
62
71
  toolCallControllers.set(chunk.part.toolCallId, reader);
63
72
 
64
73
  options.streamCall({
@@ -13,17 +13,21 @@ export class ToolResponse<TResult> {
13
13
  return true;
14
14
  }
15
15
 
16
- readonly artifact?: ReadonlyJSONValue | undefined;
16
+ readonly artifact?: ReadonlyJSONValue;
17
17
  readonly result: TResult;
18
18
  readonly isError: boolean;
19
19
 
20
20
  constructor(options: ToolResponseInit<TResult>) {
21
- this.artifact = options.artifact;
21
+ if (options.artifact !== undefined) {
22
+ this.artifact = options.artifact;
23
+ }
22
24
  this.result = options.result;
23
25
  this.isError = options.isError ?? false;
24
26
  }
25
27
 
26
- static [Symbol.hasInstance](obj: unknown): obj is ToolResponse<unknown> {
28
+ static [Symbol.hasInstance](
29
+ obj: unknown,
30
+ ): obj is ToolResponse<ReadonlyJSONValue> {
27
31
  return (
28
32
  typeof obj === "object" && obj !== null && TOOL_RESPONSE_SYMBOL in obj
29
33
  );
@@ -1,6 +1,5 @@
1
1
  import { JSONSchema7 } from "json-schema";
2
- import { TypeAtPath, TypePath } from "./type-path-utils";
3
- import { DeepPartial } from "ai";
2
+ import { DeepPartial, TypeAtPath, TypePath } from "./type-path-utils";
4
3
  import { AsyncIterableStream } from "../../utils";
5
4
  import type { StandardSchemaV1 } from "@standard-schema/spec";
6
5
  import { ToolResponse } from "./ToolResponse";
@@ -13,7 +12,7 @@ import { ToolResponse } from "./ToolResponse";
13
12
  *
14
13
  * @template TArgs The type of arguments being read.
15
14
  */
16
- export interface ToolCallArgsReader<TArgs> {
15
+ export interface ToolCallArgsReader<TArgs extends Record<string, unknown>> {
17
16
  /**
18
17
  * Returns a promise that will resolve to the value at the given path,
19
18
  * as soon as that path is generated by the LLM.
@@ -63,7 +62,10 @@ export interface ToolCallResponseReader<TResult> {
63
62
  get: () => Promise<ToolResponse<TResult>>;
64
63
  }
65
64
 
66
- export interface ToolCallReader<TArgs, TResult> {
65
+ export interface ToolCallReader<
66
+ TArgs extends Record<string, unknown> = Record<string, unknown>,
67
+ TResult = unknown,
68
+ > {
67
69
  args: ToolCallArgsReader<TArgs>;
68
70
  response: ToolCallResponseReader<TResult>;
69
71
 
@@ -85,7 +87,10 @@ export type ToolExecuteFunction<TArgs, TResult> = (
85
87
  context: ToolExecutionContext,
86
88
  ) => TResult | Promise<TResult>;
87
89
 
88
- export type ToolStreamCallFunction<TArgs, TResult> = (
90
+ export type ToolStreamCallFunction<
91
+ TArgs extends Record<string, unknown> = Record<string, unknown>,
92
+ TResult = unknown,
93
+ > = (
89
94
  reader: ToolCallReader<TArgs, TResult>,
90
95
  context: ToolExecutionContext,
91
96
  ) => void;
@@ -3,6 +3,7 @@ import { StandardSchemaV1 } from "@standard-schema/spec";
3
3
  import { ToolResponse } from "./ToolResponse";
4
4
  import { ToolExecutionStream } from "./ToolExecutionStream";
5
5
  import { AssistantMessage } from "../utils/types";
6
+ import { ReadonlyJSONObject, ReadonlyJSONValue } from "../../utils";
6
7
 
7
8
  const isStandardSchemaV1 = (
8
9
  schema: unknown,
@@ -16,18 +17,20 @@ const isStandardSchemaV1 = (
16
17
  };
17
18
 
18
19
  function getToolResponse(
19
- tools: Record<string, Tool<any, any>> | undefined,
20
+ tools: Record<string, Tool> | undefined,
20
21
  abortSignal: AbortSignal,
21
22
  toolCall: {
22
23
  toolCallId: string;
23
24
  toolName: string;
24
- args: unknown;
25
+ args: ReadonlyJSONObject;
25
26
  },
26
27
  ) {
27
28
  const tool = tools?.[toolCall.toolName];
28
29
  if (!tool || !tool.execute) return undefined;
29
30
 
30
- const getResult = async (toolExecute: ToolExecuteFunction<any, any>) => {
31
+ const getResult = async (
32
+ toolExecute: ToolExecuteFunction<ReadonlyJSONObject, unknown>,
33
+ ): Promise<ToolResponse<ReadonlyJSONValue>> => {
31
34
  let executeFn = toolExecute;
32
35
 
33
36
  if (isStandardSchemaV1(tool.parameters)) {
@@ -45,11 +48,12 @@ function getToolResponse(
45
48
  }
46
49
  }
47
50
 
48
- const result = await executeFn(toolCall.args, {
51
+ const result = (await executeFn(toolCall.args, {
49
52
  toolCallId: toolCall.toolCallId,
50
53
  abortSignal,
51
- });
52
- if (result instanceof ToolResponse) return result;
54
+ })) as unknown as ReadonlyJSONValue;
55
+ if (result instanceof ToolResponse)
56
+ return result as ToolResponse<ReadonlyJSONValue>;
53
57
  return new ToolResponse({
54
58
  result: result === undefined ? "<no result>" : result,
55
59
  });
@@ -58,10 +62,10 @@ function getToolResponse(
58
62
  return getResult(tool.execute);
59
63
  }
60
64
 
61
- function getToolStreamResponse<TArgs, TResult>(
62
- tools: Record<string, Tool<any, any>> | undefined,
65
+ function getToolStreamResponse(
66
+ tools: Record<string, Tool> | undefined,
63
67
  abortSignal: AbortSignal,
64
- reader: ToolCallReader<TArgs, TResult>,
68
+ reader: ToolCallReader<any, ReadonlyJSONValue>,
65
69
  context: {
66
70
  toolCallId: string;
67
71
  toolName: string;
@@ -75,7 +79,7 @@ function getToolStreamResponse<TArgs, TResult>(
75
79
 
76
80
  export async function unstable_runPendingTools(
77
81
  message: AssistantMessage,
78
- tools: Record<string, Tool<any, any>> | undefined,
82
+ tools: Record<string, Tool> | undefined,
79
83
  abortSignal: AbortSignal,
80
84
  ) {
81
85
  // TODO parallel tool calling
@@ -89,8 +93,10 @@ export async function unstable_runPendingTools(
89
93
  return {
90
94
  ...p,
91
95
  state: "result" as const,
92
- artifact: result.artifact,
93
- result: result.result,
96
+ ...(result.artifact !== undefined
97
+ ? { artifact: result.artifact }
98
+ : {}),
99
+ result: result.result as ReadonlyJSONValue,
94
100
  isError: result.isError,
95
101
  };
96
102
  }
@@ -108,7 +114,7 @@ export async function unstable_runPendingTools(
108
114
  }
109
115
 
110
116
  export function toolResultStream(
111
- tools: Record<string, Tool<any, any>> | undefined,
117
+ tools: Record<string, Tool> | undefined,
112
118
  abortSignal: AbortSignal,
113
119
  ) {
114
120
  return new ToolExecutionStream({
@@ -0,0 +1,116 @@
1
+ import { PipeableTransformStream } from "./PipeableTransformStream";
2
+ import { LineDecoderStream } from "./LineDecoderStream";
3
+
4
+ export class SSEEncoder<T> extends PipeableTransformStream<T, Uint8Array> {
5
+ static readonly headers = new Headers({
6
+ "Content-Type": "text/event-stream",
7
+ "Cache-Control": "no-cache",
8
+ Connection: "keep-alive",
9
+ });
10
+
11
+ headers = SSEEncoder.headers;
12
+
13
+ constructor() {
14
+ super((readable) =>
15
+ readable
16
+ .pipeThrough(
17
+ new TransformStream<T, string>({
18
+ transform(chunk, controller) {
19
+ controller.enqueue(`data: ${JSON.stringify(chunk)}\n\n`);
20
+ },
21
+ }),
22
+ )
23
+ .pipeThrough(new TextEncoderStream()),
24
+ );
25
+ }
26
+ }
27
+
28
+ type SSEEvent = {
29
+ event: string;
30
+ data: string;
31
+ id?: string | undefined;
32
+ retry?: number | undefined;
33
+ };
34
+
35
+ class SSEEventStream extends TransformStream<string, SSEEvent> {
36
+ constructor() {
37
+ let eventBuffer: Partial<SSEEvent> = {};
38
+ let dataLines: string[] = [];
39
+
40
+ super({
41
+ start() {
42
+ eventBuffer = {};
43
+ dataLines = [];
44
+ },
45
+ transform(line, controller) {
46
+ if (line.startsWith(":")) return; // Ignore comments
47
+
48
+ if (line === "") {
49
+ if (dataLines.length > 0) {
50
+ controller.enqueue({
51
+ event: eventBuffer.event || "message",
52
+ data: dataLines.join("\n"),
53
+ id: eventBuffer.id,
54
+ retry: eventBuffer.retry,
55
+ });
56
+ }
57
+ eventBuffer = {};
58
+ dataLines = [];
59
+ return;
60
+ }
61
+
62
+ const [field, ...rest] = line.split(":");
63
+ const value = rest.join(":").trimStart();
64
+
65
+ switch (field) {
66
+ case "event":
67
+ eventBuffer.event = value;
68
+ break;
69
+ case "data":
70
+ dataLines.push(value);
71
+ break;
72
+ case "id":
73
+ eventBuffer.id = value;
74
+ break;
75
+ case "retry":
76
+ eventBuffer.retry = Number(value);
77
+ break;
78
+ }
79
+ },
80
+ flush(controller) {
81
+ if (dataLines.length > 0) {
82
+ controller.enqueue({
83
+ event: eventBuffer.event || "message",
84
+ data: dataLines.join("\n"),
85
+ id: eventBuffer.id,
86
+ retry: eventBuffer.retry,
87
+ });
88
+ }
89
+ },
90
+ });
91
+ }
92
+ }
93
+
94
+ export class SSEDecoder<T> extends PipeableTransformStream<Uint8Array, T> {
95
+ constructor() {
96
+ super((readable) =>
97
+ readable
98
+ .pipeThrough(new TextDecoderStream())
99
+ .pipeThrough(new LineDecoderStream())
100
+ .pipeThrough(new SSEEventStream())
101
+ .pipeThrough(
102
+ new TransformStream<SSEEvent, T>({
103
+ transform(event, controller) {
104
+ switch (event.event) {
105
+ case "message":
106
+ controller.enqueue(JSON.parse(event.data));
107
+ break;
108
+ default:
109
+ throw new Error(`Unknown SSE event type: ${event.event}`);
110
+ }
111
+ },
112
+ }),
113
+ ),
114
+ );
115
+ }
116
+ }
@@ -50,19 +50,32 @@ type ToolCallStatus =
50
50
  reason: "cancelled" | "length" | "content-filter" | "other";
51
51
  };
52
52
 
53
- export type ToolCallPart = {
53
+ type ToolCallPartBase = {
54
54
  type: "tool-call";
55
- state: "partial-call" | "call" | "result";
56
55
  status: ToolCallStatus;
57
56
  toolCallId: string;
58
57
  toolName: string;
59
58
  argsText: string;
60
59
  args: ReadonlyJSONObject;
61
- artifact?: unknown;
60
+ artifact?: ReadonlyJSONValue;
62
61
  result?: ReadonlyJSONValue;
63
62
  isError?: boolean;
64
63
  };
65
64
 
65
+ type ToolCallPartWithoutResult = ToolCallPartBase & {
66
+ state: "partial-call" | "call";
67
+ result?: undefined;
68
+ };
69
+
70
+ type ToolCallPartWithResult = ToolCallPartBase & {
71
+ state: "result";
72
+ result: ReadonlyJSONValue;
73
+ artifact?: ReadonlyJSONValue;
74
+ isError?: boolean;
75
+ };
76
+
77
+ export type ToolCallPart = ToolCallPartWithoutResult | ToolCallPartWithResult;
78
+
66
79
  export type SourcePart = {
67
80
  type: "source";
68
81
  sourceType: "url";
@@ -141,7 +154,9 @@ export type AssistantMessage = {
141
154
  * @deprecated Use `parts` instead.
142
155
  */
143
156
  content: AssistantMessagePart[];
157
+
144
158
  metadata: {
159
+ unstable_state: ReadonlyJSONValue;
145
160
  unstable_data: ReadonlyJSONValue[];
146
161
  unstable_annotations: ReadonlyJSONValue[];
147
162
  steps: AssistantMessageStepMetadata[];
@@ -0,0 +1,5 @@
1
+ export {
2
+ asAsyncIterableStream,
3
+ type AsyncIterableStream,
4
+ } from "./AsyncIterableStream";
5
+ export { type ReadonlyJSONObject, type ReadonlyJSONValue } from "./json";
@@ -0,0 +1 @@
1
+ export { type ReadonlyJSONObject, type ReadonlyJSONValue } from "./json-value";