assistant-stream 0.3.25 → 0.3.27
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/README.md +4 -1
- package/dist/core/AssistantStream.d.ts +0 -1
- package/dist/core/AssistantStream.d.ts.map +1 -1
- package/dist/core/AssistantStreamChunk.d.ts +26 -14
- package/dist/core/AssistantStreamChunk.d.ts.map +1 -1
- package/dist/core/accumulators/AssistantMessageStream.d.ts +0 -1
- package/dist/core/accumulators/AssistantMessageStream.d.ts.map +1 -1
- package/dist/core/accumulators/TimingTracker.d.ts +0 -1
- package/dist/core/accumulators/TimingTracker.d.ts.map +1 -1
- package/dist/core/accumulators/assistant-message-accumulator.d.ts +3 -9
- package/dist/core/accumulators/assistant-message-accumulator.d.ts.map +1 -1
- package/dist/core/accumulators/assistant-message-accumulator.js +70 -28
- package/dist/core/accumulators/assistant-message-accumulator.js.map +1 -1
- package/dist/core/converters/toGenericMessages.d.ts.map +1 -1
- package/dist/core/converters/toGenericMessages.js +2 -1
- package/dist/core/converters/toGenericMessages.js.map +1 -1
- package/dist/core/gorp/GorpStreamAccumulator.d.ts +15 -0
- package/dist/core/gorp/GorpStreamAccumulator.d.ts.map +1 -0
- package/dist/core/{object/ObjectStreamAccumulator.js → gorp/GorpStreamAccumulator.js} +11 -9
- package/dist/core/gorp/GorpStreamAccumulator.js.map +1 -0
- package/dist/core/gorp/GorpStreamDeltaTracker.d.ts +17 -0
- package/dist/core/gorp/GorpStreamDeltaTracker.d.ts.map +1 -0
- package/dist/core/gorp/GorpStreamDeltaTracker.js +38 -0
- package/dist/core/gorp/GorpStreamDeltaTracker.js.map +1 -0
- package/dist/core/gorp/GorpStreamResponse.d.ts +16 -0
- package/dist/core/gorp/GorpStreamResponse.d.ts.map +1 -0
- package/dist/core/gorp/GorpStreamResponse.js +51 -0
- package/dist/core/gorp/GorpStreamResponse.js.map +1 -0
- package/dist/core/gorp/changeTree.d.ts +16 -0
- package/dist/core/gorp/changeTree.d.ts.map +1 -0
- package/dist/core/gorp/changeTree.js +77 -0
- package/dist/core/gorp/changeTree.js.map +1 -0
- package/dist/core/gorp/createGorpStream.d.ts +16 -0
- package/dist/core/gorp/createGorpStream.d.ts.map +1 -0
- package/dist/core/{object/createObjectStream.js → gorp/createGorpStream.js} +13 -8
- package/dist/core/gorp/createGorpStream.js.map +1 -0
- package/dist/core/gorp/types.d.ts +20 -0
- package/dist/core/gorp/types.d.ts.map +1 -0
- package/dist/core/modules/assistant-stream.d.ts +18 -11
- package/dist/core/modules/assistant-stream.d.ts.map +1 -1
- package/dist/core/modules/assistant-stream.js +10 -6
- package/dist/core/modules/assistant-stream.js.map +1 -1
- package/dist/core/modules/text.d.ts +0 -1
- package/dist/core/modules/text.d.ts.map +1 -1
- package/dist/core/modules/tool-call.d.ts +0 -1
- package/dist/core/modules/tool-call.d.ts.map +1 -1
- package/dist/core/modules/tool-call.js +2 -2
- package/dist/core/modules/tool-call.js.map +1 -1
- package/dist/core/serialization/PlainText.d.ts +0 -1
- package/dist/core/serialization/PlainText.d.ts.map +1 -1
- package/dist/core/serialization/assistant-transport/AssistantTransport.d.ts +0 -1
- package/dist/core/serialization/assistant-transport/AssistantTransport.d.ts.map +1 -1
- package/dist/core/serialization/assistant-transport/AssistantTransport.js +93 -53
- package/dist/core/serialization/assistant-transport/AssistantTransport.js.map +1 -1
- package/dist/core/serialization/data-stream/DataStream.d.ts +0 -1
- package/dist/core/serialization/data-stream/DataStream.d.ts.map +1 -1
- package/dist/core/serialization/data-stream/chunk-types.d.ts +3 -4
- package/dist/core/serialization/data-stream/chunk-types.d.ts.map +1 -1
- package/dist/core/serialization/data-stream/chunk-types.js.map +1 -1
- package/dist/core/serialization/data-stream/serialization.d.ts +0 -1
- package/dist/core/serialization/data-stream/serialization.d.ts.map +1 -1
- package/dist/core/serialization/ui-message-stream/UIMessageStream.d.ts +0 -1
- package/dist/core/serialization/ui-message-stream/UIMessageStream.d.ts.map +1 -1
- package/dist/core/serialization/ui-message-stream/UIMessageStream.js +76 -53
- package/dist/core/serialization/ui-message-stream/UIMessageStream.js.map +1 -1
- package/dist/core/serialization/ui-message-stream/chunk-types.d.ts +0 -1
- package/dist/core/serialization/ui-message-stream/chunk-types.d.ts.map +1 -1
- package/dist/core/tool/ToolCallReader.d.ts +1 -0
- package/dist/core/tool/ToolCallReader.d.ts.map +1 -1
- package/dist/core/tool/ToolCallReader.js.map +1 -1
- package/dist/core/tool/ToolExecutionStream.d.ts +0 -1
- package/dist/core/tool/ToolExecutionStream.d.ts.map +1 -1
- package/dist/core/tool/ToolExecutionStream.js +9 -1
- package/dist/core/tool/ToolExecutionStream.js.map +1 -1
- package/dist/core/tool/ToolResponse.d.ts +6 -4
- package/dist/core/tool/ToolResponse.d.ts.map +1 -1
- package/dist/core/tool/schema-utils.d.ts +0 -1
- package/dist/core/tool/schema-utils.d.ts.map +1 -1
- package/dist/core/tool/tool-types.d.ts +71 -33
- package/dist/core/tool/tool-types.d.ts.map +1 -1
- package/dist/core/tool/toolResultStream.d.ts +3 -2
- package/dist/core/tool/toolResultStream.d.ts.map +1 -1
- package/dist/core/tool/toolResultStream.js +7 -2
- package/dist/core/tool/toolResultStream.js.map +1 -1
- package/dist/core/tool/type-path-utils.d.ts +2 -2
- package/dist/core/tool/type-path-utils.d.ts.map +1 -1
- package/dist/core/utils/Counter.d.ts.map +1 -1
- package/dist/core/utils/generateId.d.ts.map +1 -1
- package/dist/core/utils/stream/AssistantMetaTransformStream.d.ts +0 -1
- package/dist/core/utils/stream/AssistantMetaTransformStream.d.ts.map +1 -1
- package/dist/core/utils/stream/AssistantTransformStream.d.ts +0 -1
- package/dist/core/utils/stream/AssistantTransformStream.d.ts.map +1 -1
- package/dist/core/utils/stream/LineDecoderStream.d.ts +1 -0
- package/dist/core/utils/stream/LineDecoderStream.d.ts.map +1 -1
- package/dist/core/utils/stream/LineDecoderStream.js +19 -6
- package/dist/core/utils/stream/LineDecoderStream.js.map +1 -1
- package/dist/core/utils/stream/PipeableTransformStream.d.ts.map +1 -1
- package/dist/core/utils/stream/SSE.d.ts +0 -1
- package/dist/core/utils/stream/SSE.d.ts.map +1 -1
- package/dist/core/utils/stream/SSE.js +2 -52
- package/dist/core/utils/stream/SSE.js.map +1 -1
- package/dist/core/utils/stream/SSEEventDecoder.d.ts +27 -0
- package/dist/core/utils/stream/SSEEventDecoder.d.ts.map +1 -0
- package/dist/core/utils/stream/SSEEventDecoder.js +84 -0
- package/dist/core/utils/stream/SSEEventDecoder.js.map +1 -0
- package/dist/core/utils/stream/SSEEventDecoderStream.d.ts +13 -0
- package/dist/core/utils/stream/SSEEventDecoderStream.d.ts.map +1 -0
- package/dist/core/utils/stream/SSEEventDecoderStream.js +24 -0
- package/dist/core/utils/stream/SSEEventDecoderStream.js.map +1 -0
- package/dist/core/utils/stream/UnderlyingReadable.d.ts.map +1 -1
- package/dist/core/utils/stream/merge.d.ts +2 -1
- package/dist/core/utils/stream/merge.d.ts.map +1 -1
- package/dist/core/utils/stream/merge.js +27 -8
- package/dist/core/utils/stream/merge.js.map +1 -1
- package/dist/core/utils/stream/path-utils.d.ts +0 -1
- package/dist/core/utils/stream/path-utils.d.ts.map +1 -1
- package/dist/core/utils/types.d.ts +16 -8
- package/dist/core/utils/types.d.ts.map +1 -1
- package/dist/core/utils/withPromiseOrValue.d.ts.map +1 -1
- package/dist/index.d.ts +25 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -3
- package/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts +3 -3
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts.map +1 -1
- package/dist/resumable/ResumableStreamContext.d.ts +0 -1
- package/dist/resumable/ResumableStreamContext.d.ts.map +1 -1
- package/dist/resumable/ResumableStreamContext.js +12 -5
- package/dist/resumable/ResumableStreamContext.js.map +1 -1
- package/dist/resumable/constants.d.ts.map +1 -1
- package/dist/resumable/createResumableAssistantStreamResponse.d.ts +6 -4
- package/dist/resumable/createResumableAssistantStreamResponse.d.ts.map +1 -1
- package/dist/resumable/errors.d.ts.map +1 -1
- package/dist/resumable/stores/InMemoryResumableStreamStore.d.ts +0 -1
- package/dist/resumable/stores/InMemoryResumableStreamStore.d.ts.map +1 -1
- package/dist/resumable/stores/InMemoryResumableStreamStore.js +2 -1
- package/dist/resumable/stores/InMemoryResumableStreamStore.js.map +1 -1
- package/dist/resumable/stores/ioredis.d.ts +0 -1
- package/dist/resumable/stores/ioredis.d.ts.map +1 -1
- package/dist/resumable/stores/redis-impl.d.ts +2 -2
- package/dist/resumable/stores/redis-impl.d.ts.map +1 -1
- package/dist/resumable/stores/redis.d.ts +0 -1
- package/dist/resumable/stores/redis.d.ts.map +1 -1
- package/dist/resumable/types.d.ts.map +1 -1
- package/dist/utils/AsyncIterableStream.d.ts.map +1 -1
- package/dist/utils/AsyncIterableStream.js +18 -3
- package/dist/utils/AsyncIterableStream.js.map +1 -1
- package/dist/utils/json/fix-json.d.ts.map +1 -1
- package/dist/utils/json/json-value.d.ts.map +1 -1
- package/dist/utils/json/parse-partial-json-object.d.ts +0 -1
- package/dist/utils/json/parse-partial-json-object.d.ts.map +1 -1
- package/dist/utils/promiseWithResolvers.d.ts.map +1 -1
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +2 -1
- package/package.json +5 -5
- package/src/core/AssistantStreamChunk.ts +5 -3
- package/src/core/accumulators/assistant-message-accumulator.test.ts +437 -1
- package/src/core/accumulators/assistant-message-accumulator.ts +89 -26
- package/src/core/{object/ObjectStream.test.ts → gorp/GorpStream.test.ts} +104 -23
- package/src/core/gorp/GorpStreamAccumulator.test.ts +28 -0
- package/src/core/{object/ObjectStreamAccumulator.ts → gorp/GorpStreamAccumulator.ts} +13 -15
- package/src/core/gorp/GorpStreamDeltaTracker.test.ts +182 -0
- package/src/core/gorp/GorpStreamDeltaTracker.ts +55 -0
- package/src/core/gorp/GorpStreamResponse.test.ts +32 -0
- package/src/core/gorp/GorpStreamResponse.ts +88 -0
- package/src/core/gorp/changeTree.test.ts +168 -0
- package/src/core/gorp/changeTree.ts +96 -0
- package/src/core/{object/createObjectStream.ts → gorp/createGorpStream.ts} +23 -17
- package/src/core/{object → gorp}/types.ts +5 -3
- package/src/core/modules/assistant-stream.test.ts +154 -2
- package/src/core/modules/assistant-stream.ts +16 -6
- package/src/core/modules/tool-call.test.ts +67 -0
- package/src/core/modules/tool-call.ts +3 -3
- package/src/core/serialization/assistant-transport/AssistantTransport.test.ts +215 -1
- package/src/core/serialization/assistant-transport/AssistantTransport.ts +83 -71
- package/src/core/serialization/data-stream/chunk-types.ts +2 -2
- package/src/core/serialization/ui-message-stream/UIMessageStream.test.ts +323 -4
- package/src/core/serialization/ui-message-stream/UIMessageStream.ts +81 -71
- package/src/core/tool/ToolExecutionStream.ts +10 -0
- package/src/core/tool/toolResultStream.test.ts +50 -0
- package/src/core/tool/toolResultStream.ts +7 -2
- package/src/core/utils/stream/LineDecoderStream.test.ts +26 -2
- package/src/core/utils/stream/LineDecoderStream.ts +21 -11
- package/src/core/utils/stream/SSE.ts +6 -70
- package/src/core/utils/stream/SSEEventDecoder.test.ts +146 -0
- package/src/core/utils/stream/SSEEventDecoder.ts +109 -0
- package/src/core/utils/stream/SSEEventDecoderStream.test.ts +42 -0
- package/src/core/utils/stream/SSEEventDecoderStream.ts +34 -0
- package/src/core/utils/stream/merge.ts +31 -9
- package/src/gorp.test.ts +42 -0
- package/src/index.ts +21 -6
- package/src/resumable/ResumableStreamContext.test.ts +116 -1
- package/src/resumable/ResumableStreamContext.ts +32 -5
- package/src/resumable/createResumableAssistantStreamResponse.test.ts +1 -25
- package/src/utils/AsyncIterableStream.test.ts +61 -0
- package/src/utils/AsyncIterableStream.ts +18 -3
- package/src/utils.ts +4 -0
- package/dist/core/object/ObjectStreamAccumulator.d.ts +0 -15
- package/dist/core/object/ObjectStreamAccumulator.d.ts.map +0 -1
- package/dist/core/object/ObjectStreamAccumulator.js.map +0 -1
- package/dist/core/object/ObjectStreamResponse.d.ts +0 -17
- package/dist/core/object/ObjectStreamResponse.d.ts.map +0 -1
- package/dist/core/object/ObjectStreamResponse.js +0 -57
- package/dist/core/object/ObjectStreamResponse.js.map +0 -1
- package/dist/core/object/createObjectStream.d.ts +0 -19
- package/dist/core/object/createObjectStream.d.ts.map +0 -1
- package/dist/core/object/createObjectStream.js.map +0 -1
- package/dist/core/object/types.d.ts +0 -18
- package/dist/core/object/types.d.ts.map +0 -1
- package/dist/utils/json/is-json.d.ts +0 -9
- package/dist/utils/json/is-json.d.ts.map +0 -1
- package/dist/utils/json/is-json.js +0 -17
- package/dist/utils/json/is-json.js.map +0 -1
- package/src/core/object/ObjectStreamResponse.ts +0 -109
- package/src/utils/json/is-json.ts +0 -43
- /package/dist/core/{object → gorp}/types.js +0 -0
|
@@ -1,58 +1,8 @@
|
|
|
1
1
|
import { AssistantTransformStream } from "../../utils/stream/AssistantTransformStream.js";
|
|
2
2
|
import { PipeableTransformStream } from "../../utils/stream/PipeableTransformStream.js";
|
|
3
|
-
import { LineDecoderStream } from "../../utils/stream/LineDecoderStream.js";
|
|
4
3
|
import { generateId } from "../../utils/generateId.js";
|
|
4
|
+
import { SSEEventDecoderStream } from "../../utils/stream/SSEEventDecoderStream.js";
|
|
5
5
|
//#region src/core/serialization/ui-message-stream/UIMessageStream.ts
|
|
6
|
-
var SSEEventStream = class extends TransformStream {
|
|
7
|
-
constructor() {
|
|
8
|
-
let eventBuffer = {};
|
|
9
|
-
let dataLines = [];
|
|
10
|
-
super({
|
|
11
|
-
start() {
|
|
12
|
-
eventBuffer = {};
|
|
13
|
-
dataLines = [];
|
|
14
|
-
},
|
|
15
|
-
transform(line, controller) {
|
|
16
|
-
if (line.startsWith(":")) return;
|
|
17
|
-
if (line === "") {
|
|
18
|
-
if (dataLines.length > 0) controller.enqueue({
|
|
19
|
-
event: eventBuffer.event || "message",
|
|
20
|
-
data: dataLines.join("\n"),
|
|
21
|
-
id: eventBuffer.id,
|
|
22
|
-
retry: eventBuffer.retry
|
|
23
|
-
});
|
|
24
|
-
eventBuffer = {};
|
|
25
|
-
dataLines = [];
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const [field, ...rest] = line.split(":");
|
|
29
|
-
const value = rest.join(":").trimStart();
|
|
30
|
-
switch (field) {
|
|
31
|
-
case "event":
|
|
32
|
-
eventBuffer.event = value;
|
|
33
|
-
break;
|
|
34
|
-
case "data":
|
|
35
|
-
dataLines.push(value);
|
|
36
|
-
break;
|
|
37
|
-
case "id":
|
|
38
|
-
eventBuffer.id = value;
|
|
39
|
-
break;
|
|
40
|
-
case "retry":
|
|
41
|
-
eventBuffer.retry = Number(value);
|
|
42
|
-
break;
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
flush(controller) {
|
|
46
|
-
if (dataLines.length > 0) controller.enqueue({
|
|
47
|
-
event: eventBuffer.event || "message",
|
|
48
|
-
data: dataLines.join("\n"),
|
|
49
|
-
id: eventBuffer.id,
|
|
50
|
-
retry: eventBuffer.retry
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
6
|
const isDataChunk = (chunk) => chunk.type.startsWith("data-");
|
|
57
7
|
/**
|
|
58
8
|
* Decodes AI SDK v6 UI Message Stream format into AssistantStreamChunks.
|
|
@@ -142,6 +92,7 @@ var UIMessageStreamDecoder = class extends PipeableTransformStream {
|
|
|
142
92
|
case "tool-result": {
|
|
143
93
|
const toolCallController = toolCallControllers.get(chunk.toolCallId);
|
|
144
94
|
if (!toolCallController) throw new Error(`Encountered tool result with unknown id: ${chunk.toolCallId}`);
|
|
95
|
+
if (toolCallController.argsText === activeToolCallArgsText) activeToolCallArgsText = void 0;
|
|
145
96
|
toolCallController.setResponse({
|
|
146
97
|
result: chunk.result,
|
|
147
98
|
isError: chunk.isError ?? false,
|
|
@@ -189,7 +140,7 @@ var UIMessageStreamDecoder = class extends PipeableTransformStream {
|
|
|
189
140
|
toolCallControllers.clear();
|
|
190
141
|
}
|
|
191
142
|
});
|
|
192
|
-
return readable.pipeThrough(new TextDecoderStream()).pipeThrough(new
|
|
143
|
+
return readable.pipeThrough(new TextDecoderStream()).pipeThrough(new SSEEventDecoderStream()).pipeThrough(new TransformStream({
|
|
193
144
|
transform(event, controller) {
|
|
194
145
|
if (event.event !== "message") throw new Error(`Unknown SSE event type: ${event.event}`);
|
|
195
146
|
if (event.data === "[DONE]") {
|
|
@@ -197,7 +148,79 @@ var UIMessageStreamDecoder = class extends PipeableTransformStream {
|
|
|
197
148
|
controller.terminate();
|
|
198
149
|
return;
|
|
199
150
|
}
|
|
200
|
-
|
|
151
|
+
let chunk;
|
|
152
|
+
try {
|
|
153
|
+
chunk = JSON.parse(event.data);
|
|
154
|
+
} catch {
|
|
155
|
+
chunk = void 0;
|
|
156
|
+
}
|
|
157
|
+
if (typeof chunk !== "object" || chunk === null || Array.isArray(chunk) || typeof chunk.type !== "string") {
|
|
158
|
+
console.warn(`Dropped invalid UIMessageStream chunk: ${event.data.slice(0, 200)}`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (chunk.type === "text-delta" && chunk.textDelta === void 0) {
|
|
162
|
+
const { delta, ...rest } = chunk;
|
|
163
|
+
controller.enqueue({
|
|
164
|
+
...rest,
|
|
165
|
+
textDelta: delta ?? ""
|
|
166
|
+
});
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (chunk.type === "start") {
|
|
170
|
+
controller.enqueue({
|
|
171
|
+
...chunk,
|
|
172
|
+
messageId: chunk.messageId ?? generateId()
|
|
173
|
+
});
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (chunk.type === "source-url") {
|
|
177
|
+
controller.enqueue({
|
|
178
|
+
type: "source",
|
|
179
|
+
source: {
|
|
180
|
+
sourceType: "url",
|
|
181
|
+
id: chunk.sourceId,
|
|
182
|
+
url: chunk.url,
|
|
183
|
+
...chunk.title && { title: chunk.title }
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (chunk.type === "source" && chunk.source == null) return;
|
|
189
|
+
if (chunk.type === "file" && chunk.file == null) {
|
|
190
|
+
if (chunk.url === void 0) return;
|
|
191
|
+
controller.enqueue({
|
|
192
|
+
type: "file",
|
|
193
|
+
file: {
|
|
194
|
+
mimeType: chunk.mediaType,
|
|
195
|
+
data: chunk.url
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (chunk.type === "finish-step") {
|
|
201
|
+
controller.enqueue({
|
|
202
|
+
...chunk,
|
|
203
|
+
finishReason: chunk.finishReason ?? "unknown",
|
|
204
|
+
usage: chunk.usage ?? {
|
|
205
|
+
inputTokens: 0,
|
|
206
|
+
outputTokens: 0
|
|
207
|
+
},
|
|
208
|
+
isContinued: chunk.isContinued ?? false
|
|
209
|
+
});
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (chunk.type === "finish") {
|
|
213
|
+
controller.enqueue({
|
|
214
|
+
...chunk,
|
|
215
|
+
finishReason: chunk.finishReason ?? "unknown",
|
|
216
|
+
usage: chunk.usage ?? {
|
|
217
|
+
inputTokens: 0,
|
|
218
|
+
outputTokens: 0
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
controller.enqueue(chunk);
|
|
201
224
|
},
|
|
202
225
|
flush() {
|
|
203
226
|
if (!receivedDone) throw new Error("Stream ended abruptly without receiving [DONE] marker");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UIMessageStream.js","names":[],"sources":["../../../../src/core/serialization/ui-message-stream/UIMessageStream.ts"],"sourcesContent":["import type { AssistantStreamChunk } from \"../../AssistantStreamChunk\";\nimport type { ToolCallStreamController } from \"../../modules/tool-call\";\nimport type { TextStreamController } from \"../../modules/text\";\nimport { AssistantTransformStream } from \"../../utils/stream/AssistantTransformStream\";\nimport { PipeableTransformStream } from \"../../utils/stream/PipeableTransformStream\";\nimport { LineDecoderStream } from \"../../utils/stream/LineDecoderStream\";\nimport type {\n UIMessageStreamChunk,\n UIMessageStreamDataChunk,\n} from \"./chunk-types\";\nimport { generateId } from \"../../utils/generateId\";\n\nexport type { UIMessageStreamChunk, UIMessageStreamDataChunk };\n\nexport type UIMessageStreamDecoderOptions = {\n onData?: (data: {\n type: string;\n name: string;\n data: unknown;\n transient?: boolean;\n }) => void;\n};\n\ntype SSEEvent = {\n event: string;\n data: string;\n id?: string | undefined;\n retry?: number | undefined;\n};\n\nclass SSEEventStream extends TransformStream<string, SSEEvent> {\n constructor() {\n let eventBuffer: Partial<SSEEvent> = {};\n let dataLines: string[] = [];\n\n super({\n start() {\n eventBuffer = {};\n dataLines = [];\n },\n transform(line, controller) {\n if (line.startsWith(\":\")) return;\n\n if (line === \"\") {\n if (dataLines.length > 0) {\n controller.enqueue({\n event: eventBuffer.event || \"message\",\n data: dataLines.join(\"\\n\"),\n id: eventBuffer.id,\n retry: eventBuffer.retry,\n });\n }\n eventBuffer = {};\n dataLines = [];\n return;\n }\n\n const [field, ...rest] = line.split(\":\");\n const value = rest.join(\":\").trimStart();\n\n switch (field) {\n case \"event\":\n eventBuffer.event = value;\n break;\n case \"data\":\n dataLines.push(value);\n break;\n case \"id\":\n eventBuffer.id = value;\n break;\n case \"retry\":\n eventBuffer.retry = Number(value);\n break;\n }\n },\n flush(controller) {\n if (dataLines.length > 0) {\n controller.enqueue({\n event: eventBuffer.event || \"message\",\n data: dataLines.join(\"\\n\"),\n id: eventBuffer.id,\n retry: eventBuffer.retry,\n });\n }\n },\n });\n }\n}\n\nconst isDataChunk = (\n chunk: UIMessageStreamChunk,\n): chunk is UIMessageStreamDataChunk => chunk.type.startsWith(\"data-\");\n\n/**\n * Decodes AI SDK v6 UI Message Stream format into AssistantStreamChunks.\n */\nexport class UIMessageStreamDecoder extends PipeableTransformStream<\n Uint8Array<ArrayBuffer>,\n AssistantStreamChunk\n> {\n constructor(options: UIMessageStreamDecoderOptions = {}) {\n super((readable) => {\n const toolCallControllers = new Map<string, ToolCallStreamController>();\n let activeToolCallArgsText: TextStreamController | undefined;\n let currentMessageId: string | undefined;\n let receivedDone = false;\n\n const transform = new AssistantTransformStream<UIMessageStreamChunk>({\n transform(chunk, controller) {\n const type = chunk.type;\n\n if (isDataChunk(chunk)) {\n const name = chunk.type.slice(5);\n\n if (options.onData) {\n options.onData({\n type: chunk.type,\n name,\n data: chunk.data,\n ...(chunk.transient !== undefined && {\n transient: chunk.transient,\n }),\n });\n }\n\n if (!chunk.transient) {\n controller.enqueue({\n type: \"data\",\n path: [],\n data: [{ name, data: chunk.data }],\n });\n }\n return;\n }\n\n switch (type) {\n case \"start\":\n currentMessageId = chunk.messageId;\n controller.enqueue({\n type: \"step-start\",\n path: [],\n messageId: chunk.messageId,\n });\n break;\n\n case \"text-start\":\n case \"text-end\":\n case \"reasoning-start\":\n case \"reasoning-end\":\n break;\n\n case \"text-delta\":\n controller.appendText(chunk.textDelta);\n break;\n\n case \"reasoning-delta\":\n controller.appendReasoning(chunk.delta);\n break;\n\n case \"source\":\n controller.appendSource({\n type: \"source\",\n sourceType: chunk.source.sourceType,\n id: chunk.source.id,\n url: chunk.source.url,\n ...(chunk.source.title && { title: chunk.source.title }),\n });\n break;\n\n case \"file\":\n controller.appendFile({\n type: \"file\",\n mimeType: chunk.file.mimeType,\n data: chunk.file.data,\n });\n break;\n\n case \"tool-call-start\": {\n activeToolCallArgsText?.close();\n activeToolCallArgsText = undefined;\n\n if (toolCallControllers.has(chunk.toolCallId)) {\n throw new Error(\n `Encountered duplicate tool call id: ${chunk.toolCallId}`,\n );\n }\n\n const toolCallController = controller.addToolCallPart({\n toolCallId: chunk.toolCallId,\n toolName: chunk.toolName,\n });\n toolCallControllers.set(chunk.toolCallId, toolCallController);\n activeToolCallArgsText = toolCallController.argsText;\n break;\n }\n\n case \"tool-call-delta\":\n activeToolCallArgsText?.append(chunk.argsText);\n break;\n\n case \"tool-call-end\":\n activeToolCallArgsText?.close();\n activeToolCallArgsText = undefined;\n break;\n\n case \"tool-result\": {\n const toolCallController = toolCallControllers.get(\n chunk.toolCallId,\n );\n if (!toolCallController) {\n throw new Error(\n `Encountered tool result with unknown id: ${chunk.toolCallId}`,\n );\n }\n toolCallController.setResponse({\n result: chunk.result,\n isError: chunk.isError ?? false,\n ...(chunk.messages !== undefined\n ? { messages: chunk.messages }\n : {}),\n });\n break;\n }\n\n case \"start-step\":\n controller.enqueue({\n type: \"step-start\",\n path: [],\n messageId: chunk.messageId ?? currentMessageId ?? generateId(),\n });\n break;\n\n case \"finish-step\":\n controller.enqueue({\n type: \"step-finish\",\n path: [],\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n isContinued: chunk.isContinued,\n });\n break;\n\n case \"finish\":\n controller.enqueue({\n type: \"message-finish\",\n path: [],\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n });\n break;\n\n case \"error\":\n controller.enqueue({\n type: \"error\",\n path: [],\n error: chunk.errorText,\n });\n break;\n\n default:\n // ignore unknown types for forward compatibility\n break;\n }\n },\n flush() {\n activeToolCallArgsText?.close();\n toolCallControllers.forEach((ctrl) => ctrl.close());\n toolCallControllers.clear();\n },\n });\n\n return readable\n .pipeThrough(new TextDecoderStream())\n .pipeThrough(new LineDecoderStream())\n .pipeThrough(new SSEEventStream())\n .pipeThrough(\n new TransformStream<SSEEvent, UIMessageStreamChunk>({\n transform(event, controller) {\n if (event.event !== \"message\") {\n throw new Error(`Unknown SSE event type: ${event.event}`);\n }\n\n if (event.data === \"[DONE]\") {\n receivedDone = true;\n controller.terminate();\n return;\n }\n\n controller.enqueue(JSON.parse(event.data));\n },\n flush() {\n if (!receivedDone) {\n throw new Error(\n \"Stream ended abruptly without receiving [DONE] marker\",\n );\n }\n },\n }),\n )\n .pipeThrough(transform);\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"UIMessageStream.js","names":[],"sources":["../../../../src/core/serialization/ui-message-stream/UIMessageStream.ts"],"sourcesContent":["import type { AssistantStreamChunk } from \"../../AssistantStreamChunk\";\nimport type { ToolCallStreamController } from \"../../modules/tool-call\";\nimport type { TextStreamController } from \"../../modules/text\";\nimport { AssistantTransformStream } from \"../../utils/stream/AssistantTransformStream\";\nimport { PipeableTransformStream } from \"../../utils/stream/PipeableTransformStream\";\nimport {\n SSEEventDecoderStream,\n type PipelineSSEEvent,\n} from \"../../utils/stream/SSEEventDecoderStream\";\nimport type {\n UIMessageStreamChunk,\n UIMessageStreamDataChunk,\n} from \"./chunk-types\";\nimport { generateId } from \"../../utils/generateId\";\n\nexport type { UIMessageStreamChunk, UIMessageStreamDataChunk };\n\nexport type UIMessageStreamDecoderOptions = {\n onData?: (data: {\n type: string;\n name: string;\n data: unknown;\n transient?: boolean;\n }) => void;\n};\n\nconst isDataChunk = (\n chunk: UIMessageStreamChunk,\n): chunk is UIMessageStreamDataChunk => chunk.type.startsWith(\"data-\");\n\n/**\n * Decodes AI SDK v6 UI Message Stream format into AssistantStreamChunks.\n */\nexport class UIMessageStreamDecoder extends PipeableTransformStream<\n Uint8Array<ArrayBuffer>,\n AssistantStreamChunk\n> {\n constructor(options: UIMessageStreamDecoderOptions = {}) {\n super((readable) => {\n const toolCallControllers = new Map<string, ToolCallStreamController>();\n let activeToolCallArgsText: TextStreamController | undefined;\n let currentMessageId: string | undefined;\n let receivedDone = false;\n\n const transform = new AssistantTransformStream<UIMessageStreamChunk>({\n transform(chunk, controller) {\n const type = chunk.type;\n\n if (isDataChunk(chunk)) {\n const name = chunk.type.slice(5);\n\n if (options.onData) {\n options.onData({\n type: chunk.type,\n name,\n data: chunk.data,\n ...(chunk.transient !== undefined && {\n transient: chunk.transient,\n }),\n });\n }\n\n if (!chunk.transient) {\n controller.enqueue({\n type: \"data\",\n path: [],\n data: [{ name, data: chunk.data }],\n });\n }\n return;\n }\n\n switch (type) {\n case \"start\":\n currentMessageId = chunk.messageId;\n controller.enqueue({\n type: \"step-start\",\n path: [],\n messageId: chunk.messageId,\n });\n break;\n\n case \"text-start\":\n case \"text-end\":\n case \"reasoning-start\":\n case \"reasoning-end\":\n break;\n\n case \"text-delta\":\n controller.appendText(chunk.textDelta);\n break;\n\n case \"reasoning-delta\":\n controller.appendReasoning(chunk.delta);\n break;\n\n case \"source\":\n controller.appendSource({\n type: \"source\",\n sourceType: chunk.source.sourceType,\n id: chunk.source.id,\n url: chunk.source.url,\n ...(chunk.source.title && { title: chunk.source.title }),\n });\n break;\n\n case \"file\":\n controller.appendFile({\n type: \"file\",\n mimeType: chunk.file.mimeType,\n data: chunk.file.data,\n });\n break;\n\n case \"tool-call-start\": {\n activeToolCallArgsText?.close();\n activeToolCallArgsText = undefined;\n\n if (toolCallControllers.has(chunk.toolCallId)) {\n throw new Error(\n `Encountered duplicate tool call id: ${chunk.toolCallId}`,\n );\n }\n\n const toolCallController = controller.addToolCallPart({\n toolCallId: chunk.toolCallId,\n toolName: chunk.toolName,\n });\n toolCallControllers.set(chunk.toolCallId, toolCallController);\n activeToolCallArgsText = toolCallController.argsText;\n break;\n }\n\n case \"tool-call-delta\":\n activeToolCallArgsText?.append(chunk.argsText);\n break;\n\n case \"tool-call-end\":\n activeToolCallArgsText?.close();\n activeToolCallArgsText = undefined;\n break;\n\n case \"tool-result\": {\n const toolCallController = toolCallControllers.get(\n chunk.toolCallId,\n );\n if (!toolCallController) {\n throw new Error(\n `Encountered tool result with unknown id: ${chunk.toolCallId}`,\n );\n }\n if (toolCallController.argsText === activeToolCallArgsText) {\n activeToolCallArgsText = undefined;\n }\n toolCallController.setResponse({\n result: chunk.result,\n isError: chunk.isError ?? false,\n ...(chunk.messages !== undefined\n ? { messages: chunk.messages }\n : {}),\n });\n break;\n }\n\n case \"start-step\":\n controller.enqueue({\n type: \"step-start\",\n path: [],\n messageId: chunk.messageId ?? currentMessageId ?? generateId(),\n });\n break;\n\n case \"finish-step\":\n controller.enqueue({\n type: \"step-finish\",\n path: [],\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n isContinued: chunk.isContinued,\n });\n break;\n\n case \"finish\":\n controller.enqueue({\n type: \"message-finish\",\n path: [],\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n });\n break;\n\n case \"error\":\n controller.enqueue({\n type: \"error\",\n path: [],\n error: chunk.errorText,\n });\n break;\n\n default:\n // ignore unknown types for forward compatibility\n break;\n }\n },\n flush() {\n activeToolCallArgsText?.close();\n toolCallControllers.forEach((ctrl) => ctrl.close());\n toolCallControllers.clear();\n },\n });\n\n return readable\n .pipeThrough(new TextDecoderStream())\n .pipeThrough(new SSEEventDecoderStream())\n .pipeThrough(\n new TransformStream<PipelineSSEEvent, UIMessageStreamChunk>({\n transform(event, controller) {\n if (event.event !== \"message\") {\n throw new Error(`Unknown SSE event type: ${event.event}`);\n }\n\n if (event.data === \"[DONE]\") {\n receivedDone = true;\n controller.terminate();\n return;\n }\n\n let chunk;\n try {\n chunk = JSON.parse(event.data);\n } catch {\n chunk = undefined;\n }\n if (\n typeof chunk !== \"object\" ||\n chunk === null ||\n Array.isArray(chunk) ||\n typeof chunk.type !== \"string\"\n ) {\n console.warn(\n `Dropped invalid UIMessageStream chunk: ${event.data.slice(0, 200)}`,\n );\n return;\n }\n if (\n chunk.type === \"text-delta\" &&\n chunk.textDelta === undefined\n ) {\n const { delta, ...rest } = chunk;\n controller.enqueue({ ...rest, textDelta: delta ?? \"\" });\n return;\n }\n if (chunk.type === \"start\") {\n controller.enqueue({\n ...chunk,\n messageId: chunk.messageId ?? generateId(),\n });\n return;\n }\n if (chunk.type === \"source-url\") {\n controller.enqueue({\n type: \"source\",\n source: {\n sourceType: \"url\",\n id: chunk.sourceId,\n url: chunk.url,\n ...(chunk.title && { title: chunk.title }),\n },\n });\n return;\n }\n if (chunk.type === \"source\" && chunk.source == null) return;\n if (chunk.type === \"file\" && chunk.file == null) {\n if (chunk.url === undefined) return;\n controller.enqueue({\n type: \"file\",\n file: { mimeType: chunk.mediaType, data: chunk.url },\n });\n return;\n }\n if (chunk.type === \"finish-step\") {\n controller.enqueue({\n ...chunk,\n finishReason: chunk.finishReason ?? \"unknown\",\n usage: chunk.usage ?? { inputTokens: 0, outputTokens: 0 },\n isContinued: chunk.isContinued ?? false,\n });\n return;\n }\n if (chunk.type === \"finish\") {\n controller.enqueue({\n ...chunk,\n finishReason: chunk.finishReason ?? \"unknown\",\n usage: chunk.usage ?? { inputTokens: 0, outputTokens: 0 },\n });\n return;\n }\n\n controller.enqueue(chunk);\n },\n flush() {\n if (!receivedDone) {\n throw new Error(\n \"Stream ended abruptly without receiving [DONE] marker\",\n );\n }\n },\n }),\n )\n .pipeThrough(transform);\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-types.d.ts","names":[],"sources":["../../../../src/core/serialization/ui-message-stream/chunk-types.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"chunk-types.d.ts","names":[],"sources":["../../../../src/core/serialization/ui-message-stream/chunk-types.ts"],"mappings":";;KAEK;KASA;EACH;EACA;;KAGU;EACN;EAAe;;EACf;EAAoB;;EACpB;EAAoB;;EACpB;;EACA;EAAyB;;EACzB;EAAyB;;EACzB;;EAEA;EACA;IAAU;IAAmB;IAAY;IAAa;;;EAEtD;EAAc;IAAQ;IAAkB;;;EAExC;EACA;EACA;EACA;;EAEA;EAAyB;;EACzB;;EAEA;EACA;EACA,QAAQ;EACR;EACA,WAAW;;EAEX;EAAoB;;EAEpB;EACA,cAAc;EACd,OAAO;EACP;;EAEA;EAAgB,cAAc;EAAc,OAAO;;EACnD;EAAe;IACjB;KAEQ;EACV;EACA;EACA,MAAM;EACN"}
|
|
@@ -3,6 +3,7 @@ import { AsyncIterableStream } from "../../utils/AsyncIterableStream.js";
|
|
|
3
3
|
import { DeepPartial, TypeAtPath, TypePath } from "./type-path-utils.js";
|
|
4
4
|
import { ToolCallArgsReader, ToolCallReader, ToolCallResponseReader } from "./tool-types.js";
|
|
5
5
|
import { ToolResponse } from "./ToolResponse.js";
|
|
6
|
+
import "../../utils.js";
|
|
6
7
|
//#region src/core/tool/ToolCallReader.d.ts
|
|
7
8
|
declare class ToolCallArgsReaderImpl<T extends ReadonlyJSONObject> implements ToolCallArgsReader<T> {
|
|
8
9
|
private argTextDeltas;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolCallReader.d.ts","names":[],"sources":["../../../src/core/tool/ToolCallReader.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ToolCallReader.d.ts","names":[],"sources":["../../../src/core/tool/ToolCallReader.ts"],"mappings":";;;;;;;cA0Qa,uBACX,UAAU,+BACC,mBAAmB;UACtB;UACA;UACA;UACA;EAEI,YAAA,eAAe;UAKb;EA+Bd,IAAI,cAAc,SAAS,OACtB,WAAW,QACb,QAAQ,WAAW,GAAG;EAiCzB,aAAa,cAAc,SAAS,OAC/B,WAAW,QACb,oBAAoB,YAAY,WAAW,GAAG;EA4BjD,WAAW,cAAc,SAAS,OAC7B,WAAW,QACb,WAAW,GAAG,+BAA+B,KAC5C,oBAAoB;EA6BxB,QAAQ,cAAc,SAAS,OAC1B,WAAW,QACb,YAAY,WAAW,GAAG,gBAAgB,YAAY,KACrD,oBAAoB;;cA8Bb,2BACX,gBAAgB,8BACL,uBAAuB;mBACL;EAAA,YAAA,SAAS,QAAQ,aAAa;EAEpD,OAAG,QAAA,aAAA;;cAKC,mBACX,cAAc,oBACd,gBAAgB,8BACL,eAAe,OAAO;WACjB,MAAM,uBAAuB;WAC7B,UAAU,2BAA2B;mBACpC;mBACA;EAEV;;EAYD,oBAAoB,eAAe;EAanC,kBAAkB;EAWxB,YAAY,OAAO,aAAa;EAIhC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolCallReader.js","names":[],"sources":["../../../src/core/tool/ToolCallReader.ts"],"sourcesContent":["import { promiseWithResolvers } from \"../../utils/promiseWithResolvers\";\nimport {\n parsePartialJsonObject,\n getPartialJsonObjectFieldState,\n} from \"../../utils/json/parse-partial-json-object\";\nimport type {\n ToolCallArgsReader,\n ToolCallReader,\n ToolCallResponseReader,\n} from \"./tool-types\";\nimport type { DeepPartial, TypeAtPath, TypePath } from \"./type-path-utils\";\nimport type { ToolResponse } from \"./ToolResponse\";\nimport { asAsyncIterableStream } from \"../../utils/AsyncIterableStream\";\nimport type {\n AsyncIterableStream,\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"../../utils\";\n\n// TODO: remove dispose\n\nfunction getField<T>(obj: T, fieldPath: (string | number)[]): unknown {\n let current: unknown = obj;\n for (const key of fieldPath) {\n if (current === undefined || current === null) {\n return undefined;\n }\n current = current[key as keyof typeof current];\n }\n return current;\n}\n\ninterface Handle {\n update(args: unknown): void;\n end(args: unknown): void;\n dispose(): void;\n}\n\nclass GetHandle<T, TValue> implements Handle {\n private resolve: (value: TValue) => void;\n private reject: (reason: unknown) => void;\n private disposed = false;\n private fieldPath: (string | number)[];\n\n constructor(\n resolve: (value: TValue) => void,\n reject: (reason: unknown) => void,\n fieldPath: (string | number)[],\n ) {\n this.resolve = resolve;\n this.reject = reject;\n this.fieldPath = fieldPath;\n }\n\n update(args: unknown): void {\n if (this.disposed) return;\n\n try {\n // Check if the field is complete\n if (\n getPartialJsonObjectFieldState(\n args as Record<string, unknown>,\n this.fieldPath,\n ) === \"complete\"\n ) {\n const value = getField(args as T, this.fieldPath);\n if (value !== undefined) {\n this.resolve(value as TValue);\n this.dispose();\n }\n }\n } catch (e) {\n this.reject(e);\n this.dispose();\n }\n }\n\n end(args: unknown): void {\n if (this.disposed) return;\n\n try {\n const value = getField(args as T, this.fieldPath);\n this.resolve(value as TValue);\n } catch (e) {\n this.reject(e);\n } finally {\n this.dispose();\n }\n }\n\n dispose(): void {\n this.disposed = true;\n }\n}\n\nclass StreamValuesHandle<T> implements Handle {\n private controller: ReadableStreamDefaultController<unknown>;\n private disposed = false;\n private fieldPath: (string | number)[];\n\n constructor(\n controller: ReadableStreamDefaultController<unknown>,\n fieldPath: (string | number)[],\n ) {\n this.controller = controller;\n this.fieldPath = fieldPath;\n }\n\n update(args: unknown): void {\n if (this.disposed) return;\n\n try {\n const value = getField(args as T, this.fieldPath);\n\n if (value !== undefined) {\n this.controller.enqueue(value);\n }\n\n // Check if the field is complete, if so close the stream\n if (\n getPartialJsonObjectFieldState(\n args as Record<string, unknown>,\n this.fieldPath,\n ) === \"complete\"\n ) {\n this.controller.close();\n this.dispose();\n }\n } catch (e) {\n this.controller.error(e);\n this.dispose();\n }\n }\n\n end(): void {\n if (this.disposed) return;\n this.controller.close();\n this.dispose();\n }\n\n dispose(): void {\n this.disposed = true;\n }\n}\n\nclass StreamTextHandle<T> implements Handle {\n private controller: ReadableStreamDefaultController<unknown>;\n private disposed = false;\n private fieldPath: (string | number)[];\n private lastValue: string | undefined = undefined;\n\n constructor(\n controller: ReadableStreamDefaultController<unknown>,\n fieldPath: (string | number)[],\n ) {\n this.controller = controller;\n this.fieldPath = fieldPath;\n }\n\n update(args: unknown): void {\n if (this.disposed) return;\n\n try {\n const value = getField(args as T, this.fieldPath);\n\n if (value !== undefined && typeof value === \"string\") {\n const delta = value.substring(this.lastValue?.length || 0);\n this.lastValue = value;\n this.controller.enqueue(delta);\n }\n\n // Check if the field is complete, if so close the stream\n if (\n getPartialJsonObjectFieldState(\n args as Record<string, unknown>,\n this.fieldPath,\n ) === \"complete\"\n ) {\n this.controller.close();\n this.dispose();\n }\n } catch (e) {\n this.controller.error(e);\n this.dispose();\n }\n }\n\n end(): void {\n if (this.disposed) return;\n this.controller.close();\n this.dispose();\n }\n\n dispose(): void {\n this.disposed = true;\n }\n}\n\nclass ForEachHandle<T> implements Handle {\n private controller: ReadableStreamDefaultController<unknown>;\n private disposed = false;\n private fieldPath: (string | number)[];\n private processedIndexes = new Set<number>();\n\n constructor(\n controller: ReadableStreamDefaultController<unknown>,\n fieldPath: (string | number)[],\n ) {\n this.controller = controller;\n this.fieldPath = fieldPath;\n }\n\n update(args: unknown): void {\n if (this.disposed) return;\n\n try {\n const array = getField(args as T, this.fieldPath);\n\n if (!Array.isArray(array)) {\n return;\n }\n\n // Check each array element and emit completed ones that haven't been processed\n for (let i = 0; i < array.length; i++) {\n if (!this.processedIndexes.has(i)) {\n const elementPath = [...this.fieldPath, i];\n if (\n getPartialJsonObjectFieldState(\n args as Record<string, unknown>,\n elementPath,\n ) === \"complete\"\n ) {\n this.controller.enqueue(array[i]);\n this.processedIndexes.add(i);\n }\n }\n }\n\n // Check if the entire array is complete\n if (\n getPartialJsonObjectFieldState(\n args as Record<string, unknown>,\n this.fieldPath,\n ) === \"complete\"\n ) {\n this.controller.close();\n this.dispose();\n }\n } catch (e) {\n this.controller.error(e);\n this.dispose();\n }\n }\n\n end(): void {\n if (this.disposed) return;\n this.controller.close();\n this.dispose();\n }\n\n dispose(): void {\n this.disposed = true;\n }\n}\n\n// Implementation of ToolCallReader that uses stream of partial JSON\nexport class ToolCallArgsReaderImpl<\n T extends ReadonlyJSONObject,\n> implements ToolCallArgsReader<T> {\n private argTextDeltas: ReadableStream<string>;\n private handles: Set<Handle> = new Set();\n private args: unknown = parsePartialJsonObject(\"\");\n private finished = false;\n\n constructor(argTextDeltas: ReadableStream<string>) {\n this.argTextDeltas = argTextDeltas;\n this.processStream();\n }\n\n private async processStream(): Promise<void> {\n try {\n let accumulatedText = \"\";\n const reader = this.argTextDeltas.getReader();\n\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n\n accumulatedText += value;\n const parsedArgs = parsePartialJsonObject(accumulatedText);\n\n if (parsedArgs !== undefined) {\n this.args = parsedArgs;\n // Notify all handles of the updated args\n for (const handle of this.handles) {\n handle.update(parsedArgs);\n }\n }\n }\n } catch (error) {\n console.error(\"Error processing argument stream:\", error);\n } finally {\n this.finished = true;\n for (const handle of this.handles) {\n handle.end(this.args);\n }\n this.handles.clear();\n }\n }\n\n get<PathT extends TypePath<T>>(\n ...fieldPath: PathT\n ): Promise<TypeAtPath<T, PathT>> {\n return new Promise<TypeAtPath<T, PathT>>((resolve, reject) => {\n const handle = new GetHandle<T, TypeAtPath<T, PathT>>(\n resolve,\n reject,\n fieldPath,\n );\n\n // Check if the field is already complete in current args\n if (\n this.args &&\n getPartialJsonObjectFieldState(\n this.args as Record<string, unknown>,\n fieldPath,\n ) === \"complete\"\n ) {\n const value = getField(this.args as T, fieldPath);\n if (value !== undefined) {\n resolve(value as TypeAtPath<T, PathT>);\n return;\n }\n }\n\n if (this.finished) {\n handle.end(this.args);\n return;\n }\n\n this.handles.add(handle);\n handle.update(this.args);\n });\n }\n\n streamValues<PathT extends TypePath<T>>(\n ...fieldPath: PathT\n ): AsyncIterableStream<DeepPartial<TypeAtPath<T, PathT>>> {\n // Use a type assertion to convert the complex TypePath to a simple array\n const simplePath = fieldPath as unknown as (string | number)[];\n\n let handle: StreamValuesHandle<T> | undefined;\n const stream = new ReadableStream<DeepPartial<TypeAtPath<T, PathT>>>({\n start: (controller) => {\n handle = new StreamValuesHandle<T>(controller, simplePath);\n if (!this.finished) this.handles.add(handle);\n\n // Check current args immediately\n handle.update(this.args);\n\n if (this.finished) handle.end();\n },\n cancel: () => {\n // Dispose this stream's own handle (captured above) — scanning for the\n // first match would dispose a concurrent streamValues()'s handle.\n if (handle) {\n handle.dispose();\n this.handles.delete(handle);\n }\n },\n });\n\n return asAsyncIterableStream(stream) as any;\n }\n\n streamText<PathT extends TypePath<T>>(\n ...fieldPath: PathT\n ): TypeAtPath<T, PathT> extends string & (infer U)\n ? AsyncIterableStream<U>\n : never {\n // Use a type assertion to convert the complex TypePath to a simple array\n const simplePath = fieldPath as unknown as (string | number)[];\n\n let handle: StreamTextHandle<T> | undefined;\n const stream = new ReadableStream<unknown>({\n start: (controller) => {\n handle = new StreamTextHandle<T>(controller, simplePath);\n if (!this.finished) this.handles.add(handle);\n\n // Check current args immediately\n handle.update(this.args);\n\n if (this.finished) handle.end();\n },\n cancel: () => {\n // Dispose this stream's own handle (captured above) — scanning for the\n // first match would dispose a concurrent streamText()'s handle.\n if (handle) {\n handle.dispose();\n this.handles.delete(handle);\n }\n },\n });\n\n return asAsyncIterableStream(stream) as any;\n }\n\n forEach<PathT extends TypePath<T>>(\n ...fieldPath: PathT\n ): NonNullable<TypeAtPath<T, PathT>> extends Array<infer U>\n ? AsyncIterableStream<U>\n : never {\n // Use a type assertion to convert the complex TypePath to a simple array\n const simplePath = fieldPath as unknown as (string | number)[];\n\n let handle: ForEachHandle<T> | undefined;\n const stream = new ReadableStream<unknown>({\n start: (controller) => {\n handle = new ForEachHandle<T>(controller, simplePath);\n if (!this.finished) this.handles.add(handle);\n\n // Check current args immediately\n handle.update(this.args);\n\n if (this.finished) handle.end();\n },\n cancel: () => {\n // Dispose this stream's own handle (captured above) — scanning for the\n // first match would dispose a concurrent forEach()'s handle.\n if (handle) {\n handle.dispose();\n this.handles.delete(handle);\n }\n },\n });\n\n return asAsyncIterableStream(stream) as any;\n }\n}\n\nexport class ToolCallResponseReaderImpl<\n TResult extends ReadonlyJSONValue,\n> implements ToolCallResponseReader<TResult> {\n constructor(private readonly promise: Promise<ToolResponse<TResult>>) {}\n\n public get() {\n return this.promise;\n }\n}\n\nexport class ToolCallReaderImpl<\n TArgs extends ReadonlyJSONObject,\n TResult extends ReadonlyJSONValue,\n> implements ToolCallReader<TArgs, TResult> {\n public readonly args: ToolCallArgsReaderImpl<TArgs>;\n public readonly response: ToolCallResponseReaderImpl<TResult>;\n private readonly writable: WritableStream<string>;\n private readonly resolve: (value: ToolResponse<TResult>) => void;\n\n public argsText: string = \"\";\n\n constructor() {\n const stream = new TransformStream<string, string>();\n this.writable = stream.writable;\n this.args = new ToolCallArgsReaderImpl<TArgs>(stream.readable);\n\n const { promise, resolve } = promiseWithResolvers<ToolResponse<TResult>>();\n this.resolve = resolve;\n this.response = new ToolCallResponseReaderImpl<TResult>(promise);\n }\n\n async appendArgsTextDelta(text: string): Promise<void> {\n const writer = this.writable.getWriter();\n try {\n await writer.write(text);\n } catch (err) {\n console.warn(err);\n } finally {\n writer.releaseLock();\n }\n\n this.argsText += text;\n }\n\n async finishArgsText(): Promise<void> {\n const writer = this.writable.getWriter();\n try {\n await writer.close();\n } catch (err) {\n console.warn(err);\n } finally {\n writer.releaseLock();\n }\n }\n\n setResponse(value: ToolResponse<TResult>): void {\n this.resolve(value);\n }\n\n result = {\n get: async () => {\n const response = await this.response.get();\n return response.result;\n },\n };\n}\n"],"mappings":";;;;AAqBA,SAAS,SAAY,KAAQ,WAAyC;CACpE,IAAI,UAAmB;CACvB,KAAK,MAAM,OAAO,WAAW;EAC3B,IAAI,YAAY,KAAA,KAAa,YAAY,MACvC;EAEF,UAAU,QAAQ;CACpB;CACA,OAAO;AACT;AAQA,IAAM,YAAN,MAA6C;CAC3C;CACA;CACA,WAAmB;CACnB;CAEA,YACE,SACA,QACA,WACA;EACA,KAAK,UAAU;EACf,KAAK,SAAS;EACd,KAAK,YAAY;CACnB;CAEA,OAAO,MAAqB;EAC1B,IAAI,KAAK,UAAU;EAEnB,IAAI;GAEF,IACE,+BACE,MACA,KAAK,SACP,MAAM,YACN;IACA,MAAM,QAAQ,SAAS,MAAW,KAAK,SAAS;IAChD,IAAI,UAAU,KAAA,GAAW;KACvB,KAAK,QAAQ,KAAe;KAC5B,KAAK,QAAQ;IACf;GACF;EACF,SAAS,GAAG;GACV,KAAK,OAAO,CAAC;GACb,KAAK,QAAQ;EACf;CACF;CAEA,IAAI,MAAqB;EACvB,IAAI,KAAK,UAAU;EAEnB,IAAI;GACF,MAAM,QAAQ,SAAS,MAAW,KAAK,SAAS;GAChD,KAAK,QAAQ,KAAe;EAC9B,SAAS,GAAG;GACV,KAAK,OAAO,CAAC;EACf,UAAU;GACR,KAAK,QAAQ;EACf;CACF;CAEA,UAAgB;EACd,KAAK,WAAW;CAClB;AACF;AAEA,IAAM,qBAAN,MAA8C;CAC5C;CACA,WAAmB;CACnB;CAEA,YACE,YACA,WACA;EACA,KAAK,aAAa;EAClB,KAAK,YAAY;CACnB;CAEA,OAAO,MAAqB;EAC1B,IAAI,KAAK,UAAU;EAEnB,IAAI;GACF,MAAM,QAAQ,SAAS,MAAW,KAAK,SAAS;GAEhD,IAAI,UAAU,KAAA,GACZ,KAAK,WAAW,QAAQ,KAAK;GAI/B,IACE,+BACE,MACA,KAAK,SACP,MAAM,YACN;IACA,KAAK,WAAW,MAAM;IACtB,KAAK,QAAQ;GACf;EACF,SAAS,GAAG;GACV,KAAK,WAAW,MAAM,CAAC;GACvB,KAAK,QAAQ;EACf;CACF;CAEA,MAAY;EACV,IAAI,KAAK,UAAU;EACnB,KAAK,WAAW,MAAM;EACtB,KAAK,QAAQ;CACf;CAEA,UAAgB;EACd,KAAK,WAAW;CAClB;AACF;AAEA,IAAM,mBAAN,MAA4C;CAC1C;CACA,WAAmB;CACnB;CACA,YAAwC,KAAA;CAExC,YACE,YACA,WACA;EACA,KAAK,aAAa;EAClB,KAAK,YAAY;CACnB;CAEA,OAAO,MAAqB;EAC1B,IAAI,KAAK,UAAU;EAEnB,IAAI;GACF,MAAM,QAAQ,SAAS,MAAW,KAAK,SAAS;GAEhD,IAAI,UAAU,KAAA,KAAa,OAAO,UAAU,UAAU;IACpD,MAAM,QAAQ,MAAM,UAAU,KAAK,WAAW,UAAU,CAAC;IACzD,KAAK,YAAY;IACjB,KAAK,WAAW,QAAQ,KAAK;GAC/B;GAGA,IACE,+BACE,MACA,KAAK,SACP,MAAM,YACN;IACA,KAAK,WAAW,MAAM;IACtB,KAAK,QAAQ;GACf;EACF,SAAS,GAAG;GACV,KAAK,WAAW,MAAM,CAAC;GACvB,KAAK,QAAQ;EACf;CACF;CAEA,MAAY;EACV,IAAI,KAAK,UAAU;EACnB,KAAK,WAAW,MAAM;EACtB,KAAK,QAAQ;CACf;CAEA,UAAgB;EACd,KAAK,WAAW;CAClB;AACF;AAEA,IAAM,gBAAN,MAAyC;CACvC;CACA,WAAmB;CACnB;CACA,mCAA2B,IAAI,IAAY;CAE3C,YACE,YACA,WACA;EACA,KAAK,aAAa;EAClB,KAAK,YAAY;CACnB;CAEA,OAAO,MAAqB;EAC1B,IAAI,KAAK,UAAU;EAEnB,IAAI;GACF,MAAM,QAAQ,SAAS,MAAW,KAAK,SAAS;GAEhD,IAAI,CAAC,MAAM,QAAQ,KAAK,GACtB;GAIF,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAChC,IAAI,CAAC,KAAK,iBAAiB,IAAI,CAAC;QAG5B,+BACE,MACA,CAJiB,GAAG,KAAK,WAAW,CAI1B,CACZ,MAAM,YACN;KACA,KAAK,WAAW,QAAQ,MAAM,EAAE;KAChC,KAAK,iBAAiB,IAAI,CAAC;IAC7B;;GAKJ,IACE,+BACE,MACA,KAAK,SACP,MAAM,YACN;IACA,KAAK,WAAW,MAAM;IACtB,KAAK,QAAQ;GACf;EACF,SAAS,GAAG;GACV,KAAK,WAAW,MAAM,CAAC;GACvB,KAAK,QAAQ;EACf;CACF;CAEA,MAAY;EACV,IAAI,KAAK,UAAU;EACnB,KAAK,WAAW,MAAM;EACtB,KAAK,QAAQ;CACf;CAEA,UAAgB;EACd,KAAK,WAAW;CAClB;AACF;AAGA,IAAa,yBAAb,MAEmC;CACjC;CACA,0BAA+B,IAAI,IAAI;CACvC,OAAwB,uBAAuB,EAAE;CACjD,WAAmB;CAEnB,YAAY,eAAuC;EACjD,KAAK,gBAAgB;EACrB,KAAK,cAAc;CACrB;CAEA,MAAc,gBAA+B;EAC3C,IAAI;GACF,IAAI,kBAAkB;GACtB,MAAM,SAAS,KAAK,cAAc,UAAU;GAE5C,OAAO,MAAM;IACX,MAAM,EAAE,OAAO,SAAS,MAAM,OAAO,KAAK;IAC1C,IAAI,MAAM;IAEV,mBAAmB;IACnB,MAAM,aAAa,uBAAuB,eAAe;IAEzD,IAAI,eAAe,KAAA,GAAW;KAC5B,KAAK,OAAO;KAEZ,KAAK,MAAM,UAAU,KAAK,SACxB,OAAO,OAAO,UAAU;IAE5B;GACF;EACF,SAAS,OAAO;GACd,QAAQ,MAAM,qCAAqC,KAAK;EAC1D,UAAU;GACR,KAAK,WAAW;GAChB,KAAK,MAAM,UAAU,KAAK,SACxB,OAAO,IAAI,KAAK,IAAI;GAEtB,KAAK,QAAQ,MAAM;EACrB;CACF;CAEA,IACE,GAAG,WAC4B;EAC/B,OAAO,IAAI,SAA+B,SAAS,WAAW;GAC5D,MAAM,SAAS,IAAI,UACjB,SACA,QACA,SACF;GAGA,IACE,KAAK,QACL,+BACE,KAAK,MACL,SACF,MAAM,YACN;IACA,MAAM,QAAQ,SAAS,KAAK,MAAW,SAAS;IAChD,IAAI,UAAU,KAAA,GAAW;KACvB,QAAQ,KAA6B;KACrC;IACF;GACF;GAEA,IAAI,KAAK,UAAU;IACjB,OAAO,IAAI,KAAK,IAAI;IACpB;GACF;GAEA,KAAK,QAAQ,IAAI,MAAM;GACvB,OAAO,OAAO,KAAK,IAAI;EACzB,CAAC;CACH;CAEA,aACE,GAAG,WACqD;EAExD,MAAM,aAAa;EAEnB,IAAI;EAqBJ,OAAO,sBAAsB,IApBV,eAAkD;GACnE,QAAQ,eAAe;IACrB,SAAS,IAAI,mBAAsB,YAAY,UAAU;IACzD,IAAI,CAAC,KAAK,UAAU,KAAK,QAAQ,IAAI,MAAM;IAG3C,OAAO,OAAO,KAAK,IAAI;IAEvB,IAAI,KAAK,UAAU,OAAO,IAAI;GAChC;GACA,cAAc;IAGZ,IAAI,QAAQ;KACV,OAAO,QAAQ;KACf,KAAK,QAAQ,OAAO,MAAM;IAC5B;GACF;EACF,CAEkC,CAAC;CACrC;CAEA,WACE,GAAG,WAGK;EAER,MAAM,aAAa;EAEnB,IAAI;EAqBJ,OAAO,sBAAsB,IApBV,eAAwB;GACzC,QAAQ,eAAe;IACrB,SAAS,IAAI,iBAAoB,YAAY,UAAU;IACvD,IAAI,CAAC,KAAK,UAAU,KAAK,QAAQ,IAAI,MAAM;IAG3C,OAAO,OAAO,KAAK,IAAI;IAEvB,IAAI,KAAK,UAAU,OAAO,IAAI;GAChC;GACA,cAAc;IAGZ,IAAI,QAAQ;KACV,OAAO,QAAQ;KACf,KAAK,QAAQ,OAAO,MAAM;IAC5B;GACF;EACF,CAEkC,CAAC;CACrC;CAEA,QACE,GAAG,WAGK;EAER,MAAM,aAAa;EAEnB,IAAI;EAqBJ,OAAO,sBAAsB,IApBV,eAAwB;GACzC,QAAQ,eAAe;IACrB,SAAS,IAAI,cAAiB,YAAY,UAAU;IACpD,IAAI,CAAC,KAAK,UAAU,KAAK,QAAQ,IAAI,MAAM;IAG3C,OAAO,OAAO,KAAK,IAAI;IAEvB,IAAI,KAAK,UAAU,OAAO,IAAI;GAChC;GACA,cAAc;IAGZ,IAAI,QAAQ;KACV,OAAO,QAAQ;KACf,KAAK,QAAQ,OAAO,MAAM;IAC5B;GACF;EACF,CAEkC,CAAC;CACrC;AACF;AAEA,IAAa,6BAAb,MAE6C;CACd;CAA7B,YAAY,SAA0D;EAAzC,KAAA,UAAA;CAA0C;CAEvE,MAAa;EACX,OAAO,KAAK;CACd;AACF;AAEA,IAAa,qBAAb,MAG4C;CAC1C;CACA;CACA;CACA;CAEA,WAA0B;CAE1B,cAAc;EACZ,MAAM,SAAS,IAAI,gBAAgC;EACnD,KAAK,WAAW,OAAO;EACvB,KAAK,OAAO,IAAI,uBAA8B,OAAO,QAAQ;EAE7D,MAAM,EAAE,SAAS,YAAY,qBAA4C;EACzE,KAAK,UAAU;EACf,KAAK,WAAW,IAAI,2BAAoC,OAAO;CACjE;CAEA,MAAM,oBAAoB,MAA6B;EACrD,MAAM,SAAS,KAAK,SAAS,UAAU;EACvC,IAAI;GACF,MAAM,OAAO,MAAM,IAAI;EACzB,SAAS,KAAK;GACZ,QAAQ,KAAK,GAAG;EAClB,UAAU;GACR,OAAO,YAAY;EACrB;EAEA,KAAK,YAAY;CACnB;CAEA,MAAM,iBAAgC;EACpC,MAAM,SAAS,KAAK,SAAS,UAAU;EACvC,IAAI;GACF,MAAM,OAAO,MAAM;EACrB,SAAS,KAAK;GACZ,QAAQ,KAAK,GAAG;EAClB,UAAU;GACR,OAAO,YAAY;EACrB;CACF;CAEA,YAAY,OAAoC;EAC9C,KAAK,QAAQ,KAAK;CACpB;CAEA,SAAS,EACP,KAAK,YAAY;EAEf,QAAO,MADgB,KAAK,SAAS,IAAI,EAAA,CACzB;CAClB,EACF;AACF"}
|
|
1
|
+
{"version":3,"file":"ToolCallReader.js","names":[],"sources":["../../../src/core/tool/ToolCallReader.ts"],"sourcesContent":["import { promiseWithResolvers } from \"../../utils/promiseWithResolvers\";\nimport {\n parsePartialJsonObject,\n getPartialJsonObjectFieldState,\n} from \"../../utils/json/parse-partial-json-object\";\nimport type {\n ToolCallArgsReader,\n ToolCallReader,\n ToolCallResponseReader,\n} from \"./tool-types\";\nimport type { DeepPartial, TypeAtPath, TypePath } from \"./type-path-utils\";\nimport type { ToolResponse } from \"./ToolResponse\";\nimport { asAsyncIterableStream } from \"../../utils/AsyncIterableStream\";\nimport type {\n AsyncIterableStream,\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"../../utils\";\n\n// TODO: remove dispose\n\nfunction getField<T>(obj: T, fieldPath: (string | number)[]): unknown {\n let current: unknown = obj;\n for (const key of fieldPath) {\n if (current === undefined || current === null) {\n return undefined;\n }\n current = current[key as keyof typeof current];\n }\n return current;\n}\n\ninterface Handle {\n update(args: unknown): void;\n end(args: unknown): void;\n dispose(): void;\n}\n\nclass GetHandle<T, TValue> implements Handle {\n private resolve: (value: TValue) => void;\n private reject: (reason: unknown) => void;\n private disposed = false;\n private fieldPath: (string | number)[];\n\n constructor(\n resolve: (value: TValue) => void,\n reject: (reason: unknown) => void,\n fieldPath: (string | number)[],\n ) {\n this.resolve = resolve;\n this.reject = reject;\n this.fieldPath = fieldPath;\n }\n\n update(args: unknown): void {\n if (this.disposed) return;\n\n try {\n // Check if the field is complete\n if (\n getPartialJsonObjectFieldState(\n args as Record<string, unknown>,\n this.fieldPath,\n ) === \"complete\"\n ) {\n const value = getField(args as T, this.fieldPath);\n if (value !== undefined) {\n this.resolve(value as TValue);\n this.dispose();\n }\n }\n } catch (e) {\n this.reject(e);\n this.dispose();\n }\n }\n\n end(args: unknown): void {\n if (this.disposed) return;\n\n try {\n const value = getField(args as T, this.fieldPath);\n this.resolve(value as TValue);\n } catch (e) {\n this.reject(e);\n } finally {\n this.dispose();\n }\n }\n\n dispose(): void {\n this.disposed = true;\n }\n}\n\nclass StreamValuesHandle<T> implements Handle {\n private controller: ReadableStreamDefaultController<unknown>;\n private disposed = false;\n private fieldPath: (string | number)[];\n\n constructor(\n controller: ReadableStreamDefaultController<unknown>,\n fieldPath: (string | number)[],\n ) {\n this.controller = controller;\n this.fieldPath = fieldPath;\n }\n\n update(args: unknown): void {\n if (this.disposed) return;\n\n try {\n const value = getField(args as T, this.fieldPath);\n\n if (value !== undefined) {\n this.controller.enqueue(value);\n }\n\n // Check if the field is complete, if so close the stream\n if (\n getPartialJsonObjectFieldState(\n args as Record<string, unknown>,\n this.fieldPath,\n ) === \"complete\"\n ) {\n this.controller.close();\n this.dispose();\n }\n } catch (e) {\n this.controller.error(e);\n this.dispose();\n }\n }\n\n end(): void {\n if (this.disposed) return;\n this.controller.close();\n this.dispose();\n }\n\n dispose(): void {\n this.disposed = true;\n }\n}\n\nclass StreamTextHandle<T> implements Handle {\n private controller: ReadableStreamDefaultController<unknown>;\n private disposed = false;\n private fieldPath: (string | number)[];\n private lastValue: string | undefined = undefined;\n\n constructor(\n controller: ReadableStreamDefaultController<unknown>,\n fieldPath: (string | number)[],\n ) {\n this.controller = controller;\n this.fieldPath = fieldPath;\n }\n\n update(args: unknown): void {\n if (this.disposed) return;\n\n try {\n const value = getField(args as T, this.fieldPath);\n\n if (value !== undefined && typeof value === \"string\") {\n const delta = value.substring(this.lastValue?.length || 0);\n this.lastValue = value;\n this.controller.enqueue(delta);\n }\n\n // Check if the field is complete, if so close the stream\n if (\n getPartialJsonObjectFieldState(\n args as Record<string, unknown>,\n this.fieldPath,\n ) === \"complete\"\n ) {\n this.controller.close();\n this.dispose();\n }\n } catch (e) {\n this.controller.error(e);\n this.dispose();\n }\n }\n\n end(): void {\n if (this.disposed) return;\n this.controller.close();\n this.dispose();\n }\n\n dispose(): void {\n this.disposed = true;\n }\n}\n\nclass ForEachHandle<T> implements Handle {\n private controller: ReadableStreamDefaultController<unknown>;\n private disposed = false;\n private fieldPath: (string | number)[];\n private processedIndexes = new Set<number>();\n\n constructor(\n controller: ReadableStreamDefaultController<unknown>,\n fieldPath: (string | number)[],\n ) {\n this.controller = controller;\n this.fieldPath = fieldPath;\n }\n\n update(args: unknown): void {\n if (this.disposed) return;\n\n try {\n const array = getField(args as T, this.fieldPath);\n\n if (!Array.isArray(array)) {\n return;\n }\n\n // Check each array element and emit completed ones that haven't been processed\n for (let i = 0; i < array.length; i++) {\n if (!this.processedIndexes.has(i)) {\n const elementPath = [...this.fieldPath, i];\n if (\n getPartialJsonObjectFieldState(\n args as Record<string, unknown>,\n elementPath,\n ) === \"complete\"\n ) {\n this.controller.enqueue(array[i]);\n this.processedIndexes.add(i);\n }\n }\n }\n\n // Check if the entire array is complete\n if (\n getPartialJsonObjectFieldState(\n args as Record<string, unknown>,\n this.fieldPath,\n ) === \"complete\"\n ) {\n this.controller.close();\n this.dispose();\n }\n } catch (e) {\n this.controller.error(e);\n this.dispose();\n }\n }\n\n end(): void {\n if (this.disposed) return;\n this.controller.close();\n this.dispose();\n }\n\n dispose(): void {\n this.disposed = true;\n }\n}\n\n// Implementation of ToolCallReader that uses stream of partial JSON\nexport class ToolCallArgsReaderImpl<\n T extends ReadonlyJSONObject,\n> implements ToolCallArgsReader<T> {\n private argTextDeltas: ReadableStream<string>;\n private handles: Set<Handle> = new Set();\n private args: unknown = parsePartialJsonObject(\"\");\n private finished = false;\n\n constructor(argTextDeltas: ReadableStream<string>) {\n this.argTextDeltas = argTextDeltas;\n this.processStream();\n }\n\n private async processStream(): Promise<void> {\n try {\n let accumulatedText = \"\";\n const reader = this.argTextDeltas.getReader();\n\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n\n accumulatedText += value;\n const parsedArgs = parsePartialJsonObject(accumulatedText);\n\n if (parsedArgs !== undefined) {\n this.args = parsedArgs;\n // Notify all handles of the updated args\n for (const handle of this.handles) {\n handle.update(parsedArgs);\n }\n }\n }\n } catch (error) {\n console.error(\"Error processing argument stream:\", error);\n } finally {\n this.finished = true;\n for (const handle of this.handles) {\n handle.end(this.args);\n }\n this.handles.clear();\n }\n }\n\n get<PathT extends TypePath<T>>(\n ...fieldPath: PathT\n ): Promise<TypeAtPath<T, PathT>> {\n return new Promise<TypeAtPath<T, PathT>>((resolve, reject) => {\n const handle = new GetHandle<T, TypeAtPath<T, PathT>>(\n resolve,\n reject,\n fieldPath,\n );\n\n // Check if the field is already complete in current args\n if (\n this.args &&\n getPartialJsonObjectFieldState(\n this.args as Record<string, unknown>,\n fieldPath,\n ) === \"complete\"\n ) {\n const value = getField(this.args as T, fieldPath);\n if (value !== undefined) {\n resolve(value as TypeAtPath<T, PathT>);\n return;\n }\n }\n\n if (this.finished) {\n handle.end(this.args);\n return;\n }\n\n this.handles.add(handle);\n handle.update(this.args);\n });\n }\n\n streamValues<PathT extends TypePath<T>>(\n ...fieldPath: PathT\n ): AsyncIterableStream<DeepPartial<TypeAtPath<T, PathT>>> {\n // Use a type assertion to convert the complex TypePath to a simple array\n const simplePath = fieldPath as unknown as (string | number)[];\n\n let handle: StreamValuesHandle<T> | undefined;\n const stream = new ReadableStream<DeepPartial<TypeAtPath<T, PathT>>>({\n start: (controller) => {\n handle = new StreamValuesHandle<T>(controller, simplePath);\n if (!this.finished) this.handles.add(handle);\n\n // Check current args immediately\n handle.update(this.args);\n\n if (this.finished) handle.end();\n },\n cancel: () => {\n // Dispose this stream's own handle (captured above) — scanning for the\n // first match would dispose a concurrent streamValues()'s handle.\n if (handle) {\n handle.dispose();\n this.handles.delete(handle);\n }\n },\n });\n\n return asAsyncIterableStream(stream) as any;\n }\n\n streamText<PathT extends TypePath<T>>(\n ...fieldPath: PathT\n ): TypeAtPath<T, PathT> extends string & (infer U)\n ? AsyncIterableStream<U>\n : never {\n // Use a type assertion to convert the complex TypePath to a simple array\n const simplePath = fieldPath as unknown as (string | number)[];\n\n let handle: StreamTextHandle<T> | undefined;\n const stream = new ReadableStream<unknown>({\n start: (controller) => {\n handle = new StreamTextHandle<T>(controller, simplePath);\n if (!this.finished) this.handles.add(handle);\n\n // Check current args immediately\n handle.update(this.args);\n\n if (this.finished) handle.end();\n },\n cancel: () => {\n // Dispose this stream's own handle (captured above) — scanning for the\n // first match would dispose a concurrent streamText()'s handle.\n if (handle) {\n handle.dispose();\n this.handles.delete(handle);\n }\n },\n });\n\n return asAsyncIterableStream(stream) as any;\n }\n\n forEach<PathT extends TypePath<T>>(\n ...fieldPath: PathT\n ): NonNullable<TypeAtPath<T, PathT>> extends Array<infer U>\n ? AsyncIterableStream<U>\n : never {\n // Use a type assertion to convert the complex TypePath to a simple array\n const simplePath = fieldPath as unknown as (string | number)[];\n\n let handle: ForEachHandle<T> | undefined;\n const stream = new ReadableStream<unknown>({\n start: (controller) => {\n handle = new ForEachHandle<T>(controller, simplePath);\n if (!this.finished) this.handles.add(handle);\n\n // Check current args immediately\n handle.update(this.args);\n\n if (this.finished) handle.end();\n },\n cancel: () => {\n // Dispose this stream's own handle (captured above) — scanning for the\n // first match would dispose a concurrent forEach()'s handle.\n if (handle) {\n handle.dispose();\n this.handles.delete(handle);\n }\n },\n });\n\n return asAsyncIterableStream(stream) as any;\n }\n}\n\nexport class ToolCallResponseReaderImpl<\n TResult extends ReadonlyJSONValue,\n> implements ToolCallResponseReader<TResult> {\n constructor(private readonly promise: Promise<ToolResponse<TResult>>) {}\n\n public get() {\n return this.promise;\n }\n}\n\nexport class ToolCallReaderImpl<\n TArgs extends ReadonlyJSONObject,\n TResult extends ReadonlyJSONValue,\n> implements ToolCallReader<TArgs, TResult> {\n public readonly args: ToolCallArgsReaderImpl<TArgs>;\n public readonly response: ToolCallResponseReaderImpl<TResult>;\n private readonly writable: WritableStream<string>;\n private readonly resolve: (value: ToolResponse<TResult>) => void;\n\n public argsText: string = \"\";\n\n constructor() {\n const stream = new TransformStream<string, string>();\n this.writable = stream.writable;\n this.args = new ToolCallArgsReaderImpl<TArgs>(stream.readable);\n\n const { promise, resolve } = promiseWithResolvers<ToolResponse<TResult>>();\n this.resolve = resolve;\n this.response = new ToolCallResponseReaderImpl<TResult>(promise);\n }\n\n async appendArgsTextDelta(text: string): Promise<void> {\n const writer = this.writable.getWriter();\n try {\n await writer.write(text);\n } catch (err) {\n console.warn(err);\n } finally {\n writer.releaseLock();\n }\n\n this.argsText += text;\n }\n\n async finishArgsText(): Promise<void> {\n const writer = this.writable.getWriter();\n try {\n await writer.close();\n } catch (err) {\n console.warn(err);\n } finally {\n writer.releaseLock();\n }\n }\n\n setResponse(value: ToolResponse<TResult>): void {\n this.resolve(value);\n }\n\n result = {\n get: async () => {\n const response = await this.response.get();\n return response.result;\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -3,7 +3,6 @@ import { ToolCallReader } from "./tool-types.js";
|
|
|
3
3
|
import { ToolResponse } from "./ToolResponse.js";
|
|
4
4
|
import { AssistantStreamChunk } from "../AssistantStreamChunk.js";
|
|
5
5
|
import { PipeableTransformStream } from "../utils/stream/PipeableTransformStream.js";
|
|
6
|
-
|
|
7
6
|
//#region src/core/tool/ToolExecutionStream.d.ts
|
|
8
7
|
type ToolCallback = (toolCall: {
|
|
9
8
|
toolCallId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolExecutionStream.d.ts","names":[],"sources":["../../../src/core/tool/ToolExecutionStream.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ToolExecutionStream.d.ts","names":[],"sources":["../../../src/core/tool/ToolExecutionStream.ts"],"mappings":";;;;;;KAgBK,gBAAgB;EACnB;EACA;EACA,MAAM;MAEJ,QAAQ,aAAa,sBACrB,aAAa;KAGZ,sBACH,cAAc,qBAAqB,oBACnC,gBAAgB,oBAAoB,mBACpC;EACA,QAAQ,eAAe,OAAO;EAC9B;EACA;;KAGG;EACH,SAAS;EACT,YAAY;EACZ,qBACM,oBAAoB;EAE1B,mBAAmB,oBAAoB;;cAG5B,4BAA4B,wBACvC,sBACA;EAEY,YAAA,SAAS"}
|
|
@@ -9,6 +9,7 @@ var ToolExecutionStream = class extends PipeableTransformStream {
|
|
|
9
9
|
constructor(options) {
|
|
10
10
|
const toolCallPromises = /* @__PURE__ */ new Map();
|
|
11
11
|
const toolCallControllers = /* @__PURE__ */ new Map();
|
|
12
|
+
const toolCallIdsWithBackendResult = /* @__PURE__ */ new Set();
|
|
12
13
|
super((readable) => {
|
|
13
14
|
const transform = new TransformStream({
|
|
14
15
|
async transform(chunk, controller) {
|
|
@@ -44,6 +45,7 @@ var ToolExecutionStream = class extends PipeableTransformStream {
|
|
|
44
45
|
isError: chunk.isError,
|
|
45
46
|
modelContent: chunk.modelContent
|
|
46
47
|
}));
|
|
48
|
+
toolCallIdsWithBackendResult.add(toolCallId);
|
|
47
49
|
break;
|
|
48
50
|
}
|
|
49
51
|
case "tool-call-args-text-finish": {
|
|
@@ -52,6 +54,7 @@ var ToolExecutionStream = class extends PipeableTransformStream {
|
|
|
52
54
|
const streamController = toolCallControllers.get(toolCallId);
|
|
53
55
|
if (!streamController) throw new Error("No controller found for tool call");
|
|
54
56
|
await streamController.finishArgsText();
|
|
57
|
+
if (toolCallIdsWithBackendResult.has(toolCallId)) break;
|
|
55
58
|
let isExecuting = false;
|
|
56
59
|
const promise = withPromiseOrValue(() => {
|
|
57
60
|
let args;
|
|
@@ -109,9 +112,14 @@ var ToolExecutionStream = class extends PipeableTransformStream {
|
|
|
109
112
|
if (toolCallPromise) toolCallPromise.then(() => {
|
|
110
113
|
toolCallPromises.delete(toolCallId);
|
|
111
114
|
toolCallControllers.delete(toolCallId);
|
|
115
|
+
toolCallIdsWithBackendResult.delete(toolCallId);
|
|
112
116
|
controller.enqueue(chunk);
|
|
113
117
|
});
|
|
114
|
-
else
|
|
118
|
+
else {
|
|
119
|
+
toolCallControllers.delete(toolCallId);
|
|
120
|
+
toolCallIdsWithBackendResult.delete(toolCallId);
|
|
121
|
+
controller.enqueue(chunk);
|
|
122
|
+
}
|
|
115
123
|
}
|
|
116
124
|
}
|
|
117
125
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolExecutionStream.js","names":[],"sources":["../../../src/core/tool/ToolExecutionStream.ts"],"sourcesContent":["import sjson from \"secure-json-parse\";\nimport type { AssistantStreamChunk } from \"../AssistantStreamChunk\";\nimport {\n type AssistantMetaStreamChunk,\n AssistantMetaTransformStream,\n} from \"../utils/stream/AssistantMetaTransformStream\";\nimport { PipeableTransformStream } from \"../utils/stream/PipeableTransformStream\";\nimport type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"../../utils/json/json-value\";\nimport { ToolResponse } from \"./ToolResponse\";\nimport { withPromiseOrValue } from \"../utils/withPromiseOrValue\";\nimport { ToolCallReaderImpl } from \"./ToolCallReader\";\nimport type { ToolCallReader } from \"./tool-types\";\n\ntype ToolCallback = (toolCall: {\n toolCallId: string;\n toolName: string;\n args: ReadonlyJSONObject;\n}) =>\n | Promise<ToolResponse<ReadonlyJSONValue>>\n | ToolResponse<ReadonlyJSONValue>\n | undefined;\n\ntype ToolStreamCallback = <\n TArgs extends ReadonlyJSONObject = ReadonlyJSONObject,\n TResult extends ReadonlyJSONValue = ReadonlyJSONValue,\n>(toolCall: {\n reader: ToolCallReader<TArgs, TResult>;\n toolCallId: string;\n toolName: string;\n}) => void;\n\ntype ToolExecutionOptions = {\n execute: ToolCallback;\n streamCall: ToolStreamCallback;\n onExecutionStart?:\n | ((toolCallId: string, toolName: string) => void)\n | undefined;\n onExecutionEnd?: ((toolCallId: string, toolName: string) => void) | undefined;\n};\n\nexport class ToolExecutionStream extends PipeableTransformStream<\n AssistantStreamChunk,\n AssistantStreamChunk\n> {\n constructor(options: ToolExecutionOptions) {\n const toolCallPromises = new Map<string, PromiseLike<void>>();\n const toolCallControllers = new Map<\n string,\n ToolCallReaderImpl<ReadonlyJSONObject, ReadonlyJSONValue>\n >();\n\n super((readable) => {\n const transform = new TransformStream<\n AssistantMetaStreamChunk,\n AssistantStreamChunk\n >({\n async transform(chunk, controller) {\n // forward everything\n if (chunk.type !== \"part-finish\" || chunk.meta.type !== \"tool-call\") {\n controller.enqueue(chunk);\n }\n\n const type = chunk.type;\n\n switch (type) {\n case \"part-start\":\n if (chunk.part.type === \"tool-call\") {\n const reader = new ToolCallReaderImpl<\n ReadonlyJSONObject,\n ReadonlyJSONValue\n >();\n toolCallControllers.set(chunk.part.toolCallId, reader);\n\n options.streamCall({\n reader,\n toolCallId: chunk.part.toolCallId,\n toolName: chunk.part.toolName,\n });\n }\n break;\n case \"text-delta\": {\n if (chunk.meta.type === \"tool-call\") {\n const toolCallId = chunk.meta.toolCallId;\n\n const controller = toolCallControllers.get(toolCallId);\n if (!controller)\n throw new Error(\"No controller found for tool call\");\n // Awaited so the writer lock is released (and argsText updated)\n // before the next chunk acquires the writer.\n await controller.appendArgsTextDelta(chunk.textDelta);\n }\n break;\n }\n case \"result\": {\n if (chunk.meta.type !== \"tool-call\") break;\n\n const { toolCallId } = chunk.meta;\n const controller = toolCallControllers.get(toolCallId);\n if (!controller)\n throw new Error(\"No controller found for tool call\");\n controller.setResponse(\n new ToolResponse({\n result: chunk.result,\n artifact: chunk.artifact,\n isError: chunk.isError,\n modelContent: chunk.modelContent,\n }),\n );\n break;\n }\n case \"tool-call-args-text-finish\": {\n if (chunk.meta.type !== \"tool-call\") break;\n\n const { toolCallId, toolName } = chunk.meta;\n const streamController = toolCallControllers.get(toolCallId)!;\n if (!streamController)\n throw new Error(\"No controller found for tool call\");\n\n // Args fully streamed: close the reader so awaited absent fields\n // resolve. Awaited so the close settles before the writer is reused.\n await streamController.finishArgsText();\n\n let isExecuting = false;\n const promise = withPromiseOrValue(\n () => {\n let args: ReadonlyJSONObject;\n try {\n args = sjson.parse(\n streamController.argsText,\n ) as ReadonlyJSONObject;\n } catch (e) {\n throw new Error(\n `Function parameter parsing failed. ${JSON.stringify((e as Error).message)}`,\n );\n }\n\n const executeResult = options.execute({\n toolCallId,\n toolName,\n args,\n });\n\n // Only mark as executing if the tool has frontend execution\n if (executeResult !== undefined) {\n isExecuting = true;\n options.onExecutionStart?.(toolCallId, toolName);\n }\n\n return executeResult;\n },\n (c) => {\n if (isExecuting) {\n options.onExecutionEnd?.(toolCallId, toolName);\n }\n\n if (c === undefined) return;\n\n // TODO how to handle new ToolResult({ result: undefined })?\n const result = new ToolResponse({\n artifact: c.artifact,\n result: c.result,\n isError: c.isError,\n messages: c.messages,\n modelContent: c.modelContent,\n });\n streamController.setResponse(result);\n controller.enqueue({\n type: \"result\",\n path: chunk.path,\n ...result,\n });\n },\n (e) => {\n if (isExecuting) {\n options.onExecutionEnd?.(toolCallId, toolName);\n }\n\n const result = new ToolResponse({\n result: String(e),\n isError: true,\n });\n\n streamController.setResponse(result);\n controller.enqueue({\n type: \"result\",\n path: chunk.path,\n ...result,\n });\n },\n );\n if (promise) {\n toolCallPromises.set(toolCallId, promise);\n }\n break;\n }\n\n case \"part-finish\": {\n if (chunk.meta.type !== \"tool-call\") break;\n\n const { toolCallId } = chunk.meta;\n const toolCallPromise = toolCallPromises.get(toolCallId);\n if (toolCallPromise) {\n toolCallPromise.then(() => {\n toolCallPromises.delete(toolCallId);\n toolCallControllers.delete(toolCallId);\n\n controller.enqueue(chunk);\n });\n } else {\n controller.enqueue(chunk);\n }\n }\n }\n },\n async flush() {\n await Promise.all(toolCallPromises.values());\n },\n });\n\n return readable\n .pipeThrough(new AssistantMetaTransformStream())\n .pipeThrough(transform);\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToolExecutionStream.js","names":[],"sources":["../../../src/core/tool/ToolExecutionStream.ts"],"sourcesContent":["import sjson from \"secure-json-parse\";\nimport type { AssistantStreamChunk } from \"../AssistantStreamChunk\";\nimport {\n type AssistantMetaStreamChunk,\n AssistantMetaTransformStream,\n} from \"../utils/stream/AssistantMetaTransformStream\";\nimport { PipeableTransformStream } from \"../utils/stream/PipeableTransformStream\";\nimport type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"../../utils/json/json-value\";\nimport { ToolResponse } from \"./ToolResponse\";\nimport { withPromiseOrValue } from \"../utils/withPromiseOrValue\";\nimport { ToolCallReaderImpl } from \"./ToolCallReader\";\nimport type { ToolCallReader } from \"./tool-types\";\n\ntype ToolCallback = (toolCall: {\n toolCallId: string;\n toolName: string;\n args: ReadonlyJSONObject;\n}) =>\n | Promise<ToolResponse<ReadonlyJSONValue>>\n | ToolResponse<ReadonlyJSONValue>\n | undefined;\n\ntype ToolStreamCallback = <\n TArgs extends ReadonlyJSONObject = ReadonlyJSONObject,\n TResult extends ReadonlyJSONValue = ReadonlyJSONValue,\n>(toolCall: {\n reader: ToolCallReader<TArgs, TResult>;\n toolCallId: string;\n toolName: string;\n}) => void;\n\ntype ToolExecutionOptions = {\n execute: ToolCallback;\n streamCall: ToolStreamCallback;\n onExecutionStart?:\n | ((toolCallId: string, toolName: string) => void)\n | undefined;\n onExecutionEnd?: ((toolCallId: string, toolName: string) => void) | undefined;\n};\n\nexport class ToolExecutionStream extends PipeableTransformStream<\n AssistantStreamChunk,\n AssistantStreamChunk\n> {\n constructor(options: ToolExecutionOptions) {\n const toolCallPromises = new Map<string, PromiseLike<void>>();\n const toolCallControllers = new Map<\n string,\n ToolCallReaderImpl<ReadonlyJSONObject, ReadonlyJSONValue>\n >();\n const toolCallIdsWithBackendResult = new Set<string>();\n\n super((readable) => {\n const transform = new TransformStream<\n AssistantMetaStreamChunk,\n AssistantStreamChunk\n >({\n async transform(chunk, controller) {\n // forward everything\n if (chunk.type !== \"part-finish\" || chunk.meta.type !== \"tool-call\") {\n controller.enqueue(chunk);\n }\n\n const type = chunk.type;\n\n switch (type) {\n case \"part-start\":\n if (chunk.part.type === \"tool-call\") {\n const reader = new ToolCallReaderImpl<\n ReadonlyJSONObject,\n ReadonlyJSONValue\n >();\n toolCallControllers.set(chunk.part.toolCallId, reader);\n\n options.streamCall({\n reader,\n toolCallId: chunk.part.toolCallId,\n toolName: chunk.part.toolName,\n });\n }\n break;\n case \"text-delta\": {\n if (chunk.meta.type === \"tool-call\") {\n const toolCallId = chunk.meta.toolCallId;\n\n const controller = toolCallControllers.get(toolCallId);\n if (!controller)\n throw new Error(\"No controller found for tool call\");\n // Awaited so the writer lock is released (and argsText updated)\n // before the next chunk acquires the writer.\n await controller.appendArgsTextDelta(chunk.textDelta);\n }\n break;\n }\n case \"result\": {\n if (chunk.meta.type !== \"tool-call\") break;\n\n const { toolCallId } = chunk.meta;\n const controller = toolCallControllers.get(toolCallId);\n if (!controller)\n throw new Error(\"No controller found for tool call\");\n controller.setResponse(\n new ToolResponse({\n result: chunk.result,\n artifact: chunk.artifact,\n isError: chunk.isError,\n modelContent: chunk.modelContent,\n }),\n );\n toolCallIdsWithBackendResult.add(toolCallId);\n break;\n }\n case \"tool-call-args-text-finish\": {\n if (chunk.meta.type !== \"tool-call\") break;\n\n const { toolCallId, toolName } = chunk.meta;\n const streamController = toolCallControllers.get(toolCallId)!;\n if (!streamController)\n throw new Error(\"No controller found for tool call\");\n\n // Args fully streamed: close the reader so awaited absent fields\n // resolve. Awaited so the close settles before the writer is reused.\n await streamController.finishArgsText();\n\n // A backend result is authoritative. Closing the args stream still\n // emits this finish chunk, but must not parse stale/incomplete args,\n // execute the frontend tool, or enqueue a second result.\n if (toolCallIdsWithBackendResult.has(toolCallId)) break;\n\n let isExecuting = false;\n const promise = withPromiseOrValue(\n () => {\n let args: ReadonlyJSONObject;\n try {\n args = sjson.parse(\n streamController.argsText,\n ) as ReadonlyJSONObject;\n } catch (e) {\n throw new Error(\n `Function parameter parsing failed. ${JSON.stringify((e as Error).message)}`,\n );\n }\n\n const executeResult = options.execute({\n toolCallId,\n toolName,\n args,\n });\n\n // Only mark as executing if the tool has frontend execution\n if (executeResult !== undefined) {\n isExecuting = true;\n options.onExecutionStart?.(toolCallId, toolName);\n }\n\n return executeResult;\n },\n (c) => {\n if (isExecuting) {\n options.onExecutionEnd?.(toolCallId, toolName);\n }\n\n if (c === undefined) return;\n\n // TODO how to handle new ToolResult({ result: undefined })?\n const result = new ToolResponse({\n artifact: c.artifact,\n result: c.result,\n isError: c.isError,\n messages: c.messages,\n modelContent: c.modelContent,\n });\n streamController.setResponse(result);\n controller.enqueue({\n type: \"result\",\n path: chunk.path,\n ...result,\n });\n },\n (e) => {\n if (isExecuting) {\n options.onExecutionEnd?.(toolCallId, toolName);\n }\n\n const result = new ToolResponse({\n result: String(e),\n isError: true,\n });\n\n streamController.setResponse(result);\n controller.enqueue({\n type: \"result\",\n path: chunk.path,\n ...result,\n });\n },\n );\n if (promise) {\n toolCallPromises.set(toolCallId, promise);\n }\n break;\n }\n\n case \"part-finish\": {\n if (chunk.meta.type !== \"tool-call\") break;\n\n const { toolCallId } = chunk.meta;\n const toolCallPromise = toolCallPromises.get(toolCallId);\n if (toolCallPromise) {\n toolCallPromise.then(() => {\n toolCallPromises.delete(toolCallId);\n toolCallControllers.delete(toolCallId);\n toolCallIdsWithBackendResult.delete(toolCallId);\n\n controller.enqueue(chunk);\n });\n } else {\n toolCallControllers.delete(toolCallId);\n toolCallIdsWithBackendResult.delete(toolCallId);\n controller.enqueue(chunk);\n }\n }\n }\n },\n async flush() {\n await Promise.all(toolCallPromises.values());\n },\n });\n\n return readable\n .pipeThrough(new AssistantMetaTransformStream())\n .pipeThrough(transform);\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import { ReadonlyJSONValue } from "../../utils/json/json-value.js";
|
|
2
2
|
import { ToolModelContentPart } from "./tool-types.js";
|
|
3
|
-
|
|
4
3
|
//#region src/core/tool/ToolResponse.d.ts
|
|
5
4
|
declare const TOOL_RESPONSE_SYMBOL: unique symbol;
|
|
6
5
|
/**
|
|
7
6
|
* Shape accepted anywhere a {@link ToolResponse} can be returned.
|
|
8
7
|
*/
|
|
9
8
|
type ToolResponseLike<TResult> = {
|
|
10
|
-
/** UI-visible tool result value. */
|
|
9
|
+
/** UI-visible tool result value. */
|
|
10
|
+
result: TResult;
|
|
11
11
|
/**
|
|
12
12
|
* Optional UI-only artifact associated with the result.
|
|
13
13
|
*
|
|
14
14
|
* Artifacts are useful for large or structured data that should be available
|
|
15
15
|
* to renderers without necessarily being sent back to the model.
|
|
16
16
|
*/
|
|
17
|
-
artifact?: ReadonlyJSONValue | undefined;
|
|
17
|
+
artifact?: ReadonlyJSONValue | undefined;
|
|
18
|
+
/** Marks the tool result as an error result. */
|
|
18
19
|
isError?: boolean | undefined;
|
|
19
20
|
/**
|
|
20
21
|
* Explicit model-visible content to send back after the tool call.
|
|
@@ -22,7 +23,8 @@ type ToolResponseLike<TResult> = {
|
|
|
22
23
|
* When omitted, assistant-ui derives model output from `result` or a tool's
|
|
23
24
|
* {@link ToolModelOutputFunction}.
|
|
24
25
|
*/
|
|
25
|
-
modelContent?: readonly ToolModelContentPart[] | undefined;
|
|
26
|
+
modelContent?: readonly ToolModelContentPart[] | undefined;
|
|
27
|
+
/** Optional provider-specific message payload associated with the tool result. */
|
|
26
28
|
messages?: ReadonlyJSONValue | undefined;
|
|
27
29
|
};
|
|
28
30
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolResponse.d.ts","names":[],"sources":["../../../src/core/tool/ToolResponse.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"ToolResponse.d.ts","names":[],"sources":["../../../src/core/tool/ToolResponse.ts"],"mappings":";;;cAOM;;;;KAKM,iBAAiB;;EAE3B,QAAQ;;;;;;;EAOR,WAAW;;EAEX;;;;;;;EAOA,wBAAwB;;EAExB,WAAW;;;;;;;;;;;;;;;;;;cAmBA,aAAa;OACnB;WAII,WAAW;WACX,QAAQ;WACR;WACA,wBAAwB;WACxB,WAAW;EAER,YAAA,SAAS,iBAAiB;UAc9B,OAAO,aACb,eACC,OAAO,aAAa;;;;;;;;SAahB,WAAW,cAAc,oBAAoB"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { JSONSchema7 } from "../../node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.js";
|
|
2
2
|
import { ProviderOptions, Tool } from "./tool-types.js";
|
|
3
3
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
4
|
-
|
|
5
4
|
//#region src/core/tool/schema-utils.d.ts
|
|
6
5
|
/**
|
|
7
6
|
* Type for a tool definition with JSON Schema parameters.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-utils.d.ts","names":[],"sources":["../../../src/core/tool/schema-utils.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"schema-utils.d.ts","names":[],"sources":["../../../src/core/tool/schema-utils.ts"],"mappings":";;;;;;;KAOY;EACV;EACA,YAAY;EACZ,kBAAkB;;KAGR;;;;;;;EAOV,UAAU,cAAc,MAAM;;;;;;;;;;;iBA8ChB,aACd,QAAQ,mBAAmB,cAC1B;;;;;iBA+Ca,oBAAoB,QAAQ,cAAc;;;;;;;;;;iBA2C1C,kBACd,OAAO,eAAe,mBACtB,UAAS,2BACR,eAAe"}
|