assistant-stream 0.3.26 → 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/dist/core/AssistantStream.d.ts.map +1 -1
- package/dist/core/AssistantStreamChunk.d.ts +3 -3
- package/dist/core/accumulators/AssistantMessageStream.d.ts.map +1 -1
- package/dist/core/accumulators/assistant-message-accumulator.d.ts.map +1 -1
- package/dist/core/accumulators/assistant-message-accumulator.js +65 -28
- package/dist/core/accumulators/assistant-message-accumulator.js.map +1 -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/{object → gorp}/types.d.ts +6 -5
- package/dist/core/gorp/types.d.ts.map +1 -0
- package/dist/core/modules/assistant-stream.d.ts +5 -4
- 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/tool-call.js +2 -2
- package/dist/core/modules/tool-call.js.map +1 -1
- package/dist/core/serialization/assistant-transport/AssistantTransport.d.ts.map +1 -1
- package/dist/core/serialization/assistant-transport/AssistantTransport.js +91 -1
- package/dist/core/serialization/assistant-transport/AssistantTransport.js.map +1 -1
- package/dist/core/serialization/data-stream/chunk-types.d.ts +2 -2
- package/dist/core/serialization/data-stream/chunk-types.js.map +1 -1
- package/dist/core/serialization/ui-message-stream/UIMessageStream.d.ts.map +1 -1
- package/dist/core/serialization/ui-message-stream/UIMessageStream.js +11 -1
- package/dist/core/serialization/ui-message-stream/UIMessageStream.js.map +1 -1
- 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.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.map +1 -1
- 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/utils/stream/AssistantTransformStream.d.ts.map +1 -1
- package/dist/core/utils/stream/PipeableTransformStream.d.ts.map +1 -1
- package/dist/core/utils/stream/SSEEventDecoder.d.ts.map +1 -1
- package/dist/core/utils/stream/merge.d.ts +2 -0
- 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.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/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/errors.d.ts.map +1 -1
- package/dist/resumable/stores/redis-impl.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/promiseWithResolvers.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/core/AssistantStreamChunk.ts +3 -3
- package/src/core/accumulators/assistant-message-accumulator.test.ts +374 -1
- package/src/core/accumulators/assistant-message-accumulator.ts +75 -26
- package/src/core/{object/ObjectStream.test.ts → gorp/GorpStream.test.ts} +86 -25
- 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/{object/ObjectStreamResponse.test.ts → gorp/GorpStreamResponse.test.ts} +6 -6
- 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 +174 -1
- package/src/core/serialization/assistant-transport/AssistantTransport.ts +77 -1
- package/src/core/serialization/data-stream/chunk-types.ts +2 -2
- package/src/core/serialization/ui-message-stream/UIMessageStream.test.ts +111 -0
- package/src/core/serialization/ui-message-stream/UIMessageStream.ts +20 -1
- 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/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/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 -16
- 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 -16
- 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.map +0 -1
- package/src/core/object/ObjectStreamResponse.ts +0 -114
- /package/dist/core/{object → gorp}/types.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantStream.d.ts","names":[],"sources":["../../src/core/AssistantStream.ts"],"mappings":";;;;;;;;;;KAUY,kBAAkB,eAAe;;;;;;;;KASjC,yBAAyB,qBACnC,WAAW,cACX;EAEA,UAAU;;cAGC;;;;;;;;
|
|
1
|
+
{"version":3,"file":"AssistantStream.d.ts","names":[],"sources":["../../src/core/AssistantStream.ts"],"mappings":";;;;;;;;;;KAUY,kBAAkB,eAAe;;;;;;;;KASjC,yBAAyB,qBACnC,WAAW,cACX;EAEA,UAAU;;cAGC;;;;;;;;EAQQ,WAAA,QAAA,iBAAe,aAAe,yBAAsB;;;;;;;;EAc3D,aAAA,UAAA,UAAQ,aACL,qBACX,sBACA,WAAW,gBACZ,eAAA;;;;;EAUO,aAAA,QAAA,iBAAe,aACV,qBACX,WAAW,cACX,wBACD,eAAA,WAAA;;;;;EAUS,eAAA,UAAA,eAAe,WAAW,eAAa,aACpC,qBACX,sBACA,WAAW,gBACZ,eAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReadonlyJSONValue } from "../utils/json/json-value.js";
|
|
2
2
|
import { ToolModelContentPart } from "./tool/tool-types.js";
|
|
3
|
-
import {
|
|
3
|
+
import { AssistantTransportStateOperation } from "./gorp/types.js";
|
|
4
4
|
//#region src/core/AssistantStreamChunk.d.ts
|
|
5
5
|
/**
|
|
6
6
|
* Initial metadata for a stream part.
|
|
@@ -106,9 +106,9 @@ type AssistantStreamChunk = {
|
|
|
106
106
|
readonly code?: string;
|
|
107
107
|
readonly severity?: "critical" | "warning" | "info";
|
|
108
108
|
} | {
|
|
109
|
-
/** Applies
|
|
109
|
+
/** Applies gorp-stream operations to state carried by this stream. */
|
|
110
110
|
readonly type: "update-state";
|
|
111
|
-
readonly operations:
|
|
111
|
+
readonly operations: AssistantTransportStateOperation[];
|
|
112
112
|
});
|
|
113
113
|
//#endregion
|
|
114
114
|
export { AssistantStreamChunk, PartInit };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantMessageStream.d.ts","names":[],"sources":["../../../src/core/accumulators/AssistantMessageStream.ts"],"mappings":";;;cAIa;WACiB,UAAU,eAAe;
|
|
1
|
+
{"version":3,"file":"AssistantMessageStream.d.ts","names":[],"sources":["../../../src/core/accumulators/AssistantMessageStream.ts"],"mappings":";;;cAIa;WACiB,UAAU,eAAe;EAAzB,YAAA,UAAU,eAAe;SAI9C,oBAAoB,QAAQ,kBAAe;EAM5C,mBAAmB,QAAQ;GAwBhC,OAAO;IAGU,QAAA,QAAQ,eAAe;;EAOzC,QAAQ,wBAAwB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-message-accumulator.d.ts","names":[],"sources":["../../../src/core/accumulators/assistant-message-accumulator.ts"],"mappings":";;;;;cAmBa,yBAAwB;EAGnC,iBAAiB;MACV;
|
|
1
|
+
{"version":3,"file":"assistant-message-accumulator.d.ts","names":[],"sources":["../../../src/core/accumulators/assistant-message-accumulator.ts"],"mappings":";;;;;cAmBa,yBAAwB;EAGnC,iBAAiB;MACV;cAwcI,oCAAoC,gBAC/C,sBACA;EAEY,cACV,gBACA,UACA;IAEA,iBAAiB;IACjB;IACA,WAAW"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { generateId } from "../utils/generateId.js";
|
|
2
2
|
import { parsePartialJsonObject } from "../../utils/json/parse-partial-json-object.js";
|
|
3
|
-
import {
|
|
3
|
+
import { GorpStreamAccumulator } from "../gorp/GorpStreamAccumulator.js";
|
|
4
4
|
import { TimingTracker } from "./TimingTracker.js";
|
|
5
5
|
//#region src/core/accumulators/assistant-message-accumulator.ts
|
|
6
6
|
const createInitialMessage = ({ unstable_state = null } = {}) => ({
|
|
@@ -18,11 +18,16 @@ const createInitialMessage = ({ unstable_state = null } = {}) => ({
|
|
|
18
18
|
custom: {}
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
const MAX_WARNED_KEYS = 16;
|
|
22
|
+
const updatePartForPath = (message, chunk, warnOnce, updater) => {
|
|
23
|
+
const part = chunk.path.length === 1 ? message.parts[chunk.path[0]] : void 0;
|
|
24
|
+
if (part === void 0) {
|
|
25
|
+
warnOnce(`no-part:${chunk.type}`, `Dropped ${chunk.type} chunk: no part at path [${chunk.path.join(", ")}]`);
|
|
26
|
+
return message;
|
|
27
|
+
}
|
|
24
28
|
const partIndex = chunk.path[0];
|
|
25
|
-
const updatedPart = updater(
|
|
29
|
+
const updatedPart = updater(part);
|
|
30
|
+
if (updatedPart === part) return message;
|
|
26
31
|
return {
|
|
27
32
|
...message,
|
|
28
33
|
parts: [
|
|
@@ -35,7 +40,7 @@ const updatePartForPath = (message, chunk, updater) => {
|
|
|
35
40
|
}
|
|
36
41
|
};
|
|
37
42
|
};
|
|
38
|
-
const handlePartStart = (message, chunk) => {
|
|
43
|
+
const handlePartStart = (message, chunk, warnOnce) => {
|
|
39
44
|
const partInit = chunk.part;
|
|
40
45
|
if (partInit.type === "text" || partInit.type === "reasoning") {
|
|
41
46
|
const newTextPart = {
|
|
@@ -117,20 +122,38 @@ const handlePartStart = (message, chunk) => {
|
|
|
117
122
|
return this.parts;
|
|
118
123
|
}
|
|
119
124
|
};
|
|
120
|
-
} else
|
|
125
|
+
} else {
|
|
126
|
+
const unsupportedType = String(partInit.type);
|
|
127
|
+
warnOnce(`unsupported-part-start:${unsupportedType}`, `Unsupported part-start type ${unsupportedType}: inserting an empty reasoning part to preserve part indices`);
|
|
128
|
+
const placeholderPart = {
|
|
129
|
+
type: "reasoning",
|
|
130
|
+
text: "",
|
|
131
|
+
status: { type: "running" }
|
|
132
|
+
};
|
|
133
|
+
return {
|
|
134
|
+
...message,
|
|
135
|
+
parts: [...message.parts, placeholderPart],
|
|
136
|
+
get content() {
|
|
137
|
+
return this.parts;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
121
141
|
};
|
|
122
|
-
const handleToolCallArgsTextFinish = (message, chunk) => {
|
|
123
|
-
return updatePartForPath(message, chunk, (part) => {
|
|
124
|
-
if (part.type !== "tool-call")
|
|
125
|
-
|
|
142
|
+
const handleToolCallArgsTextFinish = (message, chunk, warnOnce) => {
|
|
143
|
+
return updatePartForPath(message, chunk, warnOnce, (part) => {
|
|
144
|
+
if (part.type !== "tool-call") {
|
|
145
|
+
warnOnce("wrong-part:tool-call-args-text-finish", "Dropped tool-call-args-text-finish chunk: part is not a tool-call");
|
|
146
|
+
return part;
|
|
147
|
+
}
|
|
148
|
+
if (part.state !== "partial-call") return { ...part };
|
|
126
149
|
return {
|
|
127
150
|
...part,
|
|
128
151
|
state: "call"
|
|
129
152
|
};
|
|
130
153
|
});
|
|
131
154
|
};
|
|
132
|
-
const handlePartFinish = (message, chunk) => {
|
|
133
|
-
return updatePartForPath(message, chunk, (part) => ({
|
|
155
|
+
const handlePartFinish = (message, chunk, warnOnce) => {
|
|
156
|
+
return updatePartForPath(message, chunk, warnOnce, (part) => ({
|
|
134
157
|
...part,
|
|
135
158
|
status: {
|
|
136
159
|
type: "complete",
|
|
@@ -138,8 +161,8 @@ const handlePartFinish = (message, chunk) => {
|
|
|
138
161
|
}
|
|
139
162
|
}));
|
|
140
163
|
};
|
|
141
|
-
const handleTextDelta = (message, chunk) => {
|
|
142
|
-
return updatePartForPath(message, chunk, (part) => {
|
|
164
|
+
const handleTextDelta = (message, chunk, warnOnce) => {
|
|
165
|
+
return updatePartForPath(message, chunk, warnOnce, (part) => {
|
|
143
166
|
if (part.type === "text" || part.type === "reasoning") return {
|
|
144
167
|
...part,
|
|
145
168
|
text: part.text + chunk.textDelta
|
|
@@ -152,11 +175,14 @@ const handleTextDelta = (message, chunk) => {
|
|
|
152
175
|
argsText: newArgsText,
|
|
153
176
|
args: newArgs
|
|
154
177
|
};
|
|
155
|
-
} else
|
|
178
|
+
} else {
|
|
179
|
+
warnOnce("wrong-part:text-delta", "Dropped text-delta chunk: part is neither text nor tool-call");
|
|
180
|
+
return part;
|
|
181
|
+
}
|
|
156
182
|
});
|
|
157
183
|
};
|
|
158
|
-
const handleResult = (message, chunk) => {
|
|
159
|
-
return updatePartForPath(message, chunk, (part) => {
|
|
184
|
+
const handleResult = (message, chunk, warnOnce) => {
|
|
185
|
+
return updatePartForPath(message, chunk, warnOnce, (part) => {
|
|
160
186
|
if (part.type === "tool-call") return {
|
|
161
187
|
...part,
|
|
162
188
|
state: "result",
|
|
@@ -174,7 +200,10 @@ const handleResult = (message, chunk) => {
|
|
|
174
200
|
reason: "stop"
|
|
175
201
|
}
|
|
176
202
|
};
|
|
177
|
-
else
|
|
203
|
+
else {
|
|
204
|
+
warnOnce("wrong-part:result", "Dropped result chunk: part is not a tool-call");
|
|
205
|
+
return part;
|
|
206
|
+
}
|
|
178
207
|
});
|
|
179
208
|
};
|
|
180
209
|
const handleMessageFinish = (message, chunk) => {
|
|
@@ -263,14 +292,14 @@ const handleErrorChunk = (message, chunk) => {
|
|
|
263
292
|
reason: "error",
|
|
264
293
|
error: {
|
|
265
294
|
code: chunk.code ?? "unknown",
|
|
266
|
-
message: chunk.error,
|
|
295
|
+
message: chunk.error ?? "unknown error",
|
|
267
296
|
...severity !== void 0 && { severity }
|
|
268
297
|
}
|
|
269
298
|
}
|
|
270
299
|
};
|
|
271
300
|
};
|
|
272
301
|
const handleUpdateState = (message, chunk) => {
|
|
273
|
-
const acc = new
|
|
302
|
+
const acc = new GorpStreamAccumulator(message.metadata.unstable_state);
|
|
274
303
|
acc.append(chunk.operations);
|
|
275
304
|
return {
|
|
276
305
|
...message,
|
|
@@ -302,6 +331,12 @@ var AssistantMessageAccumulator = class extends TransformStream {
|
|
|
302
331
|
constructor({ initialMessage, throttle, onError } = {}) {
|
|
303
332
|
let message = initialMessage ?? createInitialMessage();
|
|
304
333
|
const tracker = new TimingTracker();
|
|
334
|
+
const warnedKeys = /* @__PURE__ */ new Set();
|
|
335
|
+
const warnOnce = (key, warning) => {
|
|
336
|
+
if (warnedKeys.has(key) || warnedKeys.size >= MAX_WARNED_KEYS) return;
|
|
337
|
+
warnedKeys.add(key);
|
|
338
|
+
console.warn(warning);
|
|
339
|
+
};
|
|
305
340
|
let controller;
|
|
306
341
|
const emitChunk = throttle ? throttleCallback(() => {
|
|
307
342
|
controller?.enqueue(message);
|
|
@@ -317,21 +352,23 @@ var AssistantMessageAccumulator = class extends TransformStream {
|
|
|
317
352
|
const type = chunk.type;
|
|
318
353
|
switch (type) {
|
|
319
354
|
case "part-start":
|
|
320
|
-
message = handlePartStart(message, chunk);
|
|
355
|
+
message = handlePartStart(message, chunk, warnOnce);
|
|
321
356
|
if (chunk.part.type === "tool-call") tracker.recordToolCallStart(chunk.part.toolCallId);
|
|
322
357
|
break;
|
|
323
358
|
case "tool-call-args-text-finish":
|
|
324
|
-
message = handleToolCallArgsTextFinish(message, chunk);
|
|
359
|
+
message = handleToolCallArgsTextFinish(message, chunk, warnOnce);
|
|
325
360
|
break;
|
|
326
361
|
case "part-finish":
|
|
327
|
-
message = handlePartFinish(message, chunk);
|
|
362
|
+
message = handlePartFinish(message, chunk, warnOnce);
|
|
328
363
|
break;
|
|
329
|
-
case "text-delta":
|
|
330
|
-
|
|
331
|
-
tracker.recordFirstToken();
|
|
364
|
+
case "text-delta": {
|
|
365
|
+
const next = handleTextDelta(message, chunk, warnOnce);
|
|
366
|
+
if (next !== message) tracker.recordFirstToken();
|
|
367
|
+
message = next;
|
|
332
368
|
break;
|
|
369
|
+
}
|
|
333
370
|
case "result":
|
|
334
|
-
message = handleResult(message, chunk);
|
|
371
|
+
message = handleResult(message, chunk, warnOnce);
|
|
335
372
|
break;
|
|
336
373
|
case "message-finish":
|
|
337
374
|
message = handleMessageFinish(message, chunk);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-message-accumulator.js","names":["unhandledType"],"sources":["../../../src/core/accumulators/assistant-message-accumulator.ts"],"sourcesContent":["import type { AssistantStreamChunk } from \"../AssistantStreamChunk\";\nimport { generateId } from \"../utils/generateId\";\nimport { parsePartialJsonObject } from \"../../utils/json/parse-partial-json-object\";\nimport type {\n AssistantMessage,\n AssistantMessageStatus,\n AssistantMessageTiming,\n TextPart,\n ToolCallPart,\n SourcePart,\n AssistantMessagePart,\n ReasoningPart,\n FilePart,\n DataPart,\n} from \"../utils/types\";\nimport { ObjectStreamAccumulator } from \"../object/ObjectStreamAccumulator\";\nimport type { ReadonlyJSONValue } from \"../../utils\";\nimport { TimingTracker } from \"./TimingTracker\";\n\nexport const createInitialMessage = ({\n unstable_state = null,\n}: {\n unstable_state?: ReadonlyJSONValue;\n} = {}): AssistantMessage => ({\n role: \"assistant\",\n status: { type: \"running\" },\n parts: [],\n get content() {\n return this.parts;\n },\n metadata: {\n unstable_state,\n unstable_data: [],\n unstable_annotations: [],\n steps: [],\n custom: {},\n },\n});\n\nconst updatePartForPath = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk,\n updater: (part: AssistantMessagePart) => AssistantMessagePart,\n): AssistantMessage => {\n if (message.parts.length === 0) {\n throw new Error(\"No parts available to update.\");\n }\n\n if (chunk.path.length !== 1)\n throw new Error(\"Nested paths are not supported yet.\");\n\n const partIndex = chunk.path[0]!;\n const updatedPart = updater(message.parts[partIndex]!);\n return {\n ...message,\n parts: [\n ...message.parts.slice(0, partIndex),\n updatedPart,\n ...message.parts.slice(partIndex + 1),\n ],\n get content() {\n return this.parts;\n },\n };\n};\n\nconst handlePartStart = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { readonly type: \"part-start\" },\n): AssistantMessage => {\n const partInit = chunk.part;\n if (partInit.type === \"text\" || partInit.type === \"reasoning\") {\n const newTextPart: TextPart | ReasoningPart = {\n type: partInit.type,\n text: \"\",\n status: { type: \"running\" },\n ...(partInit.parentId && { parentId: partInit.parentId }),\n };\n return {\n ...message,\n parts: [...message.parts, newTextPart],\n get content() {\n return this.parts;\n },\n };\n } else if (partInit.type === \"tool-call\") {\n const newToolCallPart: ToolCallPart = {\n type: \"tool-call\",\n state: \"partial-call\",\n status: { type: \"running\", isArgsComplete: false },\n toolCallId: partInit.toolCallId,\n toolName: partInit.toolName,\n argsText: \"\",\n args: {},\n timing: { startedAt: Date.now() },\n ...(partInit.parentId && { parentId: partInit.parentId }),\n };\n return {\n ...message,\n parts: [...message.parts, newToolCallPart],\n get content() {\n return this.parts;\n },\n };\n } else if (partInit.type === \"source\") {\n const newSourcePart: SourcePart = {\n type: \"source\",\n sourceType: partInit.sourceType,\n id: partInit.id,\n url: partInit.url,\n ...(partInit.title ? { title: partInit.title } : undefined),\n ...(partInit.parentId && { parentId: partInit.parentId }),\n };\n return {\n ...message,\n parts: [...message.parts, newSourcePart],\n get content() {\n return this.parts;\n },\n };\n } else if (partInit.type === \"file\") {\n const newFilePart: FilePart = {\n type: \"file\",\n mimeType: partInit.mimeType,\n data: partInit.data,\n ...(partInit.parentId && { parentId: partInit.parentId }),\n };\n return {\n ...message,\n parts: [...message.parts, newFilePart],\n get content() {\n return this.parts;\n },\n };\n } else if (partInit.type === \"data\") {\n const newDataPart: DataPart = {\n type: \"data\",\n name: partInit.name,\n data: partInit.data,\n ...(partInit.parentId && { parentId: partInit.parentId }),\n };\n return {\n ...message,\n parts: [...message.parts, newDataPart],\n get content() {\n return this.parts;\n },\n };\n } else {\n throw new Error(`Unsupported part type: ${partInit.type}`);\n }\n};\n\nconst handleToolCallArgsTextFinish = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & {\n readonly type: \"tool-call-args-text-finish\";\n },\n): AssistantMessage => {\n return updatePartForPath(message, chunk, (part) => {\n if (part.type !== \"tool-call\") {\n throw new Error(\"Last is not a tool call\");\n }\n\n // TODO this should never be hit; this happens if args-text-finish is emitted after result\n if (part.state !== \"partial-call\") return part;\n // throw new Error(\"Last is not a partial call\");\n\n return {\n ...part,\n state: \"call\",\n };\n });\n};\n\nconst handlePartFinish = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { readonly type: \"part-finish\" },\n): AssistantMessage => {\n return updatePartForPath(message, chunk, (part) => ({\n ...part,\n status: { type: \"complete\", reason: \"unknown\" },\n }));\n};\n\nconst handleTextDelta = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"text-delta\" },\n): AssistantMessage => {\n return updatePartForPath(message, chunk, (part) => {\n if (part.type === \"text\" || part.type === \"reasoning\") {\n return { ...part, text: part.text + chunk.textDelta };\n } else if (part.type === \"tool-call\") {\n const newArgsText = part.argsText + chunk.textDelta;\n\n // Fall back to existing args if parsing fails\n const newArgs = parsePartialJsonObject(newArgsText) ?? part.args;\n\n return { ...part, argsText: newArgsText, args: newArgs };\n } else {\n throw new Error(\n \"text-delta received but part is neither text nor tool-call\",\n );\n }\n });\n};\n\nconst handleResult = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"result\" },\n): AssistantMessage => {\n return updatePartForPath(message, chunk, (part) => {\n if (part.type === \"tool-call\") {\n return {\n ...part,\n state: \"result\",\n ...(part.timing !== undefined\n ? {\n timing: {\n ...part.timing,\n completedAt: part.timing.completedAt ?? Date.now(),\n },\n }\n : {}),\n ...(chunk.artifact !== undefined ? { artifact: chunk.artifact } : {}),\n result: chunk.result,\n isError: chunk.isError ?? false,\n ...(chunk.modelContent !== undefined\n ? { modelContent: chunk.modelContent }\n : {}),\n ...(chunk.messages !== undefined ? { messages: chunk.messages } : {}),\n status: { type: \"complete\", reason: \"stop\" },\n };\n } else {\n throw new Error(\"Result chunk received but part is not a tool-call\");\n }\n });\n};\n\nconst handleMessageFinish = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"message-finish\" },\n): AssistantMessage => {\n // avoid edge case where providers send finish chunks that overwrite message error status (issue #2181)\n if (\n message.status?.type === \"incomplete\" &&\n message.status?.reason === \"error\"\n ) {\n return message;\n }\n\n const newStatus = getStatus(chunk);\n return { ...message, status: newStatus };\n};\n\nconst getStatus = (\n chunk:\n | (AssistantStreamChunk & { type: \"message-finish\" })\n | (AssistantStreamChunk & { type: \"step-finish\" }),\n): AssistantMessageStatus => {\n if (chunk.finishReason === \"tool-calls\") {\n return {\n type: \"requires-action\",\n reason: \"tool-calls\",\n };\n } else if (\n chunk.finishReason === \"stop\" ||\n chunk.finishReason === \"unknown\"\n ) {\n return {\n type: \"complete\",\n reason: chunk.finishReason,\n };\n } else {\n return {\n type: \"incomplete\",\n reason: chunk.finishReason,\n };\n }\n};\n\nconst handleAnnotations = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"annotations\" },\n): AssistantMessage => {\n return {\n ...message,\n metadata: {\n ...message.metadata,\n unstable_annotations: [\n ...message.metadata.unstable_annotations,\n ...chunk.annotations,\n ],\n },\n };\n};\n\nconst handleData = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"data\" },\n): AssistantMessage => {\n return {\n ...message,\n metadata: {\n ...message.metadata,\n unstable_data: [...message.metadata.unstable_data, ...chunk.data],\n },\n };\n};\n\nconst handleStepStart = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"step-start\" },\n): AssistantMessage => {\n return {\n ...message,\n metadata: {\n ...message.metadata,\n steps: [\n ...message.metadata.steps,\n { state: \"started\", messageId: chunk.messageId },\n ],\n },\n };\n};\n\nconst handleStepFinish = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"step-finish\" },\n): AssistantMessage => {\n const steps = message.metadata.steps.slice();\n const lastIndex = steps.length - 1;\n\n // Check if the previous step is a step-start (has state \"started\")\n if (steps.length > 0 && steps[lastIndex]?.state === \"started\") {\n steps[lastIndex] = {\n ...steps[lastIndex],\n state: \"finished\",\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n isContinued: chunk.isContinued,\n };\n } else {\n // If no previous step-start exists, append a finished step\n steps.push({\n state: \"finished\",\n messageId: generateId(),\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n isContinued: chunk.isContinued,\n });\n }\n\n return {\n ...message,\n metadata: {\n ...message.metadata,\n steps,\n },\n };\n};\n\nconst handleErrorChunk = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"error\" },\n): AssistantMessage => {\n const severity =\n chunk.severity === \"critical\" ||\n chunk.severity === \"warning\" ||\n chunk.severity === \"info\"\n ? chunk.severity\n : undefined;\n return {\n ...message,\n status: {\n type: \"incomplete\",\n reason: \"error\",\n error: {\n code: chunk.code ?? \"unknown\",\n message: chunk.error,\n ...(severity !== undefined && { severity }),\n },\n },\n };\n};\n\nconst handleUpdateState = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"update-state\" },\n): AssistantMessage => {\n const acc = new ObjectStreamAccumulator(message.metadata.unstable_state);\n acc.append(chunk.operations);\n\n return {\n ...message,\n metadata: {\n ...message.metadata,\n unstable_state: acc.state,\n },\n };\n};\n\nconst computeTiming = (\n tracker: TimingTracker,\n message: AssistantMessage,\n): AssistantMessageTiming => {\n let outputTokens = 0;\n for (const step of message.metadata.steps) {\n if (step.state === \"finished\" && step.usage) {\n outputTokens += step.usage.outputTokens;\n }\n }\n\n let totalText = \"\";\n for (const part of message.parts) {\n if (part.type === \"text\" || part.type === \"reasoning\") {\n totalText += part.text;\n }\n }\n\n return tracker.getTiming(\n outputTokens > 0 ? outputTokens : undefined,\n totalText || undefined,\n );\n};\n\nconst throttleCallback = (callback: () => void) => {\n let hasScheduled = false;\n return () => {\n if (hasScheduled) return;\n hasScheduled = true;\n queueMicrotask(() => {\n hasScheduled = false;\n callback();\n });\n };\n};\n\nexport class AssistantMessageAccumulator extends TransformStream<\n AssistantStreamChunk,\n AssistantMessage\n> {\n constructor({\n initialMessage,\n throttle,\n onError,\n }: {\n initialMessage?: AssistantMessage;\n throttle?: boolean;\n onError?: (error: string) => void;\n } = {}) {\n let message = initialMessage ?? createInitialMessage();\n const tracker = new TimingTracker();\n let controller:\n | TransformStreamDefaultController<AssistantMessage>\n | undefined;\n const emitChunk = throttle\n ? throttleCallback(() => {\n controller?.enqueue(message);\n })\n : () => {\n controller?.enqueue(message);\n };\n super({\n start(c) {\n controller = c;\n },\n transform(chunk) {\n tracker.recordChunk();\n const type = chunk.type;\n switch (type) {\n case \"part-start\":\n message = handlePartStart(message, chunk);\n if (chunk.part.type === \"tool-call\") {\n tracker.recordToolCallStart(chunk.part.toolCallId);\n }\n break;\n\n case \"tool-call-args-text-finish\":\n message = handleToolCallArgsTextFinish(message, chunk);\n break;\n\n case \"part-finish\":\n message = handlePartFinish(message, chunk);\n break;\n\n case \"text-delta\":\n message = handleTextDelta(message, chunk);\n tracker.recordFirstToken();\n break;\n case \"result\":\n message = handleResult(message, chunk);\n break;\n case \"message-finish\":\n message = handleMessageFinish(message, chunk);\n break;\n case \"annotations\":\n message = handleAnnotations(message, chunk);\n break;\n case \"data\":\n message = handleData(message, chunk);\n break;\n case \"step-start\":\n message = handleStepStart(message, chunk);\n break;\n case \"step-finish\":\n message = handleStepFinish(message, chunk);\n break;\n case \"error\":\n message = handleErrorChunk(message, chunk);\n onError?.(chunk.error);\n break;\n case \"update-state\":\n message = handleUpdateState(message, chunk);\n break;\n default: {\n const unhandledType: never = type;\n throw new Error(`Unsupported chunk type: ${unhandledType}`);\n }\n }\n\n if (message.status.type !== \"running\") {\n message = {\n ...message,\n metadata: {\n ...message.metadata,\n timing: computeTiming(tracker, message),\n },\n };\n }\n\n emitChunk();\n },\n flush(controller) {\n if (message.status?.type === \"running\") {\n // Check if there are any tool calls that require action\n const requiresAction =\n message.parts?.some(\n (part) =>\n part.type === \"tool-call\" &&\n (part.state === \"call\" || part.state === \"partial-call\") &&\n part.result === undefined,\n ) ?? false;\n message = handleMessageFinish(message, {\n type: \"message-finish\",\n path: [],\n finishReason: requiresAction ? \"tool-calls\" : \"unknown\",\n usage: {\n inputTokens: 0,\n outputTokens: 0,\n },\n });\n\n message = {\n ...message,\n metadata: {\n ...message.metadata,\n timing: computeTiming(tracker, message),\n },\n };\n\n controller.enqueue(message);\n }\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"assistant-message-accumulator.js","names":["unhandledType"],"sources":["../../../src/core/accumulators/assistant-message-accumulator.ts"],"sourcesContent":["import type { AssistantStreamChunk } from \"../AssistantStreamChunk\";\nimport { generateId } from \"../utils/generateId\";\nimport { parsePartialJsonObject } from \"../../utils/json/parse-partial-json-object\";\nimport type {\n AssistantMessage,\n AssistantMessageStatus,\n AssistantMessageTiming,\n TextPart,\n ToolCallPart,\n SourcePart,\n AssistantMessagePart,\n ReasoningPart,\n FilePart,\n DataPart,\n} from \"../utils/types\";\nimport { GorpStreamAccumulator } from \"../gorp/GorpStreamAccumulator\";\nimport type { ReadonlyJSONValue } from \"../../utils\";\nimport { TimingTracker } from \"./TimingTracker\";\n\nexport const createInitialMessage = ({\n unstable_state = null,\n}: {\n unstable_state?: ReadonlyJSONValue;\n} = {}): AssistantMessage => ({\n role: \"assistant\",\n status: { type: \"running\" },\n parts: [],\n get content() {\n return this.parts;\n },\n metadata: {\n unstable_state,\n unstable_data: [],\n unstable_annotations: [],\n steps: [],\n custom: {},\n },\n});\n\ntype WarnOnce = (key: string, message: string) => void;\n\nconst MAX_WARNED_KEYS = 16;\n\nconst updatePartForPath = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk,\n warnOnce: WarnOnce,\n updater: (part: AssistantMessagePart) => AssistantMessagePart,\n): AssistantMessage => {\n const part =\n chunk.path.length === 1 ? message.parts[chunk.path[0]!] : undefined;\n if (part === undefined) {\n warnOnce(\n `no-part:${chunk.type}`,\n `Dropped ${chunk.type} chunk: no part at path [${chunk.path.join(\", \")}]`,\n );\n return message;\n }\n\n const partIndex = chunk.path[0]!;\n const updatedPart = updater(part);\n if (updatedPart === part) return message;\n return {\n ...message,\n parts: [\n ...message.parts.slice(0, partIndex),\n updatedPart,\n ...message.parts.slice(partIndex + 1),\n ],\n get content() {\n return this.parts;\n },\n };\n};\n\nconst handlePartStart = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { readonly type: \"part-start\" },\n warnOnce: WarnOnce,\n): AssistantMessage => {\n const partInit = chunk.part;\n if (partInit.type === \"text\" || partInit.type === \"reasoning\") {\n const newTextPart: TextPart | ReasoningPart = {\n type: partInit.type,\n text: \"\",\n status: { type: \"running\" },\n ...(partInit.parentId && { parentId: partInit.parentId }),\n };\n return {\n ...message,\n parts: [...message.parts, newTextPart],\n get content() {\n return this.parts;\n },\n };\n } else if (partInit.type === \"tool-call\") {\n const newToolCallPart: ToolCallPart = {\n type: \"tool-call\",\n state: \"partial-call\",\n status: { type: \"running\", isArgsComplete: false },\n toolCallId: partInit.toolCallId,\n toolName: partInit.toolName,\n argsText: \"\",\n args: {},\n timing: { startedAt: Date.now() },\n ...(partInit.parentId && { parentId: partInit.parentId }),\n };\n return {\n ...message,\n parts: [...message.parts, newToolCallPart],\n get content() {\n return this.parts;\n },\n };\n } else if (partInit.type === \"source\") {\n const newSourcePart: SourcePart = {\n type: \"source\",\n sourceType: partInit.sourceType,\n id: partInit.id,\n url: partInit.url,\n ...(partInit.title ? { title: partInit.title } : undefined),\n ...(partInit.parentId && { parentId: partInit.parentId }),\n };\n return {\n ...message,\n parts: [...message.parts, newSourcePart],\n get content() {\n return this.parts;\n },\n };\n } else if (partInit.type === \"file\") {\n const newFilePart: FilePart = {\n type: \"file\",\n mimeType: partInit.mimeType,\n data: partInit.data,\n ...(partInit.parentId && { parentId: partInit.parentId }),\n };\n return {\n ...message,\n parts: [...message.parts, newFilePart],\n get content() {\n return this.parts;\n },\n };\n } else if (partInit.type === \"data\") {\n const newDataPart: DataPart = {\n type: \"data\",\n name: partInit.name,\n data: partInit.data,\n ...(partInit.parentId && { parentId: partInit.parentId }),\n };\n return {\n ...message,\n parts: [...message.parts, newDataPart],\n get content() {\n return this.parts;\n },\n };\n } else {\n const unsupportedType = String((partInit as { type?: unknown }).type);\n warnOnce(\n `unsupported-part-start:${unsupportedType}`,\n `Unsupported part-start type ${unsupportedType}: inserting an empty reasoning part to preserve part indices`,\n );\n // reasoning rather than a data sentinel: auiV0Encode rejects data parts, so a data placeholder would fail cloud persistence\n const placeholderPart: ReasoningPart = {\n type: \"reasoning\",\n text: \"\",\n status: { type: \"running\" },\n };\n return {\n ...message,\n parts: [...message.parts, placeholderPart],\n get content() {\n return this.parts;\n },\n };\n }\n};\n\nconst handleToolCallArgsTextFinish = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & {\n readonly type: \"tool-call-args-text-finish\";\n },\n warnOnce: WarnOnce,\n): AssistantMessage => {\n return updatePartForPath(message, chunk, warnOnce, (part) => {\n if (part.type !== \"tool-call\") {\n warnOnce(\n \"wrong-part:tool-call-args-text-finish\",\n \"Dropped tool-call-args-text-finish chunk: part is not a tool-call\",\n );\n return part;\n }\n\n // TODO this should never be hit; this happens if args-text-finish is emitted after result\n if (part.state !== \"partial-call\") return { ...part };\n // throw new Error(\"Last is not a partial call\");\n\n return {\n ...part,\n state: \"call\",\n };\n });\n};\n\nconst handlePartFinish = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { readonly type: \"part-finish\" },\n warnOnce: WarnOnce,\n): AssistantMessage => {\n return updatePartForPath(message, chunk, warnOnce, (part) => ({\n ...part,\n status: { type: \"complete\", reason: \"unknown\" },\n }));\n};\n\nconst handleTextDelta = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"text-delta\" },\n warnOnce: WarnOnce,\n): AssistantMessage => {\n return updatePartForPath(message, chunk, warnOnce, (part) => {\n if (part.type === \"text\" || part.type === \"reasoning\") {\n return { ...part, text: part.text + chunk.textDelta };\n } else if (part.type === \"tool-call\") {\n const newArgsText = part.argsText + chunk.textDelta;\n\n // Fall back to existing args if parsing fails\n const newArgs = parsePartialJsonObject(newArgsText) ?? part.args;\n\n return { ...part, argsText: newArgsText, args: newArgs };\n } else {\n warnOnce(\n \"wrong-part:text-delta\",\n \"Dropped text-delta chunk: part is neither text nor tool-call\",\n );\n return part;\n }\n });\n};\n\nconst handleResult = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"result\" },\n warnOnce: WarnOnce,\n): AssistantMessage => {\n return updatePartForPath(message, chunk, warnOnce, (part) => {\n if (part.type === \"tool-call\") {\n return {\n ...part,\n state: \"result\",\n ...(part.timing !== undefined\n ? {\n timing: {\n ...part.timing,\n completedAt: part.timing.completedAt ?? Date.now(),\n },\n }\n : {}),\n ...(chunk.artifact !== undefined ? { artifact: chunk.artifact } : {}),\n result: chunk.result,\n isError: chunk.isError ?? false,\n ...(chunk.modelContent !== undefined\n ? { modelContent: chunk.modelContent }\n : {}),\n ...(chunk.messages !== undefined ? { messages: chunk.messages } : {}),\n status: { type: \"complete\", reason: \"stop\" },\n };\n } else {\n warnOnce(\n \"wrong-part:result\",\n \"Dropped result chunk: part is not a tool-call\",\n );\n return part;\n }\n });\n};\n\nconst handleMessageFinish = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"message-finish\" },\n): AssistantMessage => {\n // avoid edge case where providers send finish chunks that overwrite message error status (issue #2181)\n if (\n message.status?.type === \"incomplete\" &&\n message.status?.reason === \"error\"\n ) {\n return message;\n }\n\n const newStatus = getStatus(chunk);\n return { ...message, status: newStatus };\n};\n\nconst getStatus = (\n chunk:\n | (AssistantStreamChunk & { type: \"message-finish\" })\n | (AssistantStreamChunk & { type: \"step-finish\" }),\n): AssistantMessageStatus => {\n if (chunk.finishReason === \"tool-calls\") {\n return {\n type: \"requires-action\",\n reason: \"tool-calls\",\n };\n } else if (\n chunk.finishReason === \"stop\" ||\n chunk.finishReason === \"unknown\"\n ) {\n return {\n type: \"complete\",\n reason: chunk.finishReason,\n };\n } else {\n return {\n type: \"incomplete\",\n reason: chunk.finishReason,\n };\n }\n};\n\nconst handleAnnotations = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"annotations\" },\n): AssistantMessage => {\n return {\n ...message,\n metadata: {\n ...message.metadata,\n unstable_annotations: [\n ...message.metadata.unstable_annotations,\n ...chunk.annotations,\n ],\n },\n };\n};\n\nconst handleData = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"data\" },\n): AssistantMessage => {\n return {\n ...message,\n metadata: {\n ...message.metadata,\n unstable_data: [...message.metadata.unstable_data, ...chunk.data],\n },\n };\n};\n\nconst handleStepStart = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"step-start\" },\n): AssistantMessage => {\n return {\n ...message,\n metadata: {\n ...message.metadata,\n steps: [\n ...message.metadata.steps,\n { state: \"started\", messageId: chunk.messageId },\n ],\n },\n };\n};\n\nconst handleStepFinish = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"step-finish\" },\n): AssistantMessage => {\n const steps = message.metadata.steps.slice();\n const lastIndex = steps.length - 1;\n\n // Check if the previous step is a step-start (has state \"started\")\n if (steps.length > 0 && steps[lastIndex]?.state === \"started\") {\n steps[lastIndex] = {\n ...steps[lastIndex],\n state: \"finished\",\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n isContinued: chunk.isContinued,\n };\n } else {\n // If no previous step-start exists, append a finished step\n steps.push({\n state: \"finished\",\n messageId: generateId(),\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n isContinued: chunk.isContinued,\n });\n }\n\n return {\n ...message,\n metadata: {\n ...message.metadata,\n steps,\n },\n };\n};\n\nconst handleErrorChunk = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"error\" },\n): AssistantMessage => {\n const severity =\n chunk.severity === \"critical\" ||\n chunk.severity === \"warning\" ||\n chunk.severity === \"info\"\n ? chunk.severity\n : undefined;\n return {\n ...message,\n status: {\n type: \"incomplete\",\n reason: \"error\",\n error: {\n code: chunk.code ?? \"unknown\",\n message: chunk.error ?? \"unknown error\",\n ...(severity !== undefined && { severity }),\n },\n },\n };\n};\n\nconst handleUpdateState = (\n message: AssistantMessage,\n chunk: AssistantStreamChunk & { type: \"update-state\" },\n): AssistantMessage => {\n const acc = new GorpStreamAccumulator(message.metadata.unstable_state);\n acc.append(chunk.operations);\n\n return {\n ...message,\n metadata: {\n ...message.metadata,\n unstable_state: acc.state,\n },\n };\n};\n\nconst computeTiming = (\n tracker: TimingTracker,\n message: AssistantMessage,\n): AssistantMessageTiming => {\n let outputTokens = 0;\n for (const step of message.metadata.steps) {\n if (step.state === \"finished\" && step.usage) {\n outputTokens += step.usage.outputTokens;\n }\n }\n\n let totalText = \"\";\n for (const part of message.parts) {\n if (part.type === \"text\" || part.type === \"reasoning\") {\n totalText += part.text;\n }\n }\n\n return tracker.getTiming(\n outputTokens > 0 ? outputTokens : undefined,\n totalText || undefined,\n );\n};\n\nconst throttleCallback = (callback: () => void) => {\n let hasScheduled = false;\n return () => {\n if (hasScheduled) return;\n hasScheduled = true;\n queueMicrotask(() => {\n hasScheduled = false;\n callback();\n });\n };\n};\n\nexport class AssistantMessageAccumulator extends TransformStream<\n AssistantStreamChunk,\n AssistantMessage\n> {\n constructor({\n initialMessage,\n throttle,\n onError,\n }: {\n initialMessage?: AssistantMessage;\n throttle?: boolean;\n onError?: (error: string) => void;\n } = {}) {\n let message = initialMessage ?? createInitialMessage();\n const tracker = new TimingTracker();\n const warnedKeys = new Set<string>();\n const warnOnce: WarnOnce = (key, warning) => {\n if (warnedKeys.has(key) || warnedKeys.size >= MAX_WARNED_KEYS) return;\n warnedKeys.add(key);\n console.warn(warning);\n };\n let controller:\n | TransformStreamDefaultController<AssistantMessage>\n | undefined;\n const emitChunk = throttle\n ? throttleCallback(() => {\n controller?.enqueue(message);\n })\n : () => {\n controller?.enqueue(message);\n };\n super({\n start(c) {\n controller = c;\n },\n transform(chunk) {\n tracker.recordChunk();\n const type = chunk.type;\n switch (type) {\n case \"part-start\":\n message = handlePartStart(message, chunk, warnOnce);\n if (chunk.part.type === \"tool-call\") {\n tracker.recordToolCallStart(chunk.part.toolCallId);\n }\n break;\n\n case \"tool-call-args-text-finish\":\n message = handleToolCallArgsTextFinish(message, chunk, warnOnce);\n break;\n\n case \"part-finish\":\n message = handlePartFinish(message, chunk, warnOnce);\n break;\n\n case \"text-delta\": {\n const next = handleTextDelta(message, chunk, warnOnce);\n if (next !== message) tracker.recordFirstToken();\n message = next;\n break;\n }\n case \"result\":\n message = handleResult(message, chunk, warnOnce);\n break;\n case \"message-finish\":\n message = handleMessageFinish(message, chunk);\n break;\n case \"annotations\":\n message = handleAnnotations(message, chunk);\n break;\n case \"data\":\n message = handleData(message, chunk);\n break;\n case \"step-start\":\n message = handleStepStart(message, chunk);\n break;\n case \"step-finish\":\n message = handleStepFinish(message, chunk);\n break;\n case \"error\":\n message = handleErrorChunk(message, chunk);\n onError?.(chunk.error);\n break;\n case \"update-state\":\n message = handleUpdateState(message, chunk);\n break;\n default: {\n const unhandledType: never = type;\n throw new Error(`Unsupported chunk type: ${unhandledType}`);\n }\n }\n\n if (message.status.type !== \"running\") {\n message = {\n ...message,\n metadata: {\n ...message.metadata,\n timing: computeTiming(tracker, message),\n },\n };\n }\n\n emitChunk();\n },\n flush(controller) {\n if (message.status?.type === \"running\") {\n // Check if there are any tool calls that require action\n const requiresAction =\n message.parts?.some(\n (part) =>\n part.type === \"tool-call\" &&\n (part.state === \"call\" || part.state === \"partial-call\") &&\n part.result === undefined,\n ) ?? false;\n message = handleMessageFinish(message, {\n type: \"message-finish\",\n path: [],\n finishReason: requiresAction ? \"tool-calls\" : \"unknown\",\n usage: {\n inputTokens: 0,\n outputTokens: 0,\n },\n });\n\n message = {\n ...message,\n metadata: {\n ...message.metadata,\n timing: computeTiming(tracker, message),\n },\n };\n\n controller.enqueue(message);\n }\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toGenericMessages.js","names":[],"sources":["../../../src/core/converters/toGenericMessages.ts"],"sourcesContent":["/**\n * Generic message types for framework-agnostic LLM message interchange.\n * These types represent a common format that can be converted to/from\n * various LLM provider formats (AI SDK, LangChain, etc.).\n */\n\nexport type GenericTextPart = {\n type: \"text\";\n text: string;\n};\n\nexport type GenericFilePart = {\n type: \"file\";\n data: string | URL;\n mediaType: string;\n};\n\nexport type GenericToolCallPart = {\n type: \"tool-call\";\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n};\n\nexport type GenericToolResultPart = {\n type: \"tool-result\";\n toolCallId: string;\n toolName: string;\n result: unknown;\n isError?: boolean;\n};\n\nexport type GenericSystemMessage = {\n role: \"system\";\n content: string;\n};\n\nexport type GenericUserMessage = {\n role: \"user\";\n content: (GenericTextPart | GenericFilePart)[];\n};\n\nexport type GenericAssistantMessage = {\n role: \"assistant\";\n content: (GenericTextPart | GenericToolCallPart)[];\n};\n\nexport type GenericToolMessage = {\n role: \"tool\";\n content: GenericToolResultPart[];\n};\n\nexport type GenericMessage =\n | GenericSystemMessage\n | GenericUserMessage\n | GenericAssistantMessage\n | GenericToolMessage;\n\ntype MessagePartLike = {\n type: string;\n text?: string;\n image?: string;\n data?: string;\n mimeType?: string;\n toolCallId?: string;\n toolName?: string;\n args?: Record<string, unknown>;\n result?: unknown;\n isError?: boolean;\n};\n\ntype AttachmentLike = {\n content: readonly MessagePartLike[];\n};\n\ntype ThreadMessageLike = {\n role: \"system\" | \"user\" | \"assistant\";\n content: readonly MessagePartLike[];\n attachments?: readonly AttachmentLike[];\n};\n\nconst IMAGE_MEDIA_TYPES: Record<string, string> = {\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n png: \"image/png\",\n gif: \"image/gif\",\n webp: \"image/webp\",\n svg: \"image/svg+xml\",\n avif: \"image/avif\",\n bmp: \"image/bmp\",\n ico: \"image/x-icon\",\n tiff: \"image/tiff\",\n tif: \"image/tiff\",\n heic: \"image/heic\",\n heif: \"image/heif\",\n};\n\nfunction inferImageMediaType(url: string): string {\n // Handle data URLs: data:[<mediatype>][;base64],<data>\n if (url.startsWith(\"data:\")) {\n const match = url.match(/^data:([^;,]+)/);\n if (match?.[1]) return match[1];\n }\n\n // Extract extension from URL path, ignoring query string and hash\n const [pathWithoutParams = \"\"] = url.split(/[?#]/);\n const ext = pathWithoutParams.split(\".\").pop()?.toLowerCase() ?? \"\";\n return IMAGE_MEDIA_TYPES[ext] ?? \"image/png\";\n}\n\nfunction toUrlOrString(value: string): string | URL {\n try {\n return new URL(value);\n } catch {\n return value;\n }\n}\n\ntype ToolCallAccumulator = {\n textParts: (GenericTextPart | GenericToolCallPart)[];\n toolResults: GenericToolResultPart[];\n};\n\nfunction processToolCall(\n part: MessagePartLike,\n accumulator: ToolCallAccumulator,\n): boolean {\n if (!part.toolCallId || !part.toolName) return false;\n\n accumulator.textParts.push({\n type: \"tool-call\",\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n args: part.args ?? {},\n });\n\n if (part.result !== undefined) {\n const toolResult: GenericToolResultPart = {\n type: \"tool-result\",\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n result: part.result,\n };\n if (part.isError) {\n toolResult.isError = true;\n }\n accumulator.toolResults.push(toolResult);\n return true;\n }\n return false;\n}\n\nfunction flushAccumulator(\n accumulator: ToolCallAccumulator,\n result: GenericMessage[],\n): void {\n if (accumulator.textParts.length > 0) {\n result.push({ role: \"assistant\", content: accumulator.textParts });\n accumulator.textParts = [];\n }\n if (accumulator.toolResults.length > 0) {\n result.push({ role: \"tool\", content: accumulator.toolResults });\n accumulator.toolResults = [];\n }\n}\n\nfunction convertSystemMessage(\n message: ThreadMessageLike,\n result: GenericMessage[],\n): void {\n const textPart = message.content.find((p) => p.type === \"text\");\n if (textPart?.text) {\n result.push({ role: \"system\", content: textPart.text });\n }\n}\n\nfunction convertUserMessage(\n message: ThreadMessageLike,\n result: GenericMessage[],\n): void {\n const attachments = message.attachments ?? [];\n const allContent = [\n ...message.content,\n ...attachments.flatMap((a) => a.content),\n ];\n\n const content: (GenericTextPart | GenericFilePart)[] = [];\n\n for (const part of allContent) {\n if (part.type === \"text\" && part.text) {\n content.push({ type: \"text\", text: part.text });\n } else if (part.type === \"image\" && part.image) {\n content.push({\n type: \"file\",\n data: toUrlOrString(part.image),\n mediaType: inferImageMediaType(part.image),\n });\n } else if (part.type === \"file\" && part.data && part.mimeType) {\n content.push({\n type: \"file\",\n data: toUrlOrString(part.data),\n mediaType: part.mimeType,\n });\n }\n }\n\n if (content.length > 0) {\n result.push({ role: \"user\", content });\n }\n}\n\nfunction convertAssistantMessage(\n message: ThreadMessageLike,\n result: GenericMessage[],\n): void {\n const accumulator: ToolCallAccumulator = {\n textParts: [],\n toolResults: [],\n };\n let hasPendingToolResults = false;\n\n for (const part of message.content) {\n if (part.type === \"text\" && part.text) {\n // Flush pending tool results before adding more text\n if (hasPendingToolResults) {\n flushAccumulator(accumulator, result);\n hasPendingToolResults = false;\n }\n accumulator.textParts.push({ type: \"text\", text: part.text });\n } else if (part.type === \"tool-call\") {\n if (processToolCall(part, accumulator)) {\n hasPendingToolResults = true;\n }\n }\n }\n\n flushAccumulator(accumulator, result);\n}\n\n/**\n * Converts thread messages to generic LLM messages.\n * This format can then be easily converted to provider-specific formats.\n */\nexport function toGenericMessages(\n messages: readonly ThreadMessageLike[],\n): GenericMessage[] {\n const result: GenericMessage[] = [];\n\n for (const message of messages) {\n switch (message.role) {\n case \"system\":\n convertSystemMessage(message, result);\n break;\n case \"user\":\n convertUserMessage(message, result);\n break;\n case \"assistant\":\n convertAssistantMessage(message, result);\n break;\n }\n }\n\n return result;\n}\n"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"toGenericMessages.js","names":[],"sources":["../../../src/core/converters/toGenericMessages.ts"],"sourcesContent":["/**\n * Generic message types for framework-agnostic LLM message interchange.\n * These types represent a common format that can be converted to/from\n * various LLM provider formats (AI SDK, LangChain, etc.).\n */\n\nexport type GenericTextPart = {\n type: \"text\";\n text: string;\n};\n\nexport type GenericFilePart = {\n type: \"file\";\n data: string | URL;\n mediaType: string;\n};\n\nexport type GenericToolCallPart = {\n type: \"tool-call\";\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n};\n\nexport type GenericToolResultPart = {\n type: \"tool-result\";\n toolCallId: string;\n toolName: string;\n result: unknown;\n isError?: boolean;\n};\n\nexport type GenericSystemMessage = {\n role: \"system\";\n content: string;\n};\n\nexport type GenericUserMessage = {\n role: \"user\";\n content: (GenericTextPart | GenericFilePart)[];\n};\n\nexport type GenericAssistantMessage = {\n role: \"assistant\";\n content: (GenericTextPart | GenericToolCallPart)[];\n};\n\nexport type GenericToolMessage = {\n role: \"tool\";\n content: GenericToolResultPart[];\n};\n\nexport type GenericMessage =\n | GenericSystemMessage\n | GenericUserMessage\n | GenericAssistantMessage\n | GenericToolMessage;\n\ntype MessagePartLike = {\n type: string;\n text?: string;\n image?: string;\n data?: string;\n mimeType?: string;\n toolCallId?: string;\n toolName?: string;\n args?: Record<string, unknown>;\n result?: unknown;\n isError?: boolean;\n};\n\ntype AttachmentLike = {\n content: readonly MessagePartLike[];\n};\n\ntype ThreadMessageLike = {\n role: \"system\" | \"user\" | \"assistant\";\n content: readonly MessagePartLike[];\n attachments?: readonly AttachmentLike[];\n};\n\nconst IMAGE_MEDIA_TYPES: Record<string, string> = {\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n png: \"image/png\",\n gif: \"image/gif\",\n webp: \"image/webp\",\n svg: \"image/svg+xml\",\n avif: \"image/avif\",\n bmp: \"image/bmp\",\n ico: \"image/x-icon\",\n tiff: \"image/tiff\",\n tif: \"image/tiff\",\n heic: \"image/heic\",\n heif: \"image/heif\",\n};\n\nfunction inferImageMediaType(url: string): string {\n // Handle data URLs: data:[<mediatype>][;base64],<data>\n if (url.startsWith(\"data:\")) {\n const match = url.match(/^data:([^;,]+)/);\n if (match?.[1]) return match[1];\n }\n\n // Extract extension from URL path, ignoring query string and hash\n const [pathWithoutParams = \"\"] = url.split(/[?#]/);\n const ext = pathWithoutParams.split(\".\").pop()?.toLowerCase() ?? \"\";\n return IMAGE_MEDIA_TYPES[ext] ?? \"image/png\";\n}\n\nfunction toUrlOrString(value: string): string | URL {\n try {\n return new URL(value);\n } catch {\n return value;\n }\n}\n\ntype ToolCallAccumulator = {\n textParts: (GenericTextPart | GenericToolCallPart)[];\n toolResults: GenericToolResultPart[];\n};\n\nfunction processToolCall(\n part: MessagePartLike,\n accumulator: ToolCallAccumulator,\n): boolean {\n if (!part.toolCallId || !part.toolName) return false;\n\n accumulator.textParts.push({\n type: \"tool-call\",\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n args: part.args ?? {},\n });\n\n if (part.result !== undefined) {\n const toolResult: GenericToolResultPart = {\n type: \"tool-result\",\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n result: part.result,\n };\n if (part.isError) {\n toolResult.isError = true;\n }\n accumulator.toolResults.push(toolResult);\n return true;\n }\n return false;\n}\n\nfunction flushAccumulator(\n accumulator: ToolCallAccumulator,\n result: GenericMessage[],\n): void {\n if (accumulator.textParts.length > 0) {\n result.push({ role: \"assistant\", content: accumulator.textParts });\n accumulator.textParts = [];\n }\n if (accumulator.toolResults.length > 0) {\n result.push({ role: \"tool\", content: accumulator.toolResults });\n accumulator.toolResults = [];\n }\n}\n\nfunction convertSystemMessage(\n message: ThreadMessageLike,\n result: GenericMessage[],\n): void {\n const textPart = message.content.find((p) => p.type === \"text\");\n if (textPart?.text) {\n result.push({ role: \"system\", content: textPart.text });\n }\n}\n\nfunction convertUserMessage(\n message: ThreadMessageLike,\n result: GenericMessage[],\n): void {\n const attachments = message.attachments ?? [];\n const allContent = [\n ...message.content,\n ...attachments.flatMap((a) => a.content),\n ];\n\n const content: (GenericTextPart | GenericFilePart)[] = [];\n\n for (const part of allContent) {\n if (part.type === \"text\" && part.text) {\n content.push({ type: \"text\", text: part.text });\n } else if (part.type === \"image\" && part.image) {\n content.push({\n type: \"file\",\n data: toUrlOrString(part.image),\n mediaType: inferImageMediaType(part.image),\n });\n } else if (part.type === \"file\" && part.data && part.mimeType) {\n content.push({\n type: \"file\",\n data: toUrlOrString(part.data),\n mediaType: part.mimeType,\n });\n }\n }\n\n if (content.length > 0) {\n result.push({ role: \"user\", content });\n }\n}\n\nfunction convertAssistantMessage(\n message: ThreadMessageLike,\n result: GenericMessage[],\n): void {\n const accumulator: ToolCallAccumulator = {\n textParts: [],\n toolResults: [],\n };\n let hasPendingToolResults = false;\n\n for (const part of message.content) {\n if (part.type === \"text\" && part.text) {\n // Flush pending tool results before adding more text\n if (hasPendingToolResults) {\n flushAccumulator(accumulator, result);\n hasPendingToolResults = false;\n }\n accumulator.textParts.push({ type: \"text\", text: part.text });\n } else if (part.type === \"tool-call\") {\n if (processToolCall(part, accumulator)) {\n hasPendingToolResults = true;\n }\n }\n }\n\n flushAccumulator(accumulator, result);\n}\n\n/**\n * Converts thread messages to generic LLM messages.\n * This format can then be easily converted to provider-specific formats.\n */\nexport function toGenericMessages(\n messages: readonly ThreadMessageLike[],\n): GenericMessage[] {\n const result: GenericMessage[] = [];\n\n for (const message of messages) {\n switch (message.role) {\n case \"system\":\n convertSystemMessage(message, result);\n break;\n case \"user\":\n convertUserMessage(message, result);\n break;\n case \"assistant\":\n convertAssistantMessage(message, result);\n break;\n }\n }\n\n return result;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReadonlyJSONValue } from "../../utils/json/json-value.js";
|
|
2
|
+
import "../../utils.js";
|
|
3
|
+
import { GorpStreamOperation } from "./types.js";
|
|
4
|
+
//#region src/core/gorp/GorpStreamAccumulator.d.ts
|
|
5
|
+
declare class GorpStreamAccumulator {
|
|
6
|
+
private _state;
|
|
7
|
+
constructor(initialValue?: ReadonlyJSONValue);
|
|
8
|
+
get state(): ReadonlyJSONValue;
|
|
9
|
+
append(ops: readonly GorpStreamOperation[]): void;
|
|
10
|
+
private static apply;
|
|
11
|
+
private static updatePath;
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { GorpStreamAccumulator };
|
|
15
|
+
//# sourceMappingURL=GorpStreamAccumulator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GorpStreamAccumulator.d.ts","names":[],"sources":["../../../src/core/gorp/GorpStreamAccumulator.ts"],"mappings":";;;;cAIa;UACH;EAEI,YAAA,eAAc;MAItB,SAAK;EAIT,OAAO,cAAc;iBAON;iBAmBA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { assertSafePathSegment } from "./changeTree.js";
|
|
2
|
+
//#region src/core/gorp/GorpStreamAccumulator.ts
|
|
3
|
+
var GorpStreamAccumulator = class GorpStreamAccumulator {
|
|
3
4
|
_state;
|
|
4
5
|
constructor(initialValue = null) {
|
|
5
6
|
this._state = initialValue;
|
|
@@ -8,13 +9,13 @@ var ObjectStreamAccumulator = class ObjectStreamAccumulator {
|
|
|
8
9
|
return this._state;
|
|
9
10
|
}
|
|
10
11
|
append(ops) {
|
|
11
|
-
this._state = ops.reduce((state, op) =>
|
|
12
|
+
this._state = ops.reduce((state, op) => GorpStreamAccumulator.apply(state, op), this._state);
|
|
12
13
|
}
|
|
13
14
|
static apply(state, op) {
|
|
14
15
|
const type = op.type;
|
|
15
16
|
switch (type) {
|
|
16
|
-
case "set": return
|
|
17
|
-
case "append-text": return
|
|
17
|
+
case "set": return GorpStreamAccumulator.updatePath(state, op.path, () => op.value);
|
|
18
|
+
case "append-text": return GorpStreamAccumulator.updatePath(state, op.path, (current) => {
|
|
18
19
|
if (typeof current !== "string") throw new Error(`Expected string at path [${op.path.join(", ")}]`);
|
|
19
20
|
return current + op.value;
|
|
20
21
|
});
|
|
@@ -26,20 +27,21 @@ var ObjectStreamAccumulator = class ObjectStreamAccumulator {
|
|
|
26
27
|
state ??= {};
|
|
27
28
|
if (typeof state !== "object") throw new Error(`Invalid path: [${path.join(", ")}]`);
|
|
28
29
|
const [key, ...rest] = path;
|
|
30
|
+
assertSafePathSegment(key);
|
|
29
31
|
if (Array.isArray(state)) {
|
|
30
32
|
const idx = Number(key);
|
|
31
33
|
if (Number.isNaN(idx)) throw new Error(`Expected array index at [${path.join(", ")}]`);
|
|
32
34
|
if (idx > state.length || idx < 0) throw new Error(`Insert array index out of bounds`);
|
|
33
35
|
const nextState = [...state];
|
|
34
|
-
nextState[idx] =
|
|
36
|
+
nextState[idx] = GorpStreamAccumulator.updatePath(Object.hasOwn(nextState, idx) ? nextState[idx] : void 0, rest, updater);
|
|
35
37
|
return nextState;
|
|
36
38
|
}
|
|
37
39
|
const nextState = { ...state };
|
|
38
|
-
nextState[key] =
|
|
40
|
+
nextState[key] = GorpStreamAccumulator.updatePath(Object.hasOwn(nextState, key) ? nextState[key] : void 0, rest, updater);
|
|
39
41
|
return nextState;
|
|
40
42
|
}
|
|
41
43
|
};
|
|
42
44
|
//#endregion
|
|
43
|
-
export {
|
|
45
|
+
export { GorpStreamAccumulator };
|
|
44
46
|
|
|
45
|
-
//# sourceMappingURL=
|
|
47
|
+
//# sourceMappingURL=GorpStreamAccumulator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GorpStreamAccumulator.js","names":["_exhaustiveCheck"],"sources":["../../../src/core/gorp/GorpStreamAccumulator.ts"],"sourcesContent":["import type { ReadonlyJSONValue, ReadonlyJSONObject } from \"../../utils\";\nimport { assertSafePathSegment } from \"./changeTree\";\nimport type { GorpStreamOperation } from \"./types\";\n\nexport class GorpStreamAccumulator {\n private _state: ReadonlyJSONValue;\n\n constructor(initialValue: ReadonlyJSONValue = null) {\n this._state = initialValue;\n }\n\n get state() {\n return this._state;\n }\n\n append(ops: readonly GorpStreamOperation[]) {\n this._state = ops.reduce(\n (state, op) => GorpStreamAccumulator.apply(state, op),\n this._state,\n );\n }\n\n private static apply(state: ReadonlyJSONValue, op: GorpStreamOperation) {\n const type = op.type;\n switch (type) {\n case \"set\":\n return GorpStreamAccumulator.updatePath(state, op.path, () => op.value);\n case \"append-text\":\n return GorpStreamAccumulator.updatePath(state, op.path, (current) => {\n if (typeof current !== \"string\")\n throw new Error(`Expected string at path [${op.path.join(\", \")}]`);\n return current + op.value;\n });\n\n default: {\n const _exhaustiveCheck: never = type;\n throw new Error(`Invalid operation type: ${_exhaustiveCheck}`);\n }\n }\n }\n\n private static updatePath(\n state: ReadonlyJSONValue | undefined,\n path: readonly string[],\n updater: (current: ReadonlyJSONValue | undefined) => ReadonlyJSONValue,\n ): ReadonlyJSONValue {\n if (path.length === 0) return updater(state);\n\n // Initialize state as empty object if it's null and we're trying to set a property\n state ??= {};\n\n if (typeof state !== \"object\") {\n throw new Error(`Invalid path: [${path.join(\", \")}]`);\n }\n\n const [key, ...rest] = path as [string, ...(readonly string[])];\n assertSafePathSegment(key);\n if (Array.isArray(state)) {\n const idx = Number(key);\n if (Number.isNaN(idx))\n throw new Error(`Expected array index at [${path.join(\", \")}]`);\n if (idx > state.length || idx < 0)\n throw new Error(`Insert array index out of bounds`);\n\n const nextState = [...state];\n nextState[idx] = GorpStreamAccumulator.updatePath(\n Object.hasOwn(nextState, idx) ? nextState[idx] : undefined,\n rest,\n updater,\n );\n\n return nextState;\n }\n\n const nextState = { ...(state as ReadonlyJSONObject) };\n nextState[key] = GorpStreamAccumulator.updatePath(\n Object.hasOwn(nextState, key) ? nextState[key] : undefined,\n rest,\n updater,\n );\n\n return nextState;\n }\n}\n"],"mappings":";;AAIA,IAAa,wBAAb,MAAa,sBAAsB;CACjC;CAEA,YAAY,eAAkC,MAAM;EAClD,KAAK,SAAS;CAChB;CAEA,IAAI,QAAQ;EACV,OAAO,KAAK;CACd;CAEA,OAAO,KAAqC;EAC1C,KAAK,SAAS,IAAI,QACf,OAAO,OAAO,sBAAsB,MAAM,OAAO,EAAE,GACpD,KAAK,MACP;CACF;CAEA,OAAe,MAAM,OAA0B,IAAyB;EACtE,MAAM,OAAO,GAAG;EAChB,QAAQ,MAAR;GACE,KAAK,OACH,OAAO,sBAAsB,WAAW,OAAO,GAAG,YAAY,GAAG,KAAK;GACxE,KAAK,eACH,OAAO,sBAAsB,WAAW,OAAO,GAAG,OAAO,YAAY;IACnE,IAAI,OAAO,YAAY,UACrB,MAAM,IAAI,MAAM,4BAA4B,GAAG,KAAK,KAAK,IAAI,EAAE,EAAE;IACnE,OAAO,UAAU,GAAG;GACtB,CAAC;GAEH,SAEE,MAAM,IAAI,MAAM,2BAA2BA,MAAkB;EAEjE;CACF;CAEA,OAAe,WACb,OACA,MACA,SACmB;EACnB,IAAI,KAAK,WAAW,GAAG,OAAO,QAAQ,KAAK;EAG3C,UAAU,CAAC;EAEX,IAAI,OAAO,UAAU,UACnB,MAAM,IAAI,MAAM,kBAAkB,KAAK,KAAK,IAAI,EAAE,EAAE;EAGtD,MAAM,CAAC,KAAK,GAAG,QAAQ;EACvB,sBAAsB,GAAG;EACzB,IAAI,MAAM,QAAQ,KAAK,GAAG;GACxB,MAAM,MAAM,OAAO,GAAG;GACtB,IAAI,OAAO,MAAM,GAAG,GAClB,MAAM,IAAI,MAAM,4BAA4B,KAAK,KAAK,IAAI,EAAE,EAAE;GAChE,IAAI,MAAM,MAAM,UAAU,MAAM,GAC9B,MAAM,IAAI,MAAM,kCAAkC;GAEpD,MAAM,YAAY,CAAC,GAAG,KAAK;GAC3B,UAAU,OAAO,sBAAsB,WACrC,OAAO,OAAO,WAAW,GAAG,IAAI,UAAU,OAAO,KAAA,GACjD,MACA,OACF;GAEA,OAAO;EACT;EAEA,MAAM,YAAY,EAAE,GAAI,MAA6B;EACrD,UAAU,OAAO,sBAAsB,WACrC,OAAO,OAAO,WAAW,GAAG,IAAI,UAAU,OAAO,KAAA,GACjD,MACA,OACF;EAEA,OAAO;CACT;AACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReadonlyJSONValue } from "../../utils/json/json-value.js";
|
|
2
|
+
import "../../utils.js";
|
|
3
|
+
import { GorpStreamOperation } from "./types.js";
|
|
4
|
+
//#region src/core/gorp/GorpStreamDeltaTracker.d.ts
|
|
5
|
+
declare class GorpStreamDeltaTracker {
|
|
6
|
+
private readonly accumulator;
|
|
7
|
+
private previousState;
|
|
8
|
+
private changes;
|
|
9
|
+
constructor(initialValue?: ReadonlyJSONValue);
|
|
10
|
+
get state(): ReadonlyJSONValue;
|
|
11
|
+
append(operations: readonly GorpStreamOperation[]): void;
|
|
12
|
+
isChangedAt(path: readonly string[]): boolean;
|
|
13
|
+
getChangedKeys(path: readonly string[]): string[];
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { GorpStreamDeltaTracker };
|
|
17
|
+
//# sourceMappingURL=GorpStreamDeltaTracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GorpStreamDeltaTracker.d.ts","names":[],"sources":["../../../src/core/gorp/GorpStreamDeltaTracker.ts"],"mappings":";;;;cAYa;mBACM;UACT;UACA;EAEI,YAAA,eAAc;MAKtB,SAAS;EAIb,OAAO,qBAAqB;EAW5B,YAAY;EAMZ,eAAe"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createChangeNode, diffKeys, lookupChange, lookupValue, markChanged } from "./changeTree.js";
|
|
2
|
+
import { GorpStreamAccumulator } from "./GorpStreamAccumulator.js";
|
|
3
|
+
//#region src/core/gorp/GorpStreamDeltaTracker.ts
|
|
4
|
+
var GorpStreamDeltaTracker = class {
|
|
5
|
+
accumulator;
|
|
6
|
+
previousState;
|
|
7
|
+
changes = createChangeNode();
|
|
8
|
+
constructor(initialValue = null) {
|
|
9
|
+
this.accumulator = new GorpStreamAccumulator(initialValue);
|
|
10
|
+
this.previousState = this.accumulator.state;
|
|
11
|
+
}
|
|
12
|
+
get state() {
|
|
13
|
+
return this.accumulator.state;
|
|
14
|
+
}
|
|
15
|
+
append(operations) {
|
|
16
|
+
const previousState = this.accumulator.state;
|
|
17
|
+
let changes = createChangeNode();
|
|
18
|
+
for (const op of operations) changes = markChanged(changes, op.path);
|
|
19
|
+
this.accumulator.append(operations);
|
|
20
|
+
this.previousState = previousState;
|
|
21
|
+
this.changes = changes;
|
|
22
|
+
}
|
|
23
|
+
isChangedAt(path) {
|
|
24
|
+
const node = lookupChange(this.changes, path);
|
|
25
|
+
if (node === true) return true;
|
|
26
|
+
return node !== false && Object.keys(node).length > 0;
|
|
27
|
+
}
|
|
28
|
+
getChangedKeys(path) {
|
|
29
|
+
const node = lookupChange(this.changes, path);
|
|
30
|
+
if (node === false) return [];
|
|
31
|
+
if (node === true) return diffKeys(lookupValue(this.accumulator.state, path), lookupValue(this.previousState, path));
|
|
32
|
+
return Object.keys(node);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
//#endregion
|
|
36
|
+
export { GorpStreamDeltaTracker };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=GorpStreamDeltaTracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GorpStreamDeltaTracker.js","names":[],"sources":["../../../src/core/gorp/GorpStreamDeltaTracker.ts"],"sourcesContent":["import type { ReadonlyJSONValue } from \"../../utils\";\nimport { GorpStreamAccumulator } from \"./GorpStreamAccumulator\";\nimport type { GorpStreamOperation } from \"./types\";\nimport {\n type ChangeNode,\n createChangeNode,\n diffKeys,\n lookupChange,\n lookupValue,\n markChanged,\n} from \"./changeTree\";\n\nexport class GorpStreamDeltaTracker {\n private readonly accumulator: GorpStreamAccumulator;\n private previousState: ReadonlyJSONValue;\n private changes: ChangeNode = createChangeNode();\n\n constructor(initialValue: ReadonlyJSONValue = null) {\n this.accumulator = new GorpStreamAccumulator(initialValue);\n this.previousState = this.accumulator.state;\n }\n\n get state(): ReadonlyJSONValue {\n return this.accumulator.state;\n }\n\n append(operations: readonly GorpStreamOperation[]): void {\n const previousState = this.accumulator.state;\n let changes: ChangeNode = createChangeNode();\n for (const op of operations) {\n changes = markChanged(changes, op.path);\n }\n this.accumulator.append(operations);\n this.previousState = previousState;\n this.changes = changes;\n }\n\n isChangedAt(path: readonly string[]): boolean {\n const node = lookupChange(this.changes, path);\n if (node === true) return true;\n return node !== false && Object.keys(node).length > 0;\n }\n\n getChangedKeys(path: readonly string[]): string[] {\n const node = lookupChange(this.changes, path);\n if (node === false) return [];\n if (node === true) {\n return diffKeys(\n lookupValue(this.accumulator.state, path),\n lookupValue(this.previousState, path),\n );\n }\n return Object.keys(node);\n }\n}\n"],"mappings":";;;AAYA,IAAa,yBAAb,MAAoC;CAClC;CACA;CACA,UAA8B,iBAAiB;CAE/C,YAAY,eAAkC,MAAM;EAClD,KAAK,cAAc,IAAI,sBAAsB,YAAY;EACzD,KAAK,gBAAgB,KAAK,YAAY;CACxC;CAEA,IAAI,QAA2B;EAC7B,OAAO,KAAK,YAAY;CAC1B;CAEA,OAAO,YAAkD;EACvD,MAAM,gBAAgB,KAAK,YAAY;EACvC,IAAI,UAAsB,iBAAiB;EAC3C,KAAK,MAAM,MAAM,YACf,UAAU,YAAY,SAAS,GAAG,IAAI;EAExC,KAAK,YAAY,OAAO,UAAU;EAClC,KAAK,gBAAgB;EACrB,KAAK,UAAU;CACjB;CAEA,YAAY,MAAkC;EAC5C,MAAM,OAAO,aAAa,KAAK,SAAS,IAAI;EAC5C,IAAI,SAAS,MAAM,OAAO;EAC1B,OAAO,SAAS,SAAS,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS;CACtD;CAEA,eAAe,MAAmC;EAChD,MAAM,OAAO,aAAa,KAAK,SAAS,IAAI;EAC5C,IAAI,SAAS,OAAO,OAAO,CAAC;EAC5B,IAAI,SAAS,MACX,OAAO,SACL,YAAY,KAAK,YAAY,OAAO,IAAI,GACxC,YAAY,KAAK,eAAe,IAAI,CACtC;EAEF,OAAO,OAAO,KAAK,IAAI;CACzB;AACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { GorpStreamChunk } from "./types.js";
|
|
2
|
+
import { PipeableTransformStream } from "../utils/stream/PipeableTransformStream.js";
|
|
3
|
+
//#region src/core/gorp/GorpStreamResponse.d.ts
|
|
4
|
+
declare class GorpStreamEncoder extends PipeableTransformStream<GorpStreamChunk, Uint8Array> {
|
|
5
|
+
constructor();
|
|
6
|
+
}
|
|
7
|
+
declare class GorpStreamDecoder extends PipeableTransformStream<Uint8Array<ArrayBuffer>, GorpStreamChunk> {
|
|
8
|
+
constructor();
|
|
9
|
+
}
|
|
10
|
+
declare class GorpStreamResponse extends Response {
|
|
11
|
+
constructor(body: ReadableStream<GorpStreamChunk>);
|
|
12
|
+
}
|
|
13
|
+
declare const fromGorpStreamResponse: (response: Response) => ReadableStream<GorpStreamChunk>;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { GorpStreamDecoder, GorpStreamEncoder, GorpStreamResponse, fromGorpStreamResponse };
|
|
16
|
+
//# sourceMappingURL=GorpStreamResponse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GorpStreamResponse.d.ts","names":[],"sources":["../../../src/core/gorp/GorpStreamResponse.ts"],"mappings":";;;cAKa,0BAA0B,wBACrC,iBACA;;;cAyBW,0BAA0B,wBACrC,WAAW,cACX;;;cAsBW,2BAA2B;EAC1B,YAAA,MAAM,eAAe;;cAYtB,yBACX,UAAU,aACT,eAAe"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { PipeableTransformStream } from "../utils/stream/PipeableTransformStream.js";
|
|
2
|
+
import { GorpStreamAccumulator } from "./GorpStreamAccumulator.js";
|
|
3
|
+
import { SSEDecoder, SSEEncoder } from "../utils/stream/SSE.js";
|
|
4
|
+
//#region src/core/gorp/GorpStreamResponse.ts
|
|
5
|
+
var GorpStreamEncoder = class extends PipeableTransformStream {
|
|
6
|
+
constructor() {
|
|
7
|
+
let isFirstChunk = true;
|
|
8
|
+
super((readable) => readable.pipeThrough(new TransformStream({ transform(chunk, controller) {
|
|
9
|
+
if (isFirstChunk) controller.enqueue([{
|
|
10
|
+
type: "set",
|
|
11
|
+
path: [],
|
|
12
|
+
value: chunk.snapshot
|
|
13
|
+
}]);
|
|
14
|
+
else controller.enqueue(chunk.operations);
|
|
15
|
+
isFirstChunk = false;
|
|
16
|
+
} })).pipeThrough(new SSEEncoder()));
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var GorpStreamDecoder = class extends PipeableTransformStream {
|
|
20
|
+
constructor() {
|
|
21
|
+
const accumulator = new GorpStreamAccumulator();
|
|
22
|
+
super((readable) => readable.pipeThrough(new SSEDecoder()).pipeThrough(new TransformStream({ transform(operations, controller) {
|
|
23
|
+
accumulator.append(operations);
|
|
24
|
+
controller.enqueue({
|
|
25
|
+
snapshot: accumulator.state,
|
|
26
|
+
operations
|
|
27
|
+
});
|
|
28
|
+
} })));
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var GorpStreamResponse = class extends Response {
|
|
32
|
+
constructor(body) {
|
|
33
|
+
super(body.pipeThrough(new GorpStreamEncoder()), { headers: new Headers({
|
|
34
|
+
"Content-Type": "text/event-stream",
|
|
35
|
+
"Cache-Control": "no-cache",
|
|
36
|
+
Connection: "keep-alive",
|
|
37
|
+
"Assistant-Stream-Format": "object-stream/v0"
|
|
38
|
+
}) });
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const fromGorpStreamResponse = (response) => {
|
|
42
|
+
if (!response.ok) throw new Error(`Response failed, status ${response.status}`);
|
|
43
|
+
if (!response.body) throw new Error("Response body is null");
|
|
44
|
+
if (response.headers.get("Content-Type")?.split(";", 1)[0]?.trim().toLowerCase() !== "text/event-stream") throw new Error("Response is not an event stream");
|
|
45
|
+
if (response.headers.get("Assistant-Stream-Format") !== "object-stream/v0") throw new Error("Unsupported Assistant-Stream-Format header");
|
|
46
|
+
return response.body.pipeThrough(new GorpStreamDecoder());
|
|
47
|
+
};
|
|
48
|
+
//#endregion
|
|
49
|
+
export { GorpStreamDecoder, GorpStreamEncoder, GorpStreamResponse, fromGorpStreamResponse };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=GorpStreamResponse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GorpStreamResponse.js","names":[],"sources":["../../../src/core/gorp/GorpStreamResponse.ts"],"sourcesContent":["import { PipeableTransformStream } from \"../utils/stream/PipeableTransformStream\";\nimport { GorpStreamAccumulator } from \"./GorpStreamAccumulator\";\nimport { SSEDecoder, SSEEncoder } from \"../utils/stream/SSE\";\nimport type { GorpStreamChunk, GorpStreamOperation } from \"./types\";\n\nexport class GorpStreamEncoder extends PipeableTransformStream<\n GorpStreamChunk,\n Uint8Array\n> {\n constructor() {\n let isFirstChunk = true;\n super((readable) =>\n readable\n .pipeThrough(\n new TransformStream<GorpStreamChunk, readonly GorpStreamOperation[]>({\n transform(chunk, controller) {\n if (isFirstChunk) {\n controller.enqueue([\n { type: \"set\", path: [], value: chunk.snapshot },\n ]);\n } else {\n controller.enqueue(chunk.operations);\n }\n isFirstChunk = false;\n },\n }),\n )\n .pipeThrough(new SSEEncoder()),\n );\n }\n}\n\nexport class GorpStreamDecoder extends PipeableTransformStream<\n Uint8Array<ArrayBuffer>,\n GorpStreamChunk\n> {\n constructor() {\n const accumulator = new GorpStreamAccumulator();\n super((readable) =>\n readable\n .pipeThrough(new SSEDecoder<readonly GorpStreamOperation[]>())\n .pipeThrough(\n new TransformStream<readonly GorpStreamOperation[], GorpStreamChunk>({\n transform(operations, controller) {\n accumulator.append(operations);\n controller.enqueue({\n snapshot: accumulator.state,\n operations,\n });\n },\n }),\n ),\n );\n }\n}\n\nexport class GorpStreamResponse extends Response {\n constructor(body: ReadableStream<GorpStreamChunk>) {\n super(body.pipeThrough(new GorpStreamEncoder()), {\n headers: new Headers({\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Assistant-Stream-Format\": \"object-stream/v0\",\n }),\n });\n }\n}\n\nexport const fromGorpStreamResponse = (\n response: Response,\n): ReadableStream<GorpStreamChunk> => {\n if (!response.ok)\n throw new Error(`Response failed, status ${response.status}`);\n if (!response.body) throw new Error(\"Response body is null\");\n const mediaType = response.headers\n .get(\"Content-Type\")\n ?.split(\";\", 1)[0]\n ?.trim()\n .toLowerCase();\n if (mediaType !== \"text/event-stream\") {\n throw new Error(\"Response is not an event stream\");\n }\n if (response.headers.get(\"Assistant-Stream-Format\") !== \"object-stream/v0\") {\n throw new Error(\"Unsupported Assistant-Stream-Format header\");\n }\n return response.body.pipeThrough(new GorpStreamDecoder());\n};\n"],"mappings":";;;;AAKA,IAAa,oBAAb,cAAuC,wBAGrC;CACA,cAAc;EACZ,IAAI,eAAe;EACnB,OAAO,aACL,SACG,YACC,IAAI,gBAAiE,EACnE,UAAU,OAAO,YAAY;GAC3B,IAAI,cACF,WAAW,QAAQ,CACjB;IAAE,MAAM;IAAO,MAAM,CAAC;IAAG,OAAO,MAAM;GAAS,CACjD,CAAC;QAED,WAAW,QAAQ,MAAM,UAAU;GAErC,eAAe;EACjB,EACF,CAAC,CACH,CAAC,CACA,YAAY,IAAI,WAAW,CAAC,CACjC;CACF;AACF;AAEA,IAAa,oBAAb,cAAuC,wBAGrC;CACA,cAAc;EACZ,MAAM,cAAc,IAAI,sBAAsB;EAC9C,OAAO,aACL,SACG,YAAY,IAAI,WAA2C,CAAC,CAAC,CAC7D,YACC,IAAI,gBAAiE,EACnE,UAAU,YAAY,YAAY;GAChC,YAAY,OAAO,UAAU;GAC7B,WAAW,QAAQ;IACjB,UAAU,YAAY;IACtB;GACF,CAAC;EACH,EACF,CAAC,CACH,CACJ;CACF;AACF;AAEA,IAAa,qBAAb,cAAwC,SAAS;CAC/C,YAAY,MAAuC;EACjD,MAAM,KAAK,YAAY,IAAI,kBAAkB,CAAC,GAAG,EAC/C,SAAS,IAAI,QAAQ;GACnB,gBAAgB;GAChB,iBAAiB;GACjB,YAAY;GACZ,2BAA2B;EAC7B,CAAC,EACH,CAAC;CACH;AACF;AAEA,MAAa,0BACX,aACoC;CACpC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,2BAA2B,SAAS,QAAQ;CAC9D,IAAI,CAAC,SAAS,MAAM,MAAM,IAAI,MAAM,uBAAuB;CAM3D,IALkB,SAAS,QACxB,IAAI,cAAc,CAAC,EAClB,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE,EAChB,KAAK,CAAC,CACP,YAAY,MACG,qBAChB,MAAM,IAAI,MAAM,iCAAiC;CAEnD,IAAI,SAAS,QAAQ,IAAI,yBAAyB,MAAM,oBACtD,MAAM,IAAI,MAAM,4CAA4C;CAE9D,OAAO,SAAS,KAAK,YAAY,IAAI,kBAAkB,CAAC;AAC1D"}
|