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.
- package/dist/core/AssistantStreamChunk.d.ts +5 -1
- package/dist/core/AssistantStreamChunk.d.ts.map +1 -1
- package/dist/core/accumulators/AssistantMessageStream.d.ts.map +1 -1
- package/dist/core/accumulators/AssistantMessageStream.js +1 -0
- package/dist/core/accumulators/AssistantMessageStream.js.map +1 -1
- package/dist/core/accumulators/assistant-message-accumulator.d.ts.map +1 -1
- package/dist/core/accumulators/assistant-message-accumulator.js +19 -1
- package/dist/core/accumulators/assistant-message-accumulator.js.map +1 -1
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +9 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/modules/tool-call.d.ts.map +1 -1
- package/dist/core/modules/tool-call.js +1 -1
- package/dist/core/modules/tool-call.js.map +1 -1
- package/dist/core/object/ObjectStream.test.d.ts +2 -0
- package/dist/core/object/ObjectStream.test.d.ts.map +1 -0
- package/dist/core/object/ObjectStreamAccumulator.d.ts +11 -0
- package/dist/core/object/ObjectStreamAccumulator.d.ts.map +1 -0
- package/dist/core/object/ObjectStreamAccumulator.js +64 -0
- package/dist/core/object/ObjectStreamAccumulator.js.map +1 -0
- package/dist/core/object/ObjectStreamResponse.d.ts +13 -0
- package/dist/core/object/ObjectStreamResponse.d.ts.map +1 -0
- package/dist/core/object/ObjectStreamResponse.js +66 -0
- package/dist/core/object/ObjectStreamResponse.js.map +1 -0
- package/dist/core/object/createObjectStream.d.ts +13 -0
- package/dist/core/object/createObjectStream.d.ts.map +1 -0
- package/dist/core/object/createObjectStream.js +63 -0
- package/dist/core/object/createObjectStream.js.map +1 -0
- package/dist/core/object/types.d.ts +15 -0
- package/dist/core/object/types.d.ts.map +1 -0
- package/dist/core/object/types.js +1 -0
- package/dist/core/object/types.js.map +1 -0
- package/dist/core/serialization/PlainText.d.ts.map +1 -1
- package/dist/core/serialization/PlainText.js.map +1 -1
- package/dist/core/serialization/data-stream/DataStream.d.ts.map +1 -1
- package/dist/core/serialization/data-stream/DataStream.js +14 -0
- package/dist/core/serialization/data-stream/DataStream.js.map +1 -1
- package/dist/core/serialization/data-stream/chunk-types.d.ts +4 -1
- package/dist/core/serialization/data-stream/chunk-types.d.ts.map +1 -1
- package/dist/core/serialization/data-stream/chunk-types.js +1 -0
- package/dist/core/serialization/data-stream/chunk-types.js.map +1 -1
- package/dist/core/tool/ToolCallReader.d.ts +8 -7
- package/dist/core/tool/ToolCallReader.d.ts.map +1 -1
- package/dist/core/tool/ToolCallReader.js +11 -4
- package/dist/core/tool/ToolCallReader.js.map +1 -1
- package/dist/core/tool/ToolExecutionStream.d.ts +3 -3
- package/dist/core/tool/ToolExecutionStream.d.ts.map +1 -1
- package/dist/core/tool/ToolExecutionStream.js.map +1 -1
- package/dist/core/tool/ToolResponse.d.ts +2 -2
- package/dist/core/tool/ToolResponse.d.ts.map +1 -1
- package/dist/core/tool/ToolResponse.js +3 -1
- package/dist/core/tool/ToolResponse.js.map +1 -1
- package/dist/core/tool/tool-types.d.ts +4 -5
- package/dist/core/tool/tool-types.d.ts.map +1 -1
- package/dist/core/tool/toolResultStream.d.ts +2 -2
- package/dist/core/tool/toolResultStream.d.ts.map +1 -1
- package/dist/core/tool/toolResultStream.js +3 -2
- package/dist/core/tool/toolResultStream.js.map +1 -1
- package/dist/core/utils/stream/SSE.d.ts +10 -0
- package/dist/core/utils/stream/SSE.d.ts.map +1 -0
- package/dist/core/utils/stream/SSE.js +102 -0
- package/dist/core/utils/stream/SSE.js.map +1 -0
- package/dist/core/utils/types.d.ts +14 -3
- package/dist/core/utils/types.d.ts.map +1 -1
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/json/index.d.ts +2 -0
- package/dist/utils/json/index.d.ts.map +1 -0
- package/dist/utils/json/index.js +1 -0
- package/dist/utils/json/index.js.map +1 -0
- package/package.json +7 -7
- package/src/core/AssistantStreamChunk.ts +6 -1
- package/src/core/accumulators/AssistantMessageStream.ts +1 -0
- package/src/core/accumulators/assistant-message-accumulator.ts +25 -1
- package/src/core/index.ts +7 -0
- package/src/core/modules/tool-call.ts +3 -1
- package/src/core/object/ObjectStream.test.ts +376 -0
- package/src/core/object/ObjectStreamAccumulator.ts +80 -0
- package/src/core/object/ObjectStreamResponse.ts +81 -0
- package/src/core/object/createObjectStream.ts +87 -0
- package/src/core/object/types.ts +18 -0
- package/src/core/serialization/PlainText.ts +2 -1
- package/src/core/serialization/data-stream/DataStream.ts +16 -0
- package/src/core/serialization/data-stream/chunk-types.ts +6 -0
- package/src/core/tool/ToolCallReader.ts +57 -36
- package/src/core/tool/ToolExecutionStream.ts +14 -5
- package/src/core/tool/ToolResponse.ts +7 -3
- package/src/core/tool/tool-types.ts +10 -5
- package/src/core/tool/toolResultStream.ts +19 -13
- package/src/core/utils/stream/SSE.ts +116 -0
- package/src/core/utils/types.ts +18 -3
- package/src/utils/index.ts +5 -0
- 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)[]):
|
|
17
|
-
let current:
|
|
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
|
|
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:
|
|
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:
|
|
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<
|
|
83
|
+
private controller: ReadableStreamDefaultController<unknown>;
|
|
78
84
|
private disposed = false;
|
|
79
85
|
private fieldPath: (string | number)[];
|
|
80
86
|
|
|
81
87
|
constructor(
|
|
82
|
-
controller: ReadableStreamDefaultController<
|
|
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<
|
|
127
|
+
private controller: ReadableStreamDefaultController<unknown>;
|
|
122
128
|
private disposed = false;
|
|
123
129
|
private fieldPath: (string | number)[];
|
|
124
|
-
private lastValue:
|
|
130
|
+
private lastValue: string | undefined = undefined;
|
|
125
131
|
|
|
126
132
|
constructor(
|
|
127
|
-
controller: ReadableStreamDefaultController<
|
|
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<
|
|
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<
|
|
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)
|
|
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
|
|
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:
|
|
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<
|
|
272
|
-
const handle = new GetHandle<T
|
|
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>>(
|
|
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<
|
|
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
|
-
|
|
319
|
-
return stream as any;
|
|
332
|
+
return asAsyncIterableStream(stream) as any;
|
|
320
333
|
}
|
|
321
334
|
|
|
322
|
-
streamText<PathT extends TypePath<T>>(
|
|
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<
|
|
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
|
-
|
|
347
|
-
return stream as any;
|
|
363
|
+
return asAsyncIterableStream(stream) as any;
|
|
348
364
|
}
|
|
349
365
|
|
|
350
|
-
forEach<PathT extends TypePath<T>>(
|
|
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<
|
|
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
|
-
|
|
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<
|
|
390
|
-
|
|
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 {
|
|
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:
|
|
20
|
+
args: ReadonlyJSONObject;
|
|
18
21
|
}) =>
|
|
19
22
|
| Promise<ToolResponse<ReadonlyJSONValue>>
|
|
20
23
|
| ToolResponse<ReadonlyJSONValue>
|
|
21
24
|
| undefined;
|
|
22
25
|
|
|
23
|
-
type ToolStreamCallback = <
|
|
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<
|
|
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<
|
|
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
|
|
16
|
+
readonly artifact?: ReadonlyJSONValue;
|
|
17
17
|
readonly result: TResult;
|
|
18
18
|
readonly isError: boolean;
|
|
19
19
|
|
|
20
20
|
constructor(options: ToolResponseInit<TResult>) {
|
|
21
|
-
|
|
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](
|
|
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<
|
|
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<
|
|
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
|
|
20
|
+
tools: Record<string, Tool> | undefined,
|
|
20
21
|
abortSignal: AbortSignal,
|
|
21
22
|
toolCall: {
|
|
22
23
|
toolCallId: string;
|
|
23
24
|
toolName: string;
|
|
24
|
-
args:
|
|
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 (
|
|
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)
|
|
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
|
|
62
|
-
tools: Record<string, Tool
|
|
65
|
+
function getToolStreamResponse(
|
|
66
|
+
tools: Record<string, Tool> | undefined,
|
|
63
67
|
abortSignal: AbortSignal,
|
|
64
|
-
reader: ToolCallReader<
|
|
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
|
|
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
|
-
|
|
93
|
-
|
|
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
|
|
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
|
+
}
|
package/src/core/utils/types.ts
CHANGED
|
@@ -50,19 +50,32 @@ type ToolCallStatus =
|
|
|
50
50
|
reason: "cancelled" | "length" | "content-filter" | "other";
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
-
|
|
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?:
|
|
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 @@
|
|
|
1
|
+
export { type ReadonlyJSONObject, type ReadonlyJSONValue } from "./json-value";
|