@anvia/client 1.0.0-rc.2
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/LICENSE +21 -0
- package/README.md +61 -0
- package/dist/chunk-2KGXQZWA.js +201 -0
- package/dist/chunk-2KGXQZWA.js.map +1 -0
- package/dist/event-transport-CC5RD-hT.d.ts +31 -0
- package/dist/index.d.ts +461 -0
- package/dist/index.js +2380 -0
- package/dist/index.js.map +1 -0
- package/dist/transport/index.d.ts +21 -0
- package/dist/transport/index.js +17 -0
- package/dist/transport/index.js.map +1 -0
- package/package.json +48 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2380 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createFetchEventTransport
|
|
3
|
+
} from "./chunk-2KGXQZWA.js";
|
|
4
|
+
|
|
5
|
+
// src/adapters.ts
|
|
6
|
+
import {
|
|
7
|
+
isJsonValue as isJsonValue3
|
|
8
|
+
} from "@anvia/core/completion";
|
|
9
|
+
|
|
10
|
+
// src/messages.ts
|
|
11
|
+
import { isJsonValue } from "@anvia/core/completion";
|
|
12
|
+
function uiMessagesToMessages(messages) {
|
|
13
|
+
const result = [];
|
|
14
|
+
for (const message of messages) {
|
|
15
|
+
assertMetadata(message.metadata);
|
|
16
|
+
if (message.role === "system") {
|
|
17
|
+
assertOnlyParts(message, ["text", "data", "error"]);
|
|
18
|
+
result.push({
|
|
19
|
+
role: "system",
|
|
20
|
+
content: textFromParts(message.parts),
|
|
21
|
+
...metadataField(message.metadata)
|
|
22
|
+
});
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (message.role === "user") {
|
|
26
|
+
assertOnlyParts(message, ["text", "attachment", "data", "error"]);
|
|
27
|
+
const content2 = [];
|
|
28
|
+
for (const part of message.parts) {
|
|
29
|
+
if (part.type === "text") {
|
|
30
|
+
content2.push(textContent(part.text, part.signature));
|
|
31
|
+
} else if (part.type === "attachment") {
|
|
32
|
+
content2.push(attachmentToUserContent(part.attachment));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
result.push({ role: "user", content: content2, ...metadataField(message.metadata) });
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (message.role === "assistant") {
|
|
39
|
+
assertOnlyParts(message, [
|
|
40
|
+
"text",
|
|
41
|
+
"reasoning",
|
|
42
|
+
"tool",
|
|
43
|
+
"attachment",
|
|
44
|
+
"source",
|
|
45
|
+
"data",
|
|
46
|
+
"error"
|
|
47
|
+
]);
|
|
48
|
+
const content2 = [];
|
|
49
|
+
const toolResults = [];
|
|
50
|
+
for (const part of message.parts) {
|
|
51
|
+
if (part.type === "text") {
|
|
52
|
+
content2.push(textContent(part.text, part.signature));
|
|
53
|
+
} else if (part.type === "reasoning") {
|
|
54
|
+
content2.push({
|
|
55
|
+
type: "reasoning",
|
|
56
|
+
text: part.text,
|
|
57
|
+
...part.reasoningId === void 0 ? {} : { id: part.reasoningId },
|
|
58
|
+
...part.content === void 0 ? {} : { details: part.content }
|
|
59
|
+
});
|
|
60
|
+
} else if (part.type === "tool") {
|
|
61
|
+
content2.push({
|
|
62
|
+
type: "tool-call",
|
|
63
|
+
toolCallId: part.toolCallId,
|
|
64
|
+
...part.callId === void 0 ? {} : { callId: part.callId },
|
|
65
|
+
toolName: part.toolName,
|
|
66
|
+
input: part.input ?? {},
|
|
67
|
+
...part.signature === void 0 ? {} : { signature: part.signature }
|
|
68
|
+
});
|
|
69
|
+
if (part.state === "output-available" || part.state === "error") {
|
|
70
|
+
toolResults.push(toolResultFromPart(part));
|
|
71
|
+
}
|
|
72
|
+
} else if (part.type === "attachment") {
|
|
73
|
+
content2.push(attachmentToAssistantContent(part.attachment));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
result.push({
|
|
77
|
+
role: "assistant",
|
|
78
|
+
content: content2,
|
|
79
|
+
...message.modelMessageId === void 0 ? {} : { id: message.modelMessageId },
|
|
80
|
+
...metadataField(message.metadata)
|
|
81
|
+
});
|
|
82
|
+
if (toolResults.length > 0) {
|
|
83
|
+
result.push({ role: "tool", content: toolResults });
|
|
84
|
+
}
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
assertOnlyParts(message, ["tool", "data", "error"]);
|
|
88
|
+
const content = message.parts.flatMap(
|
|
89
|
+
(part) => part.type === "tool" && (part.state === "output-available" || part.state === "error") ? [toolResultFromPart(part)] : []
|
|
90
|
+
);
|
|
91
|
+
result.push({ role: "tool", content, ...metadataField(message.metadata) });
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
function messagesToUIMessages(messages) {
|
|
96
|
+
const result = [];
|
|
97
|
+
const byToolCallId = /* @__PURE__ */ new Map();
|
|
98
|
+
const byCallId = /* @__PURE__ */ new Map();
|
|
99
|
+
for (const message of messages) {
|
|
100
|
+
assertMetadata(message.metadata);
|
|
101
|
+
if (message.role === "system") {
|
|
102
|
+
result.push({
|
|
103
|
+
id: createId("msg"),
|
|
104
|
+
role: "system",
|
|
105
|
+
parts: [{ id: createId("part"), type: "text", text: message.content }],
|
|
106
|
+
...metadataField(message.metadata)
|
|
107
|
+
});
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (message.role === "user") {
|
|
111
|
+
const content = typeof message.content === "string" ? [{ type: "text", text: message.content }] : message.content;
|
|
112
|
+
const parts = content.map((part) => contentToUIMessagePart(part));
|
|
113
|
+
result.push({
|
|
114
|
+
id: createId("msg"),
|
|
115
|
+
role: "user",
|
|
116
|
+
parts,
|
|
117
|
+
...metadataField(message.metadata)
|
|
118
|
+
});
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (message.role === "assistant") {
|
|
122
|
+
const content = typeof message.content === "string" ? [{ type: "text", text: message.content }] : message.content;
|
|
123
|
+
const parts = content.map(assistantContentToUIMessagePart);
|
|
124
|
+
const uiMessage = {
|
|
125
|
+
id: createId("msg"),
|
|
126
|
+
role: "assistant",
|
|
127
|
+
parts,
|
|
128
|
+
...message.id === void 0 ? {} : { modelMessageId: message.id },
|
|
129
|
+
...metadataField(message.metadata)
|
|
130
|
+
};
|
|
131
|
+
const messageIndex = result.length;
|
|
132
|
+
result.push(uiMessage);
|
|
133
|
+
for (const [partIndex, part] of parts.entries()) {
|
|
134
|
+
if (part.type !== "tool") continue;
|
|
135
|
+
const location = { messageIndex, partIndex };
|
|
136
|
+
byToolCallId.set(part.toolCallId, location);
|
|
137
|
+
if (part.callId !== void 0) byCallId.set(part.callId, location);
|
|
138
|
+
}
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const unmerged = [];
|
|
142
|
+
for (const content of message.content) {
|
|
143
|
+
const location = (content.callId === void 0 ? void 0 : byCallId.get(content.callId)) ?? byToolCallId.get(content.toolCallId);
|
|
144
|
+
const part = toolResultToUIMessagePart(content, toolNameAt(result, location));
|
|
145
|
+
if (message.metadata === void 0 && location !== void 0) {
|
|
146
|
+
const owner = result[location.messageIndex];
|
|
147
|
+
const existing = owner?.parts[location.partIndex];
|
|
148
|
+
if (owner !== void 0 && existing?.type === "tool") {
|
|
149
|
+
const parts = [...owner.parts];
|
|
150
|
+
parts[location.partIndex] = { ...existing, ...part, id: existing.id };
|
|
151
|
+
result[location.messageIndex] = { ...owner, parts };
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
unmerged.push(part);
|
|
156
|
+
}
|
|
157
|
+
if (unmerged.length > 0 || message.metadata !== void 0) {
|
|
158
|
+
result.push({
|
|
159
|
+
id: createId("msg"),
|
|
160
|
+
role: "tool",
|
|
161
|
+
parts: unmerged,
|
|
162
|
+
...metadataField(message.metadata)
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
function contentToUIMessagePart(content) {
|
|
169
|
+
if (content.type === "text") {
|
|
170
|
+
return {
|
|
171
|
+
id: createId("part"),
|
|
172
|
+
type: "text",
|
|
173
|
+
text: content.text,
|
|
174
|
+
...content.signature === void 0 ? {} : { signature: content.signature }
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
id: createId("part"),
|
|
179
|
+
type: "attachment",
|
|
180
|
+
attachment: contentToAttachment(content)
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function assistantContentToUIMessagePart(content) {
|
|
184
|
+
if (content.type === "text") return contentToUIMessagePart(content);
|
|
185
|
+
if (content.type === "reasoning") {
|
|
186
|
+
return {
|
|
187
|
+
id: createId("part"),
|
|
188
|
+
type: "reasoning",
|
|
189
|
+
text: content.text,
|
|
190
|
+
...content.id === void 0 ? {} : { reasoningId: content.id },
|
|
191
|
+
...content.details === void 0 ? {} : { content: content.details }
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
if (content.type === "tool-call") {
|
|
195
|
+
return {
|
|
196
|
+
id: toolPartId(content.toolCallId),
|
|
197
|
+
type: "tool",
|
|
198
|
+
toolName: content.toolName,
|
|
199
|
+
toolCallId: content.toolCallId,
|
|
200
|
+
state: "input-available",
|
|
201
|
+
input: content.input,
|
|
202
|
+
...content.callId === void 0 ? {} : { callId: content.callId },
|
|
203
|
+
...content.signature === void 0 ? {} : { signature: content.signature }
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
id: createId("part"),
|
|
208
|
+
type: "attachment",
|
|
209
|
+
attachment: contentToAttachment(content)
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function textContent(text, signature) {
|
|
213
|
+
return signature === void 0 ? { type: "text", text } : { type: "text", text, signature };
|
|
214
|
+
}
|
|
215
|
+
function toolResultFromPart(part) {
|
|
216
|
+
return {
|
|
217
|
+
type: "tool-result",
|
|
218
|
+
toolCallId: part.toolCallId,
|
|
219
|
+
...part.callId === void 0 ? {} : { callId: part.callId },
|
|
220
|
+
toolName: part.toolName,
|
|
221
|
+
output: toolOutputFromPart(part)
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function toolOutputFromPart(part) {
|
|
225
|
+
if (part.state === "error") {
|
|
226
|
+
return { type: "error-text", value: part.error?.message ?? "Tool execution failed." };
|
|
227
|
+
}
|
|
228
|
+
if (part.resultContent !== void 0) {
|
|
229
|
+
return { type: "content", value: part.resultContent };
|
|
230
|
+
}
|
|
231
|
+
const output = part.output ?? null;
|
|
232
|
+
return typeof output === "string" ? { type: "text", value: output } : { type: "json", value: output };
|
|
233
|
+
}
|
|
234
|
+
function attachmentToUserContent(attachment) {
|
|
235
|
+
if (attachment.type === "image" || attachment.mediaType?.startsWith("image/") === true) {
|
|
236
|
+
return attachmentToImageContent(attachment);
|
|
237
|
+
}
|
|
238
|
+
return attachmentToFileContent(attachment);
|
|
239
|
+
}
|
|
240
|
+
function attachmentToAssistantContent(attachment) {
|
|
241
|
+
return attachment.type === "image" || attachment.mediaType?.startsWith("image/") === true ? attachmentToImageContent(attachment) : attachmentToFileContent(attachment);
|
|
242
|
+
}
|
|
243
|
+
function attachmentToImageContent(attachment) {
|
|
244
|
+
const image = attachment.url !== void 0 ? { type: "url", url: attachment.url } : attachment.data !== void 0 ? { type: "data", data: attachment.data } : (() => {
|
|
245
|
+
throw new TypeError("Image attachments require a URL or base64 data.");
|
|
246
|
+
})();
|
|
247
|
+
return {
|
|
248
|
+
type: "image",
|
|
249
|
+
image,
|
|
250
|
+
...attachment.mediaType === void 0 ? {} : { mediaType: attachment.mediaType },
|
|
251
|
+
...attachment.detail === void 0 ? {} : { detail: attachment.detail }
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function attachmentToFileContent(attachment) {
|
|
255
|
+
const data = attachment.url !== void 0 ? { type: "url", url: attachment.url } : attachment.data !== void 0 ? { type: "data", data: attachment.data } : attachment.text !== void 0 ? { type: "text", text: attachment.text } : (() => {
|
|
256
|
+
throw new TypeError("File attachments require a URL, base64 data, or text.");
|
|
257
|
+
})();
|
|
258
|
+
return {
|
|
259
|
+
type: "file",
|
|
260
|
+
data,
|
|
261
|
+
mediaType: attachment.mediaType ?? "application/octet-stream",
|
|
262
|
+
...attachment.name === void 0 ? {} : { filename: attachment.name }
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function contentToAttachment(content) {
|
|
266
|
+
const attachment = {
|
|
267
|
+
id: createId("attachment"),
|
|
268
|
+
type: content.type === "image" ? "image" : "file"
|
|
269
|
+
};
|
|
270
|
+
if (content.type === "image") {
|
|
271
|
+
if (content.detail !== void 0) attachment.detail = content.detail;
|
|
272
|
+
if (content.mediaType !== void 0) attachment.mediaType = content.mediaType;
|
|
273
|
+
if (content.image.type === "url") attachment.url = content.image.url;
|
|
274
|
+
else attachment.data = content.image.data;
|
|
275
|
+
return attachment;
|
|
276
|
+
}
|
|
277
|
+
attachment.mediaType = content.mediaType;
|
|
278
|
+
if (content.filename !== void 0) attachment.name = content.filename;
|
|
279
|
+
if (content.data.type === "url") attachment.url = content.data.url;
|
|
280
|
+
else if (content.data.type === "data") attachment.data = content.data.data;
|
|
281
|
+
else attachment.text = content.data.text;
|
|
282
|
+
return attachment;
|
|
283
|
+
}
|
|
284
|
+
function toolResultToUIMessagePart(content, fallbackToolName) {
|
|
285
|
+
const output = content.output;
|
|
286
|
+
const common = {
|
|
287
|
+
id: toolPartId(content.toolCallId),
|
|
288
|
+
type: "tool",
|
|
289
|
+
toolName: content.toolName || fallbackToolName || "tool",
|
|
290
|
+
toolCallId: content.toolCallId,
|
|
291
|
+
...content.callId === void 0 ? {} : { callId: content.callId }
|
|
292
|
+
};
|
|
293
|
+
if (output.type === "error-text" || output.type === "error-json") {
|
|
294
|
+
return {
|
|
295
|
+
...common,
|
|
296
|
+
state: "error",
|
|
297
|
+
error: {
|
|
298
|
+
message: output.type === "error-text" ? output.value : JSON.stringify(output.value)
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
if (output.type === "execution-denied") {
|
|
303
|
+
return {
|
|
304
|
+
...common,
|
|
305
|
+
state: "error",
|
|
306
|
+
error: { message: output.reason ?? "Tool execution was denied." }
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
...common,
|
|
311
|
+
state: "output-available",
|
|
312
|
+
output: toolResultOutput(output),
|
|
313
|
+
...output.type === "content" ? { resultContent: output.value } : {}
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function toolResultOutput(output) {
|
|
317
|
+
if (output.type === "text" || output.type === "error-text") return output.value;
|
|
318
|
+
if (output.type === "json" || output.type === "error-json") return output.value;
|
|
319
|
+
if (output.type === "execution-denied") return output.reason ?? "Tool execution was denied.";
|
|
320
|
+
return output.value.length === 1 && output.value[0]?.type === "text" ? output.value[0].text : output.value.map(
|
|
321
|
+
(part) => part.type === "text" ? { ...part } : { ...part, data: { ...part.data } }
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
function toolNameAt(messages, location) {
|
|
325
|
+
if (location === void 0) return void 0;
|
|
326
|
+
const part = messages[location.messageIndex]?.parts[location.partIndex];
|
|
327
|
+
return part?.type === "tool" ? part.toolName : void 0;
|
|
328
|
+
}
|
|
329
|
+
function textFromParts(parts) {
|
|
330
|
+
return parts.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
|
|
331
|
+
}
|
|
332
|
+
function assertOnlyParts(message, allowed) {
|
|
333
|
+
for (const part of message.parts) {
|
|
334
|
+
if (!allowed.includes(part.type)) {
|
|
335
|
+
throw new TypeError(`${message.role} UI messages cannot contain ${part.type} parts.`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function assertMetadata(metadata) {
|
|
340
|
+
if (metadata !== void 0 && (!isJsonValue(metadata) || Array.isArray(metadata))) {
|
|
341
|
+
throw new TypeError("Message metadata must be a strict JSON object.");
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
function metadataField(metadata) {
|
|
345
|
+
return metadata === void 0 ? {} : { metadata };
|
|
346
|
+
}
|
|
347
|
+
function toolPartId(toolCallId) {
|
|
348
|
+
return `tool_${toolCallId}`;
|
|
349
|
+
}
|
|
350
|
+
var nextId = 0;
|
|
351
|
+
function createClientId(prefix) {
|
|
352
|
+
const random = globalThis.crypto?.randomUUID?.();
|
|
353
|
+
if (random !== void 0) return `${prefix}_${random}`;
|
|
354
|
+
nextId += 1;
|
|
355
|
+
return `${prefix}_${nextId.toString(36)}`;
|
|
356
|
+
}
|
|
357
|
+
function createId(prefix) {
|
|
358
|
+
return createClientId(prefix);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// src/protocol.ts
|
|
362
|
+
import { isJsonValue as isJsonValue2, parseMessages } from "@anvia/core/completion";
|
|
363
|
+
|
|
364
|
+
// src/types.ts
|
|
365
|
+
var CLIENT_STREAM_PROTOCOL = "anvia.client.v2";
|
|
366
|
+
|
|
367
|
+
// src/protocol.ts
|
|
368
|
+
var ClientProtocolError = class extends Error {
|
|
369
|
+
constructor(message, value) {
|
|
370
|
+
super(message);
|
|
371
|
+
this.value = value;
|
|
372
|
+
this.name = "ClientProtocolError";
|
|
373
|
+
}
|
|
374
|
+
value;
|
|
375
|
+
};
|
|
376
|
+
function parseUIMessage(value, options = {}) {
|
|
377
|
+
const message = requireRecord(value, "UI message");
|
|
378
|
+
if (!isJsonValue2(message)) {
|
|
379
|
+
throw new ClientProtocolError("UI messages must be strict JSON values.", value);
|
|
380
|
+
}
|
|
381
|
+
requireOnlyKeys(
|
|
382
|
+
message,
|
|
383
|
+
["id", "role", "parts", "modelMessageId", "metadata", "generation"],
|
|
384
|
+
"UI message"
|
|
385
|
+
);
|
|
386
|
+
if (typeof message.id !== "string") invalid("UI message.id", value);
|
|
387
|
+
requireOneOf(message.role, ["system", "user", "assistant", "tool"], "UI message.role", value);
|
|
388
|
+
if (!Array.isArray(message.parts)) invalid("UI message.parts", value);
|
|
389
|
+
const parts = message.parts.map((part) => parseUIMessagePart(part, options.dataSchemas, value));
|
|
390
|
+
if (message.modelMessageId !== void 0 && typeof message.modelMessageId !== "string") {
|
|
391
|
+
invalid("UI message.modelMessageId", value);
|
|
392
|
+
}
|
|
393
|
+
const metadata = message.metadata === void 0 ? void 0 : parseMetadata(message.metadata, options.metadataSchema, value);
|
|
394
|
+
if (message.generation !== void 0 && !isUIMessageGeneration(message.generation)) {
|
|
395
|
+
invalid("UI message.generation", value);
|
|
396
|
+
}
|
|
397
|
+
return {
|
|
398
|
+
id: message.id,
|
|
399
|
+
role: message.role,
|
|
400
|
+
parts,
|
|
401
|
+
...message.modelMessageId === void 0 ? {} : { modelMessageId: message.modelMessageId },
|
|
402
|
+
...metadata === void 0 ? {} : { metadata },
|
|
403
|
+
...message.generation === void 0 ? {} : { generation: message.generation }
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
function parseUIMessages(value, options = {}) {
|
|
407
|
+
if (!Array.isArray(value)) {
|
|
408
|
+
throw new ClientProtocolError("UI messages must be an array.", value);
|
|
409
|
+
}
|
|
410
|
+
return value.map((message) => parseUIMessage(message, options));
|
|
411
|
+
}
|
|
412
|
+
function parseClientStreamRequest(value) {
|
|
413
|
+
const input = requireRecord(value, "Client stream request");
|
|
414
|
+
requireOnlyKeys(input, ["messages", "metadata", "resume"], "Client stream request");
|
|
415
|
+
let messages;
|
|
416
|
+
try {
|
|
417
|
+
messages = parseMessages(input.messages);
|
|
418
|
+
} catch {
|
|
419
|
+
throw new ClientProtocolError("Client stream request.messages must be Message[].", value);
|
|
420
|
+
}
|
|
421
|
+
if (input.metadata !== void 0 && !isJsonObject(input.metadata)) {
|
|
422
|
+
throw new ClientProtocolError("Client stream request.metadata must be a JSON object.", value);
|
|
423
|
+
}
|
|
424
|
+
const request = { messages };
|
|
425
|
+
if (input.metadata !== void 0) request.metadata = input.metadata;
|
|
426
|
+
if (input.resume !== void 0) {
|
|
427
|
+
const resume = requireRecord(input.resume, "Client stream request.resume");
|
|
428
|
+
requireOnlyKeys(resume, ["streamId", "after"], "Client stream request.resume");
|
|
429
|
+
if (typeof resume.streamId !== "string" || !isEventId(resume.after)) {
|
|
430
|
+
throw new ClientProtocolError(
|
|
431
|
+
"Client stream resume cursor requires streamId and a nonnegative safe integer after.",
|
|
432
|
+
value
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
request.resume = { streamId: resume.streamId, after: resume.after };
|
|
436
|
+
}
|
|
437
|
+
return request;
|
|
438
|
+
}
|
|
439
|
+
function parseClientStreamEvent(value, options = {}) {
|
|
440
|
+
const event = requireRecord(value, "Client stream event");
|
|
441
|
+
if (!isJsonValue2(event)) {
|
|
442
|
+
throw new ClientProtocolError("Client stream events must be strict JSON values.", value);
|
|
443
|
+
}
|
|
444
|
+
if (typeof event.type !== "string" || typeof event.runId !== "string") {
|
|
445
|
+
throw new ClientProtocolError("Client stream events require type and runId.", value);
|
|
446
|
+
}
|
|
447
|
+
if (event.turn !== void 0 && !isPositiveEventId(event.turn)) {
|
|
448
|
+
throw new ClientProtocolError(
|
|
449
|
+
"Client stream event.turn must be a positive safe integer.",
|
|
450
|
+
value
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
if (event.scope !== void 0 && !isScope(event.scope)) {
|
|
454
|
+
throw new ClientProtocolError("Client stream event.scope is invalid.", value);
|
|
455
|
+
}
|
|
456
|
+
switch (event.type) {
|
|
457
|
+
case "run_start":
|
|
458
|
+
requireEventKeys(event, ["source", "metadata"]);
|
|
459
|
+
requireOneOf(event.source, ["completion", "agent"], "run_start.source", value);
|
|
460
|
+
break;
|
|
461
|
+
case "turn_start":
|
|
462
|
+
requireEventKeys(event, []);
|
|
463
|
+
if (!isPositiveEventId(event.turn)) invalid("turn_start.turn", value);
|
|
464
|
+
break;
|
|
465
|
+
case "generation_start":
|
|
466
|
+
requireEventKeys(event, ["model"]);
|
|
467
|
+
if (event.model !== void 0 && (!isRecord(event.model) || !hasOnlyKeys(event.model, ["provider", "modelId"]) || typeof event.model.provider !== "string" || typeof event.model.modelId !== "string")) {
|
|
468
|
+
invalid("generation_start.model", value);
|
|
469
|
+
}
|
|
470
|
+
break;
|
|
471
|
+
case "message_start":
|
|
472
|
+
requireEventKeys(event, ["messageId", "role", "metadata"]);
|
|
473
|
+
requireStrings(event, ["messageId"], value);
|
|
474
|
+
if (event.role !== "assistant") invalid("message_start.role", value);
|
|
475
|
+
break;
|
|
476
|
+
case "text_start":
|
|
477
|
+
requireEventKeys(event, ["messageId", "partId"]);
|
|
478
|
+
requireStrings(event, ["messageId", "partId"], value);
|
|
479
|
+
break;
|
|
480
|
+
case "text_delta":
|
|
481
|
+
requireEventKeys(event, ["messageId", "partId", "delta"]);
|
|
482
|
+
requireStrings(event, ["messageId", "partId", "delta"], value);
|
|
483
|
+
break;
|
|
484
|
+
case "reasoning_delta":
|
|
485
|
+
requireEventKeys(event, ["messageId", "partId", "delta", "contentType", "signature"]);
|
|
486
|
+
requireStrings(event, ["messageId", "partId", "delta"], value);
|
|
487
|
+
requireOptionalStrings(event, ["signature"], value);
|
|
488
|
+
if (event.contentType !== void 0 && !["text", "summary", "encrypted", "redacted"].includes(event.contentType)) {
|
|
489
|
+
invalid("reasoning_delta.contentType", value);
|
|
490
|
+
}
|
|
491
|
+
break;
|
|
492
|
+
case "text_end":
|
|
493
|
+
requireEventKeys(event, ["messageId", "partId", "text", "signature"]);
|
|
494
|
+
requireStrings(event, ["messageId", "partId"], value);
|
|
495
|
+
requireOptionalStrings(event, ["text", "signature"], value);
|
|
496
|
+
break;
|
|
497
|
+
case "reasoning_start":
|
|
498
|
+
requireEventKeys(event, ["messageId", "partId", "reasoningId"]);
|
|
499
|
+
requireStrings(event, ["messageId", "partId"], value);
|
|
500
|
+
requireOptionalStrings(event, ["reasoningId"], value);
|
|
501
|
+
break;
|
|
502
|
+
case "reasoning_end":
|
|
503
|
+
requireEventKeys(event, ["messageId", "partId", "text", "content"]);
|
|
504
|
+
requireStrings(event, ["messageId", "partId"], value);
|
|
505
|
+
requireOptionalStrings(event, ["text"], value);
|
|
506
|
+
if (event.content !== void 0 && (!Array.isArray(event.content) || !event.content.every(isReasoningContent))) {
|
|
507
|
+
invalid("reasoning_end.content", value);
|
|
508
|
+
}
|
|
509
|
+
break;
|
|
510
|
+
case "tool_call_start":
|
|
511
|
+
requireEventKeys(event, ["messageId", "partId", "toolCallId", "callId", "toolName"]);
|
|
512
|
+
requireStrings(event, ["messageId", "partId", "toolCallId"], value);
|
|
513
|
+
requireOptionalStrings(event, ["callId", "toolName"], value);
|
|
514
|
+
break;
|
|
515
|
+
case "tool_call_delta":
|
|
516
|
+
requireEventKeys(event, [
|
|
517
|
+
"messageId",
|
|
518
|
+
"partId",
|
|
519
|
+
"toolCallId",
|
|
520
|
+
"callId",
|
|
521
|
+
"toolName",
|
|
522
|
+
"delta",
|
|
523
|
+
"mode",
|
|
524
|
+
"signature"
|
|
525
|
+
]);
|
|
526
|
+
requireStrings(event, ["messageId", "partId", "toolCallId", "delta"], value);
|
|
527
|
+
requireOptionalStrings(event, ["callId", "toolName"], value);
|
|
528
|
+
requireOptionalStrings(event, ["signature"], value);
|
|
529
|
+
requireOneOf(event.mode, ["append", "replace"], "tool_call_delta.mode", value);
|
|
530
|
+
break;
|
|
531
|
+
case "tool_call_end":
|
|
532
|
+
requireEventKeys(event, [
|
|
533
|
+
"messageId",
|
|
534
|
+
"partId",
|
|
535
|
+
"toolCallId",
|
|
536
|
+
"callId",
|
|
537
|
+
"toolName",
|
|
538
|
+
"input",
|
|
539
|
+
"signature"
|
|
540
|
+
]);
|
|
541
|
+
requireStrings(event, ["messageId", "partId", "toolCallId", "toolName"], value);
|
|
542
|
+
requireOptionalStrings(event, ["callId", "signature"], value);
|
|
543
|
+
if (!isJsonValue2(event.input)) invalid("tool_call_end.input", value);
|
|
544
|
+
break;
|
|
545
|
+
case "tool_result":
|
|
546
|
+
requireEventKeys(event, [
|
|
547
|
+
"messageId",
|
|
548
|
+
"partId",
|
|
549
|
+
"toolCallId",
|
|
550
|
+
"callId",
|
|
551
|
+
"internalCallId",
|
|
552
|
+
"toolName",
|
|
553
|
+
"input",
|
|
554
|
+
"result"
|
|
555
|
+
]);
|
|
556
|
+
requireStrings(event, ["messageId", "partId", "toolCallId", "toolName"], value);
|
|
557
|
+
requireOptionalStrings(event, ["callId", "internalCallId"], value);
|
|
558
|
+
if (!isRecord(event.result)) invalid("tool_result.result", value);
|
|
559
|
+
if (event.result.status === "success") {
|
|
560
|
+
if (!hasOnlyKeys(event.result, ["status", "output", "content"]) || !isJsonValue2(event.result.output) || event.result.content !== void 0 && (!Array.isArray(event.result.content) || !event.result.content.every(isToolResultContent))) {
|
|
561
|
+
invalid("tool_result.result", value);
|
|
562
|
+
}
|
|
563
|
+
} else if (event.result.status === "error") {
|
|
564
|
+
if (!hasOnlyKeys(event.result, ["status", "error"]) || !isClientStreamError(event.result.error)) {
|
|
565
|
+
invalid("tool_result.result", value);
|
|
566
|
+
}
|
|
567
|
+
} else {
|
|
568
|
+
invalid("tool_result.result.status", value);
|
|
569
|
+
}
|
|
570
|
+
break;
|
|
571
|
+
case "source":
|
|
572
|
+
requireEventKeys(event, ["messageId", "partId", "source"]);
|
|
573
|
+
requireStrings(event, ["messageId", "partId"], value);
|
|
574
|
+
if (!isCompletionSource(event.source)) invalid("source.source", value);
|
|
575
|
+
break;
|
|
576
|
+
case "attachment":
|
|
577
|
+
requireEventKeys(event, ["messageId", "partId", "attachment"]);
|
|
578
|
+
requireStrings(event, ["messageId", "partId"], value);
|
|
579
|
+
if (!isAttachment(event.attachment)) invalid("attachment.attachment", value);
|
|
580
|
+
break;
|
|
581
|
+
case "provider_tool_call":
|
|
582
|
+
requireEventKeys(event, ["toolCall"]);
|
|
583
|
+
if (!isProviderToolCall(event.toolCall)) invalid("provider_tool_call.toolCall", value);
|
|
584
|
+
break;
|
|
585
|
+
case "tool_approval":
|
|
586
|
+
requireEventKeys(event, ["approval"]);
|
|
587
|
+
if (!isToolApproval(event.approval)) invalid("tool_approval.approval", value);
|
|
588
|
+
break;
|
|
589
|
+
case "tool_question":
|
|
590
|
+
requireEventKeys(event, ["question"]);
|
|
591
|
+
if (!isToolQuestion(event.question)) invalid("tool_question.question", value);
|
|
592
|
+
break;
|
|
593
|
+
case "guardrail_decision":
|
|
594
|
+
requireEventKeys(event, ["decision"]);
|
|
595
|
+
if (!isGuardrailDecision(event.decision)) invalid("guardrail_decision.decision", value);
|
|
596
|
+
break;
|
|
597
|
+
case "data":
|
|
598
|
+
requireEventKeys(event, ["name", "data", "transient"]);
|
|
599
|
+
requireStrings(event, ["name"], value);
|
|
600
|
+
if (!isJsonValue2(event.data)) invalid("data.data", value);
|
|
601
|
+
if (event.transient !== void 0 && typeof event.transient !== "boolean") {
|
|
602
|
+
invalid("data.transient", value);
|
|
603
|
+
}
|
|
604
|
+
return {
|
|
605
|
+
...event,
|
|
606
|
+
data: parseDataEvent(event.name, event.data, options.dataSchemas, value)
|
|
607
|
+
};
|
|
608
|
+
case "message_end":
|
|
609
|
+
requireEventKeys(event, [
|
|
610
|
+
"messageId",
|
|
611
|
+
"modelMessageId",
|
|
612
|
+
"parts",
|
|
613
|
+
"usage",
|
|
614
|
+
"contextUsage",
|
|
615
|
+
"metadata"
|
|
616
|
+
]);
|
|
617
|
+
requireStrings(event, ["messageId"], value);
|
|
618
|
+
requireOptionalStrings(event, ["modelMessageId"], value);
|
|
619
|
+
if (event.parts !== void 0) {
|
|
620
|
+
if (!Array.isArray(event.parts)) invalid("message_end.parts", value);
|
|
621
|
+
const parts = event.parts.map(
|
|
622
|
+
(part) => parseUIMessagePart(part, options.dataSchemas, value)
|
|
623
|
+
);
|
|
624
|
+
validateUsageAndContext(event, value);
|
|
625
|
+
return parseEventMetadata(
|
|
626
|
+
{ ...event, parts },
|
|
627
|
+
options.metadataSchema,
|
|
628
|
+
value
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
validateUsageAndContext(event, value);
|
|
632
|
+
break;
|
|
633
|
+
case "turn_end":
|
|
634
|
+
requireEventKeys(event, ["usage", "contextUsage", "firstDeltaMs"]);
|
|
635
|
+
if (!isPositiveEventId(event.turn)) invalid("turn_end.turn", value);
|
|
636
|
+
if (event.firstDeltaMs !== void 0 && !isNonnegativeNumber(event.firstDeltaMs)) {
|
|
637
|
+
invalid("turn_end.firstDeltaMs", value);
|
|
638
|
+
}
|
|
639
|
+
validateUsageAndContext(event, value);
|
|
640
|
+
break;
|
|
641
|
+
case "memory_compaction":
|
|
642
|
+
requireEventKeys(event, [
|
|
643
|
+
"originalMessageCount",
|
|
644
|
+
"compactedMessageCount",
|
|
645
|
+
"retainedMessageCount",
|
|
646
|
+
"attempts",
|
|
647
|
+
"usage"
|
|
648
|
+
]);
|
|
649
|
+
validateMemoryCompactionInfo(event, value);
|
|
650
|
+
break;
|
|
651
|
+
case "run_end":
|
|
652
|
+
requireEventKeys(event, [
|
|
653
|
+
"status",
|
|
654
|
+
"text",
|
|
655
|
+
"output",
|
|
656
|
+
"usage",
|
|
657
|
+
"contextUsage",
|
|
658
|
+
"trace",
|
|
659
|
+
"memoryCompaction",
|
|
660
|
+
"metadata"
|
|
661
|
+
]);
|
|
662
|
+
requireOneOf(
|
|
663
|
+
event.status,
|
|
664
|
+
["completed", "blocked", "approval_required", "cancelled", "error"],
|
|
665
|
+
"run_end.status",
|
|
666
|
+
value
|
|
667
|
+
);
|
|
668
|
+
requireOptionalStrings(event, ["text"], value);
|
|
669
|
+
validateUsageAndContext(event, value);
|
|
670
|
+
if (event.trace !== void 0 && !isTrace(event.trace)) invalid("run_end.trace", value);
|
|
671
|
+
if (event.memoryCompaction !== void 0) {
|
|
672
|
+
if (!isRecord(event.memoryCompaction)) invalid("run_end.memoryCompaction", value);
|
|
673
|
+
requireOnlyKeys(
|
|
674
|
+
event.memoryCompaction,
|
|
675
|
+
[
|
|
676
|
+
"originalMessageCount",
|
|
677
|
+
"compactedMessageCount",
|
|
678
|
+
"retainedMessageCount",
|
|
679
|
+
"attempts",
|
|
680
|
+
"usage"
|
|
681
|
+
],
|
|
682
|
+
"run_end.memoryCompaction"
|
|
683
|
+
);
|
|
684
|
+
validateMemoryCompactionInfo(event.memoryCompaction, value);
|
|
685
|
+
}
|
|
686
|
+
break;
|
|
687
|
+
case "error":
|
|
688
|
+
requireEventKeys(event, ["error", "usage"]);
|
|
689
|
+
if (!isClientStreamError(event.error)) invalid("error.error", value);
|
|
690
|
+
if (event.usage !== void 0 && !isUsage(event.usage)) invalid("error.usage", value);
|
|
691
|
+
break;
|
|
692
|
+
default:
|
|
693
|
+
throw new ClientProtocolError(`Unknown client stream event type "${event.type}".`, value);
|
|
694
|
+
}
|
|
695
|
+
return parseEventMetadata(event, options.metadataSchema, value);
|
|
696
|
+
}
|
|
697
|
+
function parseClientStreamFrame(value, options = {}) {
|
|
698
|
+
const frame = requireRecord(value, "Client stream frame");
|
|
699
|
+
if (!isJsonValue2(frame)) {
|
|
700
|
+
throw new ClientProtocolError("Client stream frames must be strict JSON values.", value);
|
|
701
|
+
}
|
|
702
|
+
if (typeof frame.type !== "string") {
|
|
703
|
+
throw new ClientProtocolError("Client stream frames require type.", value);
|
|
704
|
+
}
|
|
705
|
+
if (frame.type === "stream_start") {
|
|
706
|
+
requireOnlyKeys(
|
|
707
|
+
frame,
|
|
708
|
+
["type", "protocol", "streamId", "eventId", "resumable"],
|
|
709
|
+
"stream_start frame"
|
|
710
|
+
);
|
|
711
|
+
if (frame.protocol === "anvia.client.v1") {
|
|
712
|
+
throw new ClientProtocolError("Client stream protocol v1 is not supported.", value);
|
|
713
|
+
}
|
|
714
|
+
if (frame.protocol !== CLIENT_STREAM_PROTOCOL || typeof frame.streamId !== "string" || frame.eventId !== 0 || typeof frame.resumable !== "boolean") {
|
|
715
|
+
throw new ClientProtocolError("Invalid client stream_start frame.", value);
|
|
716
|
+
}
|
|
717
|
+
return frame;
|
|
718
|
+
}
|
|
719
|
+
if (frame.type === "stream_event") {
|
|
720
|
+
requireOnlyKeys(frame, ["type", "streamId", "eventId", "event"], "stream_event frame");
|
|
721
|
+
if (typeof frame.streamId !== "string" || !isPositiveEventId(frame.eventId)) {
|
|
722
|
+
throw new ClientProtocolError("Invalid client stream_event frame.", value);
|
|
723
|
+
}
|
|
724
|
+
const event = parseClientStreamEvent(frame.event, options);
|
|
725
|
+
return { ...frame, event };
|
|
726
|
+
}
|
|
727
|
+
if (frame.type === "stream_end") {
|
|
728
|
+
requireOnlyKeys(frame, ["type", "streamId", "eventId", "status"], "stream_end frame");
|
|
729
|
+
if (typeof frame.streamId !== "string" || !isEventId(frame.eventId)) {
|
|
730
|
+
throw new ClientProtocolError("Invalid client stream_end frame.", value);
|
|
731
|
+
}
|
|
732
|
+
requireOneOf(frame.status, ["completed", "error", "missing"], "stream_end.status", value);
|
|
733
|
+
return frame;
|
|
734
|
+
}
|
|
735
|
+
throw new ClientProtocolError(`Unknown client stream frame type "${frame.type}".`, value);
|
|
736
|
+
}
|
|
737
|
+
function maskedClientError() {
|
|
738
|
+
return { message: "An unexpected error occurred." };
|
|
739
|
+
}
|
|
740
|
+
function normalizeClientError(value) {
|
|
741
|
+
if (value instanceof Error) return value;
|
|
742
|
+
if (isClientStreamError(value)) {
|
|
743
|
+
const error = new Error(value.message);
|
|
744
|
+
if (value.name !== void 0) error.name = value.name;
|
|
745
|
+
return error;
|
|
746
|
+
}
|
|
747
|
+
return new Error(typeof value === "string" ? value : "An unexpected error occurred.");
|
|
748
|
+
}
|
|
749
|
+
function parseDataEvent(name, data, schemas, value) {
|
|
750
|
+
if (schemas === void 0) return data;
|
|
751
|
+
const schema = schemas[name];
|
|
752
|
+
if (schema === void 0) {
|
|
753
|
+
throw new ClientProtocolError(`Invalid data event "${name}".`, value);
|
|
754
|
+
}
|
|
755
|
+
const parsed = schema.safeParse(data);
|
|
756
|
+
if (parsed.success !== true || !isJsonValue2(parsed.data)) {
|
|
757
|
+
throw new ClientProtocolError(`Invalid data event "${name}".`, value);
|
|
758
|
+
}
|
|
759
|
+
return parsed.data;
|
|
760
|
+
}
|
|
761
|
+
function parseUIMessagePart(value, schemas, root) {
|
|
762
|
+
if (!isUIMessagePart(value)) {
|
|
763
|
+
throw new ClientProtocolError("UI message contains an invalid part.", root);
|
|
764
|
+
}
|
|
765
|
+
if (value.type !== "data") {
|
|
766
|
+
return value;
|
|
767
|
+
}
|
|
768
|
+
return {
|
|
769
|
+
...value,
|
|
770
|
+
data: parseDataEvent(value.name, value.data, schemas, root)
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
function parseMetadata(value, schema, root) {
|
|
774
|
+
if (schema === void 0) {
|
|
775
|
+
if (!isJsonObject(value)) {
|
|
776
|
+
throw new ClientProtocolError("Client metadata must be a JSON object.", root);
|
|
777
|
+
}
|
|
778
|
+
return value;
|
|
779
|
+
}
|
|
780
|
+
const parsed = schema.safeParse(value);
|
|
781
|
+
if (parsed.success !== true || !isJsonObject(parsed.data)) {
|
|
782
|
+
throw new ClientProtocolError("Invalid client metadata.", root);
|
|
783
|
+
}
|
|
784
|
+
return parsed.data;
|
|
785
|
+
}
|
|
786
|
+
function parseEventMetadata(event, schema, root) {
|
|
787
|
+
if (event.metadata === void 0) return event;
|
|
788
|
+
return { ...event, metadata: parseMetadata(event.metadata, schema, root) };
|
|
789
|
+
}
|
|
790
|
+
function isUIMessageGeneration(value) {
|
|
791
|
+
if (!isRecord(value)) return false;
|
|
792
|
+
if (!hasOnlyKeys(value, ["runId", "status", "usage", "contextUsage", "trace", "memoryCompaction"])) {
|
|
793
|
+
return false;
|
|
794
|
+
}
|
|
795
|
+
return (value.runId === void 0 || typeof value.runId === "string") && (value.status === void 0 || ["completed", "blocked", "approval_required", "cancelled", "error"].includes(
|
|
796
|
+
value.status
|
|
797
|
+
)) && (value.usage === void 0 || isUsage(value.usage)) && (value.contextUsage === void 0 || isContextUsage(value.contextUsage)) && (value.trace === void 0 || isTrace(value.trace)) && (value.memoryCompaction === void 0 || isRecord(value.memoryCompaction) && validateMemoryCompactionForGuard(value.memoryCompaction));
|
|
798
|
+
}
|
|
799
|
+
function validateMemoryCompactionForGuard(value) {
|
|
800
|
+
try {
|
|
801
|
+
requireOnlyKeys(
|
|
802
|
+
value,
|
|
803
|
+
[
|
|
804
|
+
"originalMessageCount",
|
|
805
|
+
"compactedMessageCount",
|
|
806
|
+
"retainedMessageCount",
|
|
807
|
+
"attempts",
|
|
808
|
+
"usage"
|
|
809
|
+
],
|
|
810
|
+
"memory compaction"
|
|
811
|
+
);
|
|
812
|
+
validateMemoryCompactionInfo(value, value);
|
|
813
|
+
return true;
|
|
814
|
+
} catch {
|
|
815
|
+
return false;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
function isJsonObject(value) {
|
|
819
|
+
return isRecord(value) && isJsonValue2(value);
|
|
820
|
+
}
|
|
821
|
+
function isClientStreamError(value) {
|
|
822
|
+
return isRecord(value) && hasOnlyKeys(value, ["name", "message", "code", "retryable", "details"]) && typeof value.message === "string" && (value.name === void 0 || typeof value.name === "string") && (value.code === void 0 || typeof value.code === "string") && (value.retryable === void 0 || typeof value.retryable === "boolean") && (value.details === void 0 || isJsonValue2(value.details));
|
|
823
|
+
}
|
|
824
|
+
function isScope(value) {
|
|
825
|
+
if (!isRecord(value)) return false;
|
|
826
|
+
const keys = [
|
|
827
|
+
"agentId",
|
|
828
|
+
"agentName",
|
|
829
|
+
"parentRunId",
|
|
830
|
+
"parentToolName",
|
|
831
|
+
"parentToolCallId",
|
|
832
|
+
"parentInternalToolCallId"
|
|
833
|
+
];
|
|
834
|
+
return hasOnlyKeys(value, keys) && keys.every((key) => value[key] === void 0 || typeof value[key] === "string");
|
|
835
|
+
}
|
|
836
|
+
function isAttachment(value) {
|
|
837
|
+
if (!isRecord(value) || typeof value.id !== "string") return false;
|
|
838
|
+
if (value.type !== "image" && value.type !== "document" && value.type !== "file") return false;
|
|
839
|
+
return hasOnlyKeys(value, [
|
|
840
|
+
"id",
|
|
841
|
+
"type",
|
|
842
|
+
"name",
|
|
843
|
+
"mediaType",
|
|
844
|
+
"url",
|
|
845
|
+
"data",
|
|
846
|
+
"text",
|
|
847
|
+
"detail",
|
|
848
|
+
"metadata"
|
|
849
|
+
]) && (value.name === void 0 || typeof value.name === "string") && (value.mediaType === void 0 || typeof value.mediaType === "string") && (value.url === void 0 || typeof value.url === "string") && (value.data === void 0 || typeof value.data === "string") && (value.text === void 0 || typeof value.text === "string") && (value.detail === void 0 || ["auto", "low", "high"].includes(value.detail)) && (value.metadata === void 0 || isJsonValue2(value.metadata));
|
|
850
|
+
}
|
|
851
|
+
function isUIMessagePart(value) {
|
|
852
|
+
if (!isRecord(value) || typeof value.id !== "string" || typeof value.type !== "string") {
|
|
853
|
+
return false;
|
|
854
|
+
}
|
|
855
|
+
if (value.type === "text") {
|
|
856
|
+
return hasOnlyKeys(value, ["id", "type", "text", "signature"]) && typeof value.text === "string" && (value.signature === void 0 || typeof value.signature === "string");
|
|
857
|
+
}
|
|
858
|
+
if (value.type === "reasoning") {
|
|
859
|
+
return hasOnlyKeys(value, ["id", "type", "text", "reasoningId", "content"]) && typeof value.text === "string" && (value.reasoningId === void 0 || typeof value.reasoningId === "string") && (value.content === void 0 || Array.isArray(value.content) && value.content.every(isReasoningContent));
|
|
860
|
+
}
|
|
861
|
+
if (value.type === "source") {
|
|
862
|
+
return hasOnlyKeys(value, ["id", "type", "source"]) && isCompletionSource(value.source);
|
|
863
|
+
}
|
|
864
|
+
if (value.type === "data") {
|
|
865
|
+
return hasOnlyKeys(value, ["id", "type", "name", "data"]) && typeof value.name === "string" && isJsonValue2(value.data);
|
|
866
|
+
}
|
|
867
|
+
if (value.type === "attachment") {
|
|
868
|
+
return hasOnlyKeys(value, ["id", "type", "attachment"]) && isAttachment(value.attachment);
|
|
869
|
+
}
|
|
870
|
+
if (value.type === "error") {
|
|
871
|
+
return hasOnlyKeys(value, ["id", "type", "error"]) && isClientStreamError(value.error);
|
|
872
|
+
}
|
|
873
|
+
return value.type === "tool" && hasOnlyKeys(value, [
|
|
874
|
+
"id",
|
|
875
|
+
"type",
|
|
876
|
+
"toolName",
|
|
877
|
+
"toolCallId",
|
|
878
|
+
"callId",
|
|
879
|
+
"internalCallId",
|
|
880
|
+
"turn",
|
|
881
|
+
"state",
|
|
882
|
+
"input",
|
|
883
|
+
"output",
|
|
884
|
+
"resultContent",
|
|
885
|
+
"signature",
|
|
886
|
+
"error"
|
|
887
|
+
]) && typeof value.toolName === "string" && typeof value.toolCallId === "string" && (value.callId === void 0 || typeof value.callId === "string") && (value.internalCallId === void 0 || typeof value.internalCallId === "string") && (value.turn === void 0 || isPositiveEventId(value.turn)) && (value.signature === void 0 || typeof value.signature === "string") && (value.input === void 0 || isJsonValue2(value.input)) && (value.output === void 0 || isJsonValue2(value.output)) && (value.resultContent === void 0 || Array.isArray(value.resultContent) && value.resultContent.every(isToolResultContent)) && (value.error === void 0 || isClientStreamError(value.error)) && ["input-streaming", "input-available", "output-available", "error"].includes(
|
|
888
|
+
value.state
|
|
889
|
+
);
|
|
890
|
+
}
|
|
891
|
+
function isReasoningContent(value) {
|
|
892
|
+
if (!isRecord(value) || typeof value.type !== "string") return false;
|
|
893
|
+
if (value.type === "text") {
|
|
894
|
+
return hasOnlyKeys(value, ["type", "text", "signature"]) && typeof value.text === "string" && (value.signature === void 0 || typeof value.signature === "string");
|
|
895
|
+
}
|
|
896
|
+
if (value.type === "summary") {
|
|
897
|
+
return hasOnlyKeys(value, ["type", "text"]) && typeof value.text === "string";
|
|
898
|
+
}
|
|
899
|
+
if (value.type === "encrypted" || value.type === "redacted") {
|
|
900
|
+
return hasOnlyKeys(value, ["type", "data"]) && typeof value.data === "string";
|
|
901
|
+
}
|
|
902
|
+
return false;
|
|
903
|
+
}
|
|
904
|
+
function isToolResultContent(value) {
|
|
905
|
+
if (!isRecord(value)) return false;
|
|
906
|
+
if (value.type === "text") {
|
|
907
|
+
return hasOnlyKeys(value, ["type", "text", "signature"]) && typeof value.text === "string" && (value.signature === void 0 || typeof value.signature === "string");
|
|
908
|
+
}
|
|
909
|
+
return value.type === "file" && hasOnlyKeys(value, ["type", "data", "mediaType", "filename"]) && isFileData(value.data) && typeof value.mediaType === "string" && (value.filename === void 0 || typeof value.filename === "string");
|
|
910
|
+
}
|
|
911
|
+
function isFileData(value) {
|
|
912
|
+
if (!isRecord(value)) return false;
|
|
913
|
+
if (value.type === "url") {
|
|
914
|
+
return hasOnlyKeys(value, ["type", "url"]) && typeof value.url === "string";
|
|
915
|
+
}
|
|
916
|
+
if (value.type === "data") {
|
|
917
|
+
return hasOnlyKeys(value, ["type", "data"]) && typeof value.data === "string";
|
|
918
|
+
}
|
|
919
|
+
return value.type === "text" && hasOnlyKeys(value, ["type", "text"]) && typeof value.text === "string";
|
|
920
|
+
}
|
|
921
|
+
function isCompletionSource(value) {
|
|
922
|
+
return isRecord(value) && value.type === "url" && hasOnlyKeys(value, ["type", "url", "title", "id", "startIndex", "endIndex"]) && typeof value.url === "string" && (value.title === void 0 || typeof value.title === "string") && (value.id === void 0 || typeof value.id === "string") && (value.startIndex === void 0 || isNonnegativeNumber(value.startIndex)) && (value.endIndex === void 0 || isNonnegativeNumber(value.endIndex));
|
|
923
|
+
}
|
|
924
|
+
function isProviderToolCall(value) {
|
|
925
|
+
return isRecord(value) && hasOnlyKeys(value, ["id", "name", "status", "details"]) && typeof value.id === "string" && typeof value.name === "string" && (value.status === void 0 || typeof value.status === "string") && (value.details === void 0 || isRecord(value.details) && isJsonValue2(value.details));
|
|
926
|
+
}
|
|
927
|
+
function isToolApproval(value) {
|
|
928
|
+
if (!isRecord(value)) return false;
|
|
929
|
+
const optionalStrings = [
|
|
930
|
+
"runId",
|
|
931
|
+
"agentId",
|
|
932
|
+
"sessionId",
|
|
933
|
+
"callId",
|
|
934
|
+
"internalCallId",
|
|
935
|
+
"requestedAt",
|
|
936
|
+
"resolvedAt",
|
|
937
|
+
"reason"
|
|
938
|
+
];
|
|
939
|
+
return hasOnlyKeys(value, ["id", "toolName", "input", "status", ...optionalStrings]) && typeof value.id === "string" && typeof value.toolName === "string" && optionalStrings.every((key) => value[key] === void 0 || typeof value[key] === "string") && (value.input === void 0 || isJsonValue2(value.input)) && typeof value.status === "string" && ["pending", "approved", "rejected", "timed_out", "cancelled"].includes(value.status);
|
|
940
|
+
}
|
|
941
|
+
function isToolQuestion(value) {
|
|
942
|
+
if (!isRecord(value)) return false;
|
|
943
|
+
const optionalStrings = [
|
|
944
|
+
"runId",
|
|
945
|
+
"agentId",
|
|
946
|
+
"sessionId",
|
|
947
|
+
"callId",
|
|
948
|
+
"internalCallId",
|
|
949
|
+
"requestedAt",
|
|
950
|
+
"answeredAt",
|
|
951
|
+
"cancelledAt"
|
|
952
|
+
];
|
|
953
|
+
return hasOnlyKeys(value, [
|
|
954
|
+
"id",
|
|
955
|
+
"toolName",
|
|
956
|
+
"input",
|
|
957
|
+
"questions",
|
|
958
|
+
"status",
|
|
959
|
+
"answers",
|
|
960
|
+
...optionalStrings
|
|
961
|
+
]) && typeof value.id === "string" && typeof value.toolName === "string" && optionalStrings.every((key) => value[key] === void 0 || typeof value[key] === "string") && (value.input === void 0 || isJsonValue2(value.input)) && Array.isArray(value.questions) && value.questions.every(isToolQuestionPrompt) && typeof value.status === "string" && ["pending", "answered", "cancelled"].includes(value.status) && (value.answers === void 0 || Array.isArray(value.answers) && value.answers.every(isToolQuestionAnswer));
|
|
962
|
+
}
|
|
963
|
+
function isToolQuestionPrompt(value) {
|
|
964
|
+
return isRecord(value) && hasOnlyKeys(value, ["id", "question", "choices"]) && typeof value.id === "string" && typeof value.question === "string" && Array.isArray(value.choices) && value.choices.every(
|
|
965
|
+
(choice) => isRecord(choice) && hasOnlyKeys(choice, ["label", "value"]) && typeof choice.label === "string" && typeof choice.value === "string"
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
function isToolQuestionAnswer(value) {
|
|
969
|
+
return isRecord(value) && hasOnlyKeys(value, ["questionId", "answer", "choice", "custom"]) && typeof value.questionId === "string" && typeof value.answer === "string" && (value.choice === void 0 || typeof value.choice === "string") && (value.custom === void 0 || typeof value.custom === "boolean");
|
|
970
|
+
}
|
|
971
|
+
function isGuardrailDecision(value) {
|
|
972
|
+
return isRecord(value) && hasOnlyKeys(value, [
|
|
973
|
+
"policyId",
|
|
974
|
+
"guardrailId",
|
|
975
|
+
"boundary",
|
|
976
|
+
"mode",
|
|
977
|
+
"action",
|
|
978
|
+
"applied",
|
|
979
|
+
"reason",
|
|
980
|
+
"message",
|
|
981
|
+
"metadata",
|
|
982
|
+
"latencyMs"
|
|
983
|
+
]) && typeof value.policyId === "string" && typeof value.guardrailId === "string" && (value.boundary === "input" || value.boundary === "output") && (value.mode === "enforce" || value.mode === "observe") && typeof value.action === "string" && ["allow", "block", "rewrite", "error"].includes(value.action) && typeof value.applied === "boolean" && (value.reason === void 0 || typeof value.reason === "string") && (value.message === void 0 || typeof value.message === "string") && (value.metadata === void 0 || isRecord(value.metadata) && isJsonValue2(value.metadata)) && isNonnegativeNumber(value.latencyMs);
|
|
984
|
+
}
|
|
985
|
+
function isUsage(value) {
|
|
986
|
+
if (!isRecord(value) || !hasOnlyKeys(value, [
|
|
987
|
+
"inputTokens",
|
|
988
|
+
"outputTokens",
|
|
989
|
+
"totalTokens",
|
|
990
|
+
"cachedInputTokens",
|
|
991
|
+
"cacheCreationInputTokens",
|
|
992
|
+
"details"
|
|
993
|
+
]) || ![
|
|
994
|
+
value.inputTokens,
|
|
995
|
+
value.outputTokens,
|
|
996
|
+
value.totalTokens,
|
|
997
|
+
value.cachedInputTokens,
|
|
998
|
+
value.cacheCreationInputTokens
|
|
999
|
+
].every(isNonnegativeNumber)) {
|
|
1000
|
+
return false;
|
|
1001
|
+
}
|
|
1002
|
+
return value.details === void 0 || isRecord(value.details) && Object.values(value.details).every(isNonnegativeNumber);
|
|
1003
|
+
}
|
|
1004
|
+
function isContextUsage(value) {
|
|
1005
|
+
if (!isRecord(value) || !isRecord(value.model) || !isRecord(value.model.context)) return false;
|
|
1006
|
+
const context = value.model.context;
|
|
1007
|
+
return hasOnlyKeys(value, [
|
|
1008
|
+
"model",
|
|
1009
|
+
"usedTokens",
|
|
1010
|
+
"remainingTokens",
|
|
1011
|
+
"usedPercent",
|
|
1012
|
+
"remainingPercent"
|
|
1013
|
+
]) && hasOnlyKeys(value.model, ["modelId", "context"]) && typeof value.model.modelId === "string" && hasOnlyKeys(context, ["contextWindow", "maxInputTokens", "maxOutputTokens"]) && isNonnegativeNumber(context.contextWindow) && (context.maxInputTokens === void 0 || isNonnegativeNumber(context.maxInputTokens)) && (context.maxOutputTokens === void 0 || isNonnegativeNumber(context.maxOutputTokens)) && isNonnegativeNumber(value.usedTokens) && isNonnegativeNumber(value.remainingTokens) && isNonnegativeNumber(value.usedPercent) && isNonnegativeNumber(value.remainingPercent);
|
|
1014
|
+
}
|
|
1015
|
+
function validateUsageAndContext(event, original) {
|
|
1016
|
+
if (event.usage !== void 0 && !isUsage(event.usage)) {
|
|
1017
|
+
invalid(`${String(event.type)}.usage`, original);
|
|
1018
|
+
}
|
|
1019
|
+
if (event.contextUsage !== void 0 && !isContextUsage(event.contextUsage)) {
|
|
1020
|
+
invalid(`${String(event.type)}.contextUsage`, original);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
function validateMemoryCompactionInfo(value, original) {
|
|
1024
|
+
for (const field of ["originalMessageCount", "compactedMessageCount", "retainedMessageCount"]) {
|
|
1025
|
+
if (!isEventId(value[field])) invalid(`memory_compaction.${field}`, original);
|
|
1026
|
+
}
|
|
1027
|
+
if (!isPositiveEventId(value.attempts)) invalid("memory_compaction.attempts", original);
|
|
1028
|
+
if (!isUsage(value.usage)) invalid("memory_compaction.usage", original);
|
|
1029
|
+
}
|
|
1030
|
+
function isTrace(value) {
|
|
1031
|
+
return isRecord(value) && hasOnlyKeys(value, ["observer", "traceId", "observationId"]) && typeof value.observer === "string" && value.observer.trim().length > 0 && (value.traceId === void 0 || typeof value.traceId === "string") && (value.observationId === void 0 || typeof value.observationId === "string");
|
|
1032
|
+
}
|
|
1033
|
+
function requireRecord(value, label) {
|
|
1034
|
+
if (!isRecord(value)) throw new ClientProtocolError(`${label} must be an object.`, value);
|
|
1035
|
+
return value;
|
|
1036
|
+
}
|
|
1037
|
+
function requireOnlyKeys(value, keys, label) {
|
|
1038
|
+
for (const key of Object.keys(value)) {
|
|
1039
|
+
if (!keys.includes(key)) throw new ClientProtocolError(`${label} has unknown field "${key}".`);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
function requireEventKeys(value, keys) {
|
|
1043
|
+
requireOnlyKeys(
|
|
1044
|
+
value,
|
|
1045
|
+
["type", "runId", "turn", "scope", ...keys],
|
|
1046
|
+
`${String(value.type)} event`
|
|
1047
|
+
);
|
|
1048
|
+
}
|
|
1049
|
+
function requireStrings(value, keys, original) {
|
|
1050
|
+
for (const key of keys) {
|
|
1051
|
+
if (typeof value[key] !== "string") invalid(`${String(value.type)}.${key}`, original);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
function requireOptionalStrings(value, keys, original) {
|
|
1055
|
+
for (const key of keys) {
|
|
1056
|
+
if (value[key] !== void 0 && typeof value[key] !== "string") {
|
|
1057
|
+
invalid(`${String(value.type)}.${key}`, original);
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
function requireOneOf(value, allowed, label, original) {
|
|
1062
|
+
if (typeof value !== "string" || !allowed.includes(value)) invalid(label, original);
|
|
1063
|
+
}
|
|
1064
|
+
function invalid(label, value) {
|
|
1065
|
+
throw new ClientProtocolError(`Invalid ${label}.`, value);
|
|
1066
|
+
}
|
|
1067
|
+
function isEventId(value) {
|
|
1068
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
1069
|
+
}
|
|
1070
|
+
function isPositiveEventId(value) {
|
|
1071
|
+
return isEventId(value) && value > 0;
|
|
1072
|
+
}
|
|
1073
|
+
function isNonnegativeNumber(value) {
|
|
1074
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
1075
|
+
}
|
|
1076
|
+
function hasOnlyKeys(value, keys) {
|
|
1077
|
+
return Object.keys(value).every((key) => keys.includes(key));
|
|
1078
|
+
}
|
|
1079
|
+
function isRecord(value) {
|
|
1080
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// src/adapters.ts
|
|
1084
|
+
function completionToClientStream(options) {
|
|
1085
|
+
const { events } = options;
|
|
1086
|
+
const runId = options.runId ?? createClientId("run");
|
|
1087
|
+
return propagateCancellation(events, (source) => ({
|
|
1088
|
+
async *[Symbol.asyncIterator]() {
|
|
1089
|
+
const state = createMessageState({ runId });
|
|
1090
|
+
yield clientEvent(state, {
|
|
1091
|
+
type: "run_start",
|
|
1092
|
+
source: "completion",
|
|
1093
|
+
...options.metadata === void 0 ? {} : { metadata: options.metadata }
|
|
1094
|
+
});
|
|
1095
|
+
if (options.model !== void 0) {
|
|
1096
|
+
yield clientEvent(state, { type: "generation_start", model: options.model });
|
|
1097
|
+
}
|
|
1098
|
+
yield* startMessage(state);
|
|
1099
|
+
let terminal = false;
|
|
1100
|
+
try {
|
|
1101
|
+
for await (const event of source) {
|
|
1102
|
+
if (terminal) break;
|
|
1103
|
+
switch (event.type) {
|
|
1104
|
+
case "text_delta":
|
|
1105
|
+
yield* appendText(state, event.delta);
|
|
1106
|
+
break;
|
|
1107
|
+
case "reasoning_delta":
|
|
1108
|
+
yield* appendReasoning(state, event);
|
|
1109
|
+
break;
|
|
1110
|
+
case "tool_call_delta":
|
|
1111
|
+
yield* appendToolCall(state, event);
|
|
1112
|
+
break;
|
|
1113
|
+
case "tool_call":
|
|
1114
|
+
yield* finishToolCall(state, event.toolCall);
|
|
1115
|
+
break;
|
|
1116
|
+
case "source":
|
|
1117
|
+
yield* emitSource(state, event.source);
|
|
1118
|
+
break;
|
|
1119
|
+
case "provider_tool_call":
|
|
1120
|
+
yield* emitProviderToolCall(state, event.toolCall);
|
|
1121
|
+
break;
|
|
1122
|
+
case "message_id":
|
|
1123
|
+
state.modelMessageId = event.id;
|
|
1124
|
+
break;
|
|
1125
|
+
case "final": {
|
|
1126
|
+
const result = event.result;
|
|
1127
|
+
if (result.messageId !== void 0) state.modelMessageId = result.messageId;
|
|
1128
|
+
yield* finishMessage(state, result.content, {
|
|
1129
|
+
usage: result.usage,
|
|
1130
|
+
...result.contextUsage === void 0 ? {} : { contextUsage: result.contextUsage },
|
|
1131
|
+
...result.sources === void 0 ? {} : { sources: result.sources },
|
|
1132
|
+
...result.providerToolCalls === void 0 ? {} : { providerToolCalls: result.providerToolCalls }
|
|
1133
|
+
});
|
|
1134
|
+
const output = clientOutput(result.output, options.mapOutput);
|
|
1135
|
+
yield clientEvent(state, {
|
|
1136
|
+
type: "run_end",
|
|
1137
|
+
status: "completed",
|
|
1138
|
+
text: result.text,
|
|
1139
|
+
...output === void 0 ? {} : { output },
|
|
1140
|
+
usage: result.usage,
|
|
1141
|
+
...result.contextUsage === void 0 ? {} : { contextUsage: result.contextUsage }
|
|
1142
|
+
});
|
|
1143
|
+
terminal = true;
|
|
1144
|
+
break;
|
|
1145
|
+
}
|
|
1146
|
+
case "error":
|
|
1147
|
+
yield* finishErroredRun(state, event.error, event.usage, options.mapError);
|
|
1148
|
+
terminal = true;
|
|
1149
|
+
break;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
if (!terminal) {
|
|
1153
|
+
yield* finishErroredRun(
|
|
1154
|
+
state,
|
|
1155
|
+
new Error("Completion stream ended without a terminal event."),
|
|
1156
|
+
void 0,
|
|
1157
|
+
options.mapError
|
|
1158
|
+
);
|
|
1159
|
+
}
|
|
1160
|
+
} catch (error) {
|
|
1161
|
+
if (!terminal) yield* finishErroredRun(state, error, void 0, options.mapError);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
}));
|
|
1165
|
+
}
|
|
1166
|
+
function agentToClientStream(options) {
|
|
1167
|
+
const { events } = options;
|
|
1168
|
+
const runId = options.runId ?? createClientId("run");
|
|
1169
|
+
return propagateCancellation(events, (source) => ({
|
|
1170
|
+
async *[Symbol.asyncIterator]() {
|
|
1171
|
+
const runtime = {
|
|
1172
|
+
runId,
|
|
1173
|
+
options,
|
|
1174
|
+
messages: /* @__PURE__ */ new Map(),
|
|
1175
|
+
startedScopes: /* @__PURE__ */ new Set(["root"])
|
|
1176
|
+
};
|
|
1177
|
+
yield rootEvent(runId, {
|
|
1178
|
+
type: "run_start",
|
|
1179
|
+
source: "agent",
|
|
1180
|
+
...options.metadata === void 0 ? {} : { metadata: options.metadata }
|
|
1181
|
+
});
|
|
1182
|
+
let terminal = false;
|
|
1183
|
+
try {
|
|
1184
|
+
for await (const event of source) {
|
|
1185
|
+
if (terminal) break;
|
|
1186
|
+
yield* translateAgentEvent(runtime, event, void 0);
|
|
1187
|
+
terminal = isRootTerminalAgentEvent(event);
|
|
1188
|
+
}
|
|
1189
|
+
if (!terminal) {
|
|
1190
|
+
const error = mapClientError(
|
|
1191
|
+
new Error("Agent stream ended without a terminal event."),
|
|
1192
|
+
options.mapError
|
|
1193
|
+
);
|
|
1194
|
+
yield rootEvent(runId, { type: "error", error });
|
|
1195
|
+
yield rootEvent(runId, { type: "run_end", status: "error" });
|
|
1196
|
+
}
|
|
1197
|
+
} catch (error) {
|
|
1198
|
+
if (!terminal) {
|
|
1199
|
+
yield rootEvent(runId, {
|
|
1200
|
+
type: "error",
|
|
1201
|
+
error: mapClientError(error, options.mapError)
|
|
1202
|
+
});
|
|
1203
|
+
yield rootEvent(runId, { type: "run_end", status: "error" });
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
}));
|
|
1208
|
+
}
|
|
1209
|
+
function customAgentEventsToClientStream(options) {
|
|
1210
|
+
return agentToClientStream(
|
|
1211
|
+
options
|
|
1212
|
+
);
|
|
1213
|
+
}
|
|
1214
|
+
async function* translateAgentEvent(runtime, event, scope) {
|
|
1215
|
+
if (event.type === "agent_tool_event") {
|
|
1216
|
+
const childScope = {
|
|
1217
|
+
agentId: event.agentId,
|
|
1218
|
+
...event.agentName === void 0 ? {} : { agentName: event.agentName },
|
|
1219
|
+
parentRunId: runtime.runId,
|
|
1220
|
+
parentToolName: event.toolName,
|
|
1221
|
+
parentToolCallId: event.toolCallId ?? event.internalCallId,
|
|
1222
|
+
parentInternalToolCallId: event.internalCallId
|
|
1223
|
+
};
|
|
1224
|
+
const key = scopeKey(childScope);
|
|
1225
|
+
if (!runtime.startedScopes.has(key)) {
|
|
1226
|
+
runtime.startedScopes.add(key);
|
|
1227
|
+
yield rootEvent(runtime.runId, { type: "run_start", source: "agent" }, childScope);
|
|
1228
|
+
}
|
|
1229
|
+
yield* translateAgentEvent(runtime, event.event, childScope);
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
const turn = "turn" in event && typeof event.turn === "number" ? event.turn : void 0;
|
|
1233
|
+
switch (event.type) {
|
|
1234
|
+
case "memory_compaction":
|
|
1235
|
+
yield scopedEvent(runtime.runId, turn, scope, {
|
|
1236
|
+
type: "memory_compaction",
|
|
1237
|
+
originalMessageCount: event.originalMessageCount,
|
|
1238
|
+
compactedMessageCount: event.compactedMessageCount,
|
|
1239
|
+
retainedMessageCount: event.retainedMessageCount,
|
|
1240
|
+
attempts: event.attempts,
|
|
1241
|
+
usage: event.usage
|
|
1242
|
+
});
|
|
1243
|
+
return;
|
|
1244
|
+
case "turn_start":
|
|
1245
|
+
yield scopedEvent(runtime.runId, turn, scope, { type: "turn_start" });
|
|
1246
|
+
return;
|
|
1247
|
+
case "generation_start": {
|
|
1248
|
+
const state = getAgentMessage(runtime, event.turn, scope);
|
|
1249
|
+
yield scopedEvent(runtime.runId, event.turn, scope, {
|
|
1250
|
+
type: "generation_start",
|
|
1251
|
+
model: {
|
|
1252
|
+
provider: event.modelInfo.provider,
|
|
1253
|
+
modelId: event.modelInfo.modelId
|
|
1254
|
+
}
|
|
1255
|
+
});
|
|
1256
|
+
yield* startMessage(state);
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
case "text_delta": {
|
|
1260
|
+
const state = getAgentMessage(runtime, event.turn, scope);
|
|
1261
|
+
yield* startMessage(state);
|
|
1262
|
+
yield* appendText(state, event.delta);
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
case "reasoning_delta": {
|
|
1266
|
+
const state = getAgentMessage(runtime, event.turn, scope);
|
|
1267
|
+
yield* startMessage(state);
|
|
1268
|
+
yield* appendReasoning(state, event);
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1271
|
+
case "tool_call_delta": {
|
|
1272
|
+
const state = getAgentMessage(runtime, event.turn, scope);
|
|
1273
|
+
yield* startMessage(state);
|
|
1274
|
+
yield* appendToolCall(state, event);
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1277
|
+
case "tool_call": {
|
|
1278
|
+
const state = getAgentMessage(runtime, event.turn, scope);
|
|
1279
|
+
yield* startMessage(state);
|
|
1280
|
+
yield* finishToolCall(state, event.toolCall);
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
case "source": {
|
|
1284
|
+
const state = getAgentMessage(runtime, event.turn, scope);
|
|
1285
|
+
yield* startMessage(state);
|
|
1286
|
+
yield* emitSource(state, event.source);
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
case "provider_tool_call": {
|
|
1290
|
+
const state = getAgentMessage(runtime, event.turn, scope);
|
|
1291
|
+
yield* emitProviderToolCall(state, event.toolCall);
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
case "tool_result": {
|
|
1295
|
+
const state = getAgentMessage(runtime, event.turn, scope);
|
|
1296
|
+
yield* startMessage(state);
|
|
1297
|
+
const tool = getToolResultState(
|
|
1298
|
+
state,
|
|
1299
|
+
event.toolName,
|
|
1300
|
+
event.toolCallId,
|
|
1301
|
+
event.callId,
|
|
1302
|
+
event.internalCallId
|
|
1303
|
+
);
|
|
1304
|
+
tool.result = clientToolResult(event.output, event.result);
|
|
1305
|
+
yield clientEvent(state, {
|
|
1306
|
+
type: "tool_result",
|
|
1307
|
+
messageId: state.messageId,
|
|
1308
|
+
partId: tool.partId,
|
|
1309
|
+
toolCallId: tool.toolCallId,
|
|
1310
|
+
...tool.callId === void 0 ? {} : { callId: tool.callId },
|
|
1311
|
+
internalCallId: event.internalCallId,
|
|
1312
|
+
toolName: event.toolName,
|
|
1313
|
+
input: parseJsonOrString(event.args),
|
|
1314
|
+
result: tool.result
|
|
1315
|
+
});
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
case "turn_end": {
|
|
1319
|
+
const state = getAgentMessage(runtime, event.turn, scope);
|
|
1320
|
+
yield* startMessage(state);
|
|
1321
|
+
if (event.response.messageId !== void 0) state.modelMessageId = event.response.messageId;
|
|
1322
|
+
yield* finishMessage(state, event.response.choice, {
|
|
1323
|
+
usage: event.response.usage,
|
|
1324
|
+
...event.response.contextUsage === void 0 ? {} : { contextUsage: event.response.contextUsage },
|
|
1325
|
+
...event.response.sources === void 0 ? {} : { sources: event.response.sources },
|
|
1326
|
+
...event.response.providerToolCalls === void 0 ? {} : { providerToolCalls: event.response.providerToolCalls }
|
|
1327
|
+
});
|
|
1328
|
+
yield scopedEvent(runtime.runId, event.turn, scope, {
|
|
1329
|
+
type: "turn_end",
|
|
1330
|
+
usage: event.response.usage,
|
|
1331
|
+
...event.response.contextUsage === void 0 ? {} : { contextUsage: event.response.contextUsage },
|
|
1332
|
+
...event.firstDeltaMs === void 0 ? {} : { firstDeltaMs: event.firstDeltaMs }
|
|
1333
|
+
});
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
case "guardrail_decision":
|
|
1337
|
+
yield scopedEvent(runtime.runId, event.turn, scope, {
|
|
1338
|
+
type: "guardrail_decision",
|
|
1339
|
+
decision: event.decision
|
|
1340
|
+
});
|
|
1341
|
+
return;
|
|
1342
|
+
case "approval_required": {
|
|
1343
|
+
const input = jsonValueOrUndefined(event.approval.input);
|
|
1344
|
+
yield scopedEvent(runtime.runId, turn, scope, {
|
|
1345
|
+
type: "tool_approval",
|
|
1346
|
+
approval: {
|
|
1347
|
+
id: event.approval.id,
|
|
1348
|
+
runId: event.runId,
|
|
1349
|
+
toolName: event.approval.toolName,
|
|
1350
|
+
...event.approval.toolCallId === void 0 ? {} : { callId: event.approval.toolCallId },
|
|
1351
|
+
...input === void 0 ? {} : { input },
|
|
1352
|
+
status: "pending",
|
|
1353
|
+
...event.approval.reason === void 0 ? {} : { reason: event.approval.reason }
|
|
1354
|
+
}
|
|
1355
|
+
});
|
|
1356
|
+
yield scopedEvent(runtime.runId, turn, scope, {
|
|
1357
|
+
type: "run_end",
|
|
1358
|
+
status: "approval_required",
|
|
1359
|
+
usage: event.usage,
|
|
1360
|
+
...event.memoryCompaction === void 0 ? {} : { memoryCompaction: event.memoryCompaction },
|
|
1361
|
+
...runtime.options.metadata === void 0 ? {} : { metadata: runtime.options.metadata }
|
|
1362
|
+
});
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
case "final": {
|
|
1366
|
+
const result = event.result;
|
|
1367
|
+
const output = result.status === "completed" ? clientOutput(result.output, runtime.options.mapOutput) : void 0;
|
|
1368
|
+
yield scopedEvent(runtime.runId, turn, scope, {
|
|
1369
|
+
type: "run_end",
|
|
1370
|
+
status: result.status,
|
|
1371
|
+
text: result.text,
|
|
1372
|
+
...output === void 0 ? {} : { output },
|
|
1373
|
+
usage: result.usage,
|
|
1374
|
+
...result.contextUsage === void 0 ? {} : { contextUsage: result.contextUsage },
|
|
1375
|
+
...result.trace === void 0 ? {} : { trace: clientTrace(result.trace) },
|
|
1376
|
+
...result.memoryCompaction === void 0 ? {} : { memoryCompaction: result.memoryCompaction },
|
|
1377
|
+
...runtime.options.metadata === void 0 ? {} : { metadata: runtime.options.metadata }
|
|
1378
|
+
});
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
case "error": {
|
|
1382
|
+
const error = mapClientError(event.error, runtime.options.mapError);
|
|
1383
|
+
yield scopedEvent(runtime.runId, turn, scope, { type: "error", error, usage: event.usage });
|
|
1384
|
+
yield scopedEvent(runtime.runId, turn, scope, {
|
|
1385
|
+
type: "run_end",
|
|
1386
|
+
status: "error",
|
|
1387
|
+
usage: event.usage
|
|
1388
|
+
});
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
default: {
|
|
1392
|
+
const mapped = runtime.options.mapCustomEvent?.(event, {
|
|
1393
|
+
runId: runtime.runId,
|
|
1394
|
+
...turn === void 0 ? {} : { turn },
|
|
1395
|
+
...scope === void 0 ? {} : { scope }
|
|
1396
|
+
});
|
|
1397
|
+
if (mapped === void 0) return;
|
|
1398
|
+
if (Array.isArray(mapped)) {
|
|
1399
|
+
yield* mapped;
|
|
1400
|
+
} else {
|
|
1401
|
+
yield mapped;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
function createMessageState(input) {
|
|
1407
|
+
return {
|
|
1408
|
+
runId: input.runId,
|
|
1409
|
+
messageId: createClientId("msg"),
|
|
1410
|
+
...input.turn === void 0 ? {} : { turn: input.turn },
|
|
1411
|
+
...input.scope === void 0 ? {} : { scope: input.scope },
|
|
1412
|
+
started: false,
|
|
1413
|
+
ended: false,
|
|
1414
|
+
textPartId: createClientId("text"),
|
|
1415
|
+
text: "",
|
|
1416
|
+
textStarted: false,
|
|
1417
|
+
textEnded: false,
|
|
1418
|
+
reasoning: /* @__PURE__ */ new Map(),
|
|
1419
|
+
tools: /* @__PURE__ */ new Map(),
|
|
1420
|
+
sourceFingerprints: /* @__PURE__ */ new Set(),
|
|
1421
|
+
providerToolCallFingerprints: /* @__PURE__ */ new Set()
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1424
|
+
function getAgentMessage(runtime, turn, scope) {
|
|
1425
|
+
const key = `${scopeKey(scope)}:${turn}`;
|
|
1426
|
+
const current = runtime.messages.get(key);
|
|
1427
|
+
if (current !== void 0) return current;
|
|
1428
|
+
const created = createMessageState({
|
|
1429
|
+
runId: runtime.runId,
|
|
1430
|
+
turn,
|
|
1431
|
+
...scope === void 0 ? {} : { scope }
|
|
1432
|
+
});
|
|
1433
|
+
runtime.messages.set(key, created);
|
|
1434
|
+
return created;
|
|
1435
|
+
}
|
|
1436
|
+
async function* startMessage(state) {
|
|
1437
|
+
if (state.started) return;
|
|
1438
|
+
state.started = true;
|
|
1439
|
+
yield clientEvent(state, {
|
|
1440
|
+
type: "message_start",
|
|
1441
|
+
messageId: state.messageId,
|
|
1442
|
+
role: "assistant"
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
async function* appendText(state, delta) {
|
|
1446
|
+
if (!state.textStarted) {
|
|
1447
|
+
state.textStarted = true;
|
|
1448
|
+
yield clientEvent(state, {
|
|
1449
|
+
type: "text_start",
|
|
1450
|
+
messageId: state.messageId,
|
|
1451
|
+
partId: state.textPartId
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
state.text += delta;
|
|
1455
|
+
yield clientEvent(state, {
|
|
1456
|
+
type: "text_delta",
|
|
1457
|
+
messageId: state.messageId,
|
|
1458
|
+
partId: state.textPartId,
|
|
1459
|
+
delta
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
async function* emitSource(state, source) {
|
|
1463
|
+
const fingerprint = valueFingerprint(source);
|
|
1464
|
+
if (state.sourceFingerprints.has(fingerprint)) return;
|
|
1465
|
+
state.sourceFingerprints.add(fingerprint);
|
|
1466
|
+
yield clientEvent(state, {
|
|
1467
|
+
type: "source",
|
|
1468
|
+
messageId: state.messageId,
|
|
1469
|
+
partId: createClientId("source"),
|
|
1470
|
+
source
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
async function* emitProviderToolCall(state, toolCall) {
|
|
1474
|
+
const fingerprint = valueFingerprint(toolCall);
|
|
1475
|
+
if (state.providerToolCallFingerprints.has(fingerprint)) return;
|
|
1476
|
+
state.providerToolCallFingerprints.add(fingerprint);
|
|
1477
|
+
yield clientEvent(state, { type: "provider_tool_call", toolCall });
|
|
1478
|
+
}
|
|
1479
|
+
async function* appendReasoning(state, event) {
|
|
1480
|
+
const key = event.id ?? "default";
|
|
1481
|
+
let reasoning = state.reasoning.get(key);
|
|
1482
|
+
if (reasoning === void 0) {
|
|
1483
|
+
reasoning = {
|
|
1484
|
+
partId: createClientId("reasoning"),
|
|
1485
|
+
...event.id === void 0 ? {} : { reasoningId: event.id },
|
|
1486
|
+
text: "",
|
|
1487
|
+
ended: false
|
|
1488
|
+
};
|
|
1489
|
+
state.reasoning.set(key, reasoning);
|
|
1490
|
+
yield clientEvent(state, {
|
|
1491
|
+
type: "reasoning_start",
|
|
1492
|
+
messageId: state.messageId,
|
|
1493
|
+
partId: reasoning.partId,
|
|
1494
|
+
...event.id === void 0 ? {} : { reasoningId: event.id }
|
|
1495
|
+
});
|
|
1496
|
+
}
|
|
1497
|
+
reasoning.text += event.delta;
|
|
1498
|
+
yield clientEvent(state, {
|
|
1499
|
+
type: "reasoning_delta",
|
|
1500
|
+
messageId: state.messageId,
|
|
1501
|
+
partId: reasoning.partId,
|
|
1502
|
+
delta: event.delta,
|
|
1503
|
+
...event.contentType === void 0 ? {} : { contentType: event.contentType },
|
|
1504
|
+
...event.signature === void 0 ? {} : { signature: event.signature }
|
|
1505
|
+
});
|
|
1506
|
+
}
|
|
1507
|
+
async function* appendToolCall(state, event) {
|
|
1508
|
+
const tool = getToolState(state, event.id, event.name);
|
|
1509
|
+
if (!tool.started) {
|
|
1510
|
+
tool.started = true;
|
|
1511
|
+
yield clientEvent(state, {
|
|
1512
|
+
type: "tool_call_start",
|
|
1513
|
+
messageId: state.messageId,
|
|
1514
|
+
partId: tool.partId,
|
|
1515
|
+
toolCallId: event.id,
|
|
1516
|
+
...event.callId === void 0 ? {} : { callId: event.callId },
|
|
1517
|
+
...event.name === void 0 ? {} : { toolName: event.name }
|
|
1518
|
+
});
|
|
1519
|
+
}
|
|
1520
|
+
if (event.callId !== void 0) tool.callId = event.callId;
|
|
1521
|
+
if (event.name !== void 0) tool.toolName = event.name;
|
|
1522
|
+
if (event.signature !== void 0) tool.signature = event.signature;
|
|
1523
|
+
if (event.argumentsDelta === void 0) return;
|
|
1524
|
+
const mode = event.argumentsMode ?? "append";
|
|
1525
|
+
const prior = typeof tool.input === "string" ? tool.input : "";
|
|
1526
|
+
tool.input = mode === "replace" ? event.argumentsDelta : `${prior}${event.argumentsDelta}`;
|
|
1527
|
+
yield clientEvent(state, {
|
|
1528
|
+
type: "tool_call_delta",
|
|
1529
|
+
messageId: state.messageId,
|
|
1530
|
+
partId: tool.partId,
|
|
1531
|
+
toolCallId: event.id,
|
|
1532
|
+
...event.callId === void 0 ? {} : { callId: event.callId },
|
|
1533
|
+
...event.name === void 0 ? {} : { toolName: event.name },
|
|
1534
|
+
delta: event.argumentsDelta,
|
|
1535
|
+
mode,
|
|
1536
|
+
...event.signature === void 0 ? {} : { signature: event.signature }
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
async function* finishToolCall(state, toolCall) {
|
|
1540
|
+
const tool = getToolState(state, toolCall.toolCallId, toolCall.toolName);
|
|
1541
|
+
const wasEnded = tool.ended;
|
|
1542
|
+
if (!tool.started) {
|
|
1543
|
+
tool.started = true;
|
|
1544
|
+
yield clientEvent(state, {
|
|
1545
|
+
type: "tool_call_start",
|
|
1546
|
+
messageId: state.messageId,
|
|
1547
|
+
partId: tool.partId,
|
|
1548
|
+
toolCallId: toolCall.toolCallId,
|
|
1549
|
+
...toolCall.callId === void 0 ? {} : { callId: toolCall.callId },
|
|
1550
|
+
toolName: toolCall.toolName
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
if (toolCall.callId === void 0) delete tool.callId;
|
|
1554
|
+
else tool.callId = toolCall.callId;
|
|
1555
|
+
tool.toolName = toolCall.toolName;
|
|
1556
|
+
tool.input = toolCall.input;
|
|
1557
|
+
if (toolCall.signature === void 0) delete tool.signature;
|
|
1558
|
+
else tool.signature = toolCall.signature;
|
|
1559
|
+
if (wasEnded) return;
|
|
1560
|
+
tool.ended = true;
|
|
1561
|
+
yield clientEvent(state, {
|
|
1562
|
+
type: "tool_call_end",
|
|
1563
|
+
messageId: state.messageId,
|
|
1564
|
+
partId: tool.partId,
|
|
1565
|
+
toolCallId: toolCall.toolCallId,
|
|
1566
|
+
...toolCall.callId === void 0 ? {} : { callId: toolCall.callId },
|
|
1567
|
+
toolName: toolCall.toolName,
|
|
1568
|
+
input: toolCall.input,
|
|
1569
|
+
...toolCall.signature === void 0 ? {} : { signature: toolCall.signature }
|
|
1570
|
+
});
|
|
1571
|
+
}
|
|
1572
|
+
async function* finishMessage(state, content, metadata) {
|
|
1573
|
+
if (state.ended) return;
|
|
1574
|
+
const textContent2 = content.filter(
|
|
1575
|
+
(part) => part.type === "text"
|
|
1576
|
+
);
|
|
1577
|
+
const text = textContent2.map((part) => part.text).join("");
|
|
1578
|
+
if (state.textStarted || text.length > 0) {
|
|
1579
|
+
if (!state.textStarted) {
|
|
1580
|
+
state.textStarted = true;
|
|
1581
|
+
yield clientEvent(state, {
|
|
1582
|
+
type: "text_start",
|
|
1583
|
+
messageId: state.messageId,
|
|
1584
|
+
partId: state.textPartId
|
|
1585
|
+
});
|
|
1586
|
+
}
|
|
1587
|
+
state.text = text;
|
|
1588
|
+
state.textEnded = true;
|
|
1589
|
+
yield clientEvent(state, {
|
|
1590
|
+
type: "text_end",
|
|
1591
|
+
messageId: state.messageId,
|
|
1592
|
+
partId: state.textPartId,
|
|
1593
|
+
text,
|
|
1594
|
+
...textContent2.length === 1 && textContent2[0]?.signature !== void 0 ? { signature: textContent2[0].signature } : {}
|
|
1595
|
+
});
|
|
1596
|
+
}
|
|
1597
|
+
const finalReasoning = content.filter(
|
|
1598
|
+
(part) => part.type === "reasoning"
|
|
1599
|
+
);
|
|
1600
|
+
const anonymousReasoning = [...state.reasoning.values()].filter(
|
|
1601
|
+
(reasoning) => reasoning.reasoningId === void 0
|
|
1602
|
+
);
|
|
1603
|
+
let anonymousIndex = 0;
|
|
1604
|
+
for (const [index, reasoning] of finalReasoning.entries()) {
|
|
1605
|
+
const existing = reasoning.id === void 0 ? anonymousReasoning[anonymousIndex++] : state.reasoning.get(reasoning.id);
|
|
1606
|
+
const current = existing ?? createReasoningState(reasoning.id);
|
|
1607
|
+
if (existing === void 0) {
|
|
1608
|
+
state.reasoning.set(reasoning.id ?? `final:${index}`, current);
|
|
1609
|
+
yield clientEvent(state, {
|
|
1610
|
+
type: "reasoning_start",
|
|
1611
|
+
messageId: state.messageId,
|
|
1612
|
+
partId: current.partId,
|
|
1613
|
+
...reasoning.id === void 0 ? {} : { reasoningId: reasoning.id }
|
|
1614
|
+
});
|
|
1615
|
+
}
|
|
1616
|
+
if (!current.ended) {
|
|
1617
|
+
current.ended = true;
|
|
1618
|
+
current.text = reasoning.text;
|
|
1619
|
+
yield clientEvent(state, {
|
|
1620
|
+
type: "reasoning_end",
|
|
1621
|
+
messageId: state.messageId,
|
|
1622
|
+
partId: current.partId,
|
|
1623
|
+
text: reasoning.text,
|
|
1624
|
+
...reasoning.details === void 0 ? {} : { content: reasoning.details }
|
|
1625
|
+
});
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
for (const reasoning of state.reasoning.values()) {
|
|
1629
|
+
if (reasoning.ended) continue;
|
|
1630
|
+
reasoning.ended = true;
|
|
1631
|
+
yield clientEvent(state, {
|
|
1632
|
+
type: "reasoning_end",
|
|
1633
|
+
messageId: state.messageId,
|
|
1634
|
+
partId: reasoning.partId,
|
|
1635
|
+
text: reasoning.text
|
|
1636
|
+
});
|
|
1637
|
+
}
|
|
1638
|
+
for (const part of content) {
|
|
1639
|
+
if (part.type === "tool-call") yield* finishToolCall(state, part);
|
|
1640
|
+
if (part.type === "image" || part.type === "file") {
|
|
1641
|
+
const attachment = contentAttachment(part);
|
|
1642
|
+
yield clientEvent(state, {
|
|
1643
|
+
type: "attachment",
|
|
1644
|
+
messageId: state.messageId,
|
|
1645
|
+
partId: createClientId("attachment_part"),
|
|
1646
|
+
attachment
|
|
1647
|
+
});
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
for (const source of metadata.sources ?? []) yield* emitSource(state, source);
|
|
1651
|
+
for (const toolCall of metadata.providerToolCalls ?? []) {
|
|
1652
|
+
yield* emitProviderToolCall(state, toolCall);
|
|
1653
|
+
}
|
|
1654
|
+
state.ended = true;
|
|
1655
|
+
yield clientEvent(state, {
|
|
1656
|
+
type: "message_end",
|
|
1657
|
+
messageId: state.messageId,
|
|
1658
|
+
...state.modelMessageId === void 0 ? {} : { modelMessageId: state.modelMessageId },
|
|
1659
|
+
parts: contentToUIMessageParts(content, state),
|
|
1660
|
+
usage: metadata.usage,
|
|
1661
|
+
...metadata.contextUsage === void 0 ? {} : { contextUsage: metadata.contextUsage }
|
|
1662
|
+
});
|
|
1663
|
+
}
|
|
1664
|
+
async function* finishErroredRun(state, error, usage, mapper) {
|
|
1665
|
+
const mapped = mapClientError(error, mapper);
|
|
1666
|
+
if (state.textStarted && !state.textEnded) {
|
|
1667
|
+
state.textEnded = true;
|
|
1668
|
+
yield clientEvent(state, {
|
|
1669
|
+
type: "text_end",
|
|
1670
|
+
messageId: state.messageId,
|
|
1671
|
+
partId: state.textPartId,
|
|
1672
|
+
text: state.text
|
|
1673
|
+
});
|
|
1674
|
+
}
|
|
1675
|
+
yield clientEvent(state, {
|
|
1676
|
+
type: "error",
|
|
1677
|
+
error: mapped,
|
|
1678
|
+
...usage === void 0 ? {} : { usage }
|
|
1679
|
+
});
|
|
1680
|
+
if (!state.ended) {
|
|
1681
|
+
state.ended = true;
|
|
1682
|
+
yield clientEvent(state, {
|
|
1683
|
+
type: "message_end",
|
|
1684
|
+
messageId: state.messageId,
|
|
1685
|
+
...state.modelMessageId === void 0 ? {} : { modelMessageId: state.modelMessageId },
|
|
1686
|
+
...usage === void 0 ? {} : { usage }
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
yield clientEvent(state, {
|
|
1690
|
+
type: "run_end",
|
|
1691
|
+
status: "error",
|
|
1692
|
+
...usage === void 0 ? {} : { usage }
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1695
|
+
function contentToUIMessageParts(content, state) {
|
|
1696
|
+
let textIndex = 0;
|
|
1697
|
+
let anonymousReasoningIndex = 0;
|
|
1698
|
+
const anonymousReasoning = [...state.reasoning.values()].filter(
|
|
1699
|
+
(reasoning) => reasoning.reasoningId === void 0
|
|
1700
|
+
);
|
|
1701
|
+
return content.map((contentPart) => {
|
|
1702
|
+
if (contentPart.type === "text") {
|
|
1703
|
+
const part = {
|
|
1704
|
+
id: textIndex === 0 ? state.textPartId : createClientId("text"),
|
|
1705
|
+
type: "text",
|
|
1706
|
+
text: contentPart.text
|
|
1707
|
+
};
|
|
1708
|
+
textIndex += 1;
|
|
1709
|
+
if (contentPart.signature !== void 0) part.signature = contentPart.signature;
|
|
1710
|
+
return part;
|
|
1711
|
+
}
|
|
1712
|
+
if (contentPart.type === "reasoning") {
|
|
1713
|
+
const current = contentPart.id === void 0 ? anonymousReasoning[anonymousReasoningIndex++] : state.reasoning.get(contentPart.id);
|
|
1714
|
+
const part = {
|
|
1715
|
+
id: current?.partId ?? createClientId("reasoning"),
|
|
1716
|
+
type: "reasoning",
|
|
1717
|
+
text: contentPart.text
|
|
1718
|
+
};
|
|
1719
|
+
if (contentPart.id !== void 0) part.reasoningId = contentPart.id;
|
|
1720
|
+
if (contentPart.details !== void 0) part.content = contentPart.details;
|
|
1721
|
+
return part;
|
|
1722
|
+
}
|
|
1723
|
+
if (contentPart.type === "tool-call") {
|
|
1724
|
+
const tool = getToolState(state, contentPart.toolCallId, contentPart.toolName);
|
|
1725
|
+
const part = {
|
|
1726
|
+
id: tool.partId,
|
|
1727
|
+
type: "tool",
|
|
1728
|
+
toolName: contentPart.toolName,
|
|
1729
|
+
toolCallId: contentPart.toolCallId,
|
|
1730
|
+
state: tool.result?.status === "error" ? "error" : tool.result ? "output-available" : "input-available",
|
|
1731
|
+
input: contentPart.input
|
|
1732
|
+
};
|
|
1733
|
+
if (contentPart.callId !== void 0) part.callId = contentPart.callId;
|
|
1734
|
+
if (tool.internalCallId !== void 0) part.internalCallId = tool.internalCallId;
|
|
1735
|
+
if (state.turn !== void 0) part.turn = state.turn;
|
|
1736
|
+
if (contentPart.signature !== void 0) part.signature = contentPart.signature;
|
|
1737
|
+
if (tool.result?.status === "success") {
|
|
1738
|
+
part.output = tool.result.output;
|
|
1739
|
+
if (tool.result.content !== void 0) part.resultContent = tool.result.content;
|
|
1740
|
+
} else if (tool.result?.status === "error") {
|
|
1741
|
+
part.error = tool.result.error;
|
|
1742
|
+
}
|
|
1743
|
+
return part;
|
|
1744
|
+
}
|
|
1745
|
+
const attachment = contentAttachment(contentPart);
|
|
1746
|
+
return {
|
|
1747
|
+
id: createClientId("attachment_part"),
|
|
1748
|
+
type: "attachment",
|
|
1749
|
+
attachment
|
|
1750
|
+
};
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
function getToolState(state, id, name) {
|
|
1754
|
+
let tool = state.tools.get(id);
|
|
1755
|
+
if (tool === void 0) {
|
|
1756
|
+
tool = {
|
|
1757
|
+
partId: createClientId("tool"),
|
|
1758
|
+
toolCallId: id,
|
|
1759
|
+
...name === void 0 ? {} : { toolName: name },
|
|
1760
|
+
input: "",
|
|
1761
|
+
started: false,
|
|
1762
|
+
ended: false
|
|
1763
|
+
};
|
|
1764
|
+
state.tools.set(id, tool);
|
|
1765
|
+
} else if (name !== void 0) {
|
|
1766
|
+
tool.toolName = name;
|
|
1767
|
+
}
|
|
1768
|
+
return tool;
|
|
1769
|
+
}
|
|
1770
|
+
function getToolResultState(state, toolName, toolCallId, callId, internalCallId) {
|
|
1771
|
+
const matchedByToolCallId = state.tools.get(toolCallId);
|
|
1772
|
+
const matchedByCallId = callId === void 0 ? void 0 : [...state.tools.values()].find((tool2) => tool2.callId === callId);
|
|
1773
|
+
const tool = matchedByToolCallId ?? matchedByCallId ?? getToolState(state, toolCallId, toolName);
|
|
1774
|
+
tool.toolName = toolName;
|
|
1775
|
+
if (callId !== void 0) tool.callId = callId;
|
|
1776
|
+
tool.internalCallId = internalCallId;
|
|
1777
|
+
return tool;
|
|
1778
|
+
}
|
|
1779
|
+
function createReasoningState(id) {
|
|
1780
|
+
return {
|
|
1781
|
+
partId: createClientId("reasoning"),
|
|
1782
|
+
...id === void 0 ? {} : { reasoningId: id },
|
|
1783
|
+
text: "",
|
|
1784
|
+
ended: false
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
function contentAttachment(content) {
|
|
1788
|
+
const attachment = {
|
|
1789
|
+
id: createClientId("attachment"),
|
|
1790
|
+
type: content.type === "image" ? "image" : "file"
|
|
1791
|
+
};
|
|
1792
|
+
if (content.type === "image") {
|
|
1793
|
+
if (content.detail !== void 0) attachment.detail = content.detail;
|
|
1794
|
+
if (content.mediaType !== void 0) attachment.mediaType = content.mediaType;
|
|
1795
|
+
if (content.image.type === "url") attachment.url = content.image.url;
|
|
1796
|
+
else attachment.data = content.image.data;
|
|
1797
|
+
return attachment;
|
|
1798
|
+
}
|
|
1799
|
+
attachment.mediaType = content.mediaType;
|
|
1800
|
+
if (content.filename !== void 0) attachment.name = content.filename;
|
|
1801
|
+
if (content.data.type === "url") {
|
|
1802
|
+
attachment.url = content.data.url;
|
|
1803
|
+
} else if (content.data.type === "data") {
|
|
1804
|
+
attachment.data = content.data.data;
|
|
1805
|
+
} else {
|
|
1806
|
+
attachment.text = content.data.text;
|
|
1807
|
+
}
|
|
1808
|
+
return attachment;
|
|
1809
|
+
}
|
|
1810
|
+
function clientToolResult(output, result) {
|
|
1811
|
+
switch (output.type) {
|
|
1812
|
+
case "text":
|
|
1813
|
+
return { status: "success", output: output.value };
|
|
1814
|
+
case "json":
|
|
1815
|
+
return { status: "success", output: output.value };
|
|
1816
|
+
case "content":
|
|
1817
|
+
return { status: "success", output: result, content: output.value };
|
|
1818
|
+
case "execution-denied":
|
|
1819
|
+
return {
|
|
1820
|
+
status: "error",
|
|
1821
|
+
error: {
|
|
1822
|
+
message: output.reason ?? "Tool execution was denied.",
|
|
1823
|
+
code: "tool_execution_denied"
|
|
1824
|
+
}
|
|
1825
|
+
};
|
|
1826
|
+
case "error-text":
|
|
1827
|
+
return {
|
|
1828
|
+
status: "error",
|
|
1829
|
+
error: { message: output.value, code: "tool_execution_error" }
|
|
1830
|
+
};
|
|
1831
|
+
case "error-json":
|
|
1832
|
+
return {
|
|
1833
|
+
status: "error",
|
|
1834
|
+
error: {
|
|
1835
|
+
message: "Tool execution failed.",
|
|
1836
|
+
code: "tool_execution_error",
|
|
1837
|
+
details: output.value
|
|
1838
|
+
}
|
|
1839
|
+
};
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
function parseJsonOrString(value) {
|
|
1843
|
+
try {
|
|
1844
|
+
const parsed = JSON.parse(value);
|
|
1845
|
+
return isJsonValue3(parsed) ? parsed : value;
|
|
1846
|
+
} catch {
|
|
1847
|
+
return value;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
function clientOutput(output, mapper) {
|
|
1851
|
+
const mapped = mapper === void 0 ? isJsonValue3(output) ? output : void 0 : mapper(output);
|
|
1852
|
+
if (mapped !== void 0 && !isJsonValue3(mapped)) {
|
|
1853
|
+
throw new TypeError("mapOutput must return a strict JSON value or undefined.");
|
|
1854
|
+
}
|
|
1855
|
+
return mapped;
|
|
1856
|
+
}
|
|
1857
|
+
function valueFingerprint(value) {
|
|
1858
|
+
if (value === null) return "null";
|
|
1859
|
+
if (value === void 0) return "undefined";
|
|
1860
|
+
if (Array.isArray(value)) return `[${value.map(valueFingerprint).join(",")}]`;
|
|
1861
|
+
if (typeof value === "object") {
|
|
1862
|
+
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => `${JSON.stringify(key)}:${valueFingerprint(entry)}`).join(",")}}`;
|
|
1863
|
+
}
|
|
1864
|
+
return `${typeof value}:${JSON.stringify(value)}`;
|
|
1865
|
+
}
|
|
1866
|
+
function jsonValueOrUndefined(value) {
|
|
1867
|
+
return isJsonValue3(value) ? value : void 0;
|
|
1868
|
+
}
|
|
1869
|
+
function clientTrace(trace) {
|
|
1870
|
+
return {
|
|
1871
|
+
observer: trace.observer,
|
|
1872
|
+
...trace.traceId === void 0 ? {} : { traceId: trace.traceId },
|
|
1873
|
+
...trace.observationId === void 0 ? {} : { observationId: trace.observationId }
|
|
1874
|
+
};
|
|
1875
|
+
}
|
|
1876
|
+
function mapClientError(error, mapper) {
|
|
1877
|
+
const mapped = mapper?.(error) ?? maskedClientError();
|
|
1878
|
+
if (typeof mapped.message !== "string" || mapped.details !== void 0 && !isJsonValue3(mapped.details)) {
|
|
1879
|
+
throw new TypeError("mapError must return a JSON-safe ClientStreamError.");
|
|
1880
|
+
}
|
|
1881
|
+
return mapped;
|
|
1882
|
+
}
|
|
1883
|
+
function clientEvent(state, event) {
|
|
1884
|
+
return scopedEvent(state.runId, state.turn, state.scope, event);
|
|
1885
|
+
}
|
|
1886
|
+
function rootEvent(runId, event, scope) {
|
|
1887
|
+
return scopedEvent(runId, void 0, scope, event);
|
|
1888
|
+
}
|
|
1889
|
+
function scopedEvent(runId, turn, scope, event) {
|
|
1890
|
+
return {
|
|
1891
|
+
runId,
|
|
1892
|
+
...turn === void 0 ? {} : { turn },
|
|
1893
|
+
...scope === void 0 ? {} : { scope },
|
|
1894
|
+
...event
|
|
1895
|
+
};
|
|
1896
|
+
}
|
|
1897
|
+
function scopeKey(scope) {
|
|
1898
|
+
if (scope === void 0) return "root";
|
|
1899
|
+
return [
|
|
1900
|
+
scope.agentId,
|
|
1901
|
+
scope.parentRunId,
|
|
1902
|
+
scope.parentToolName,
|
|
1903
|
+
scope.parentToolCallId,
|
|
1904
|
+
scope.parentInternalToolCallId
|
|
1905
|
+
].join(":");
|
|
1906
|
+
}
|
|
1907
|
+
function isRootTerminalAgentEvent(event) {
|
|
1908
|
+
return event.type === "final" || event.type === "approval_required" || event.type === "error";
|
|
1909
|
+
}
|
|
1910
|
+
function propagateCancellation(source, transform) {
|
|
1911
|
+
return {
|
|
1912
|
+
[Symbol.asyncIterator]() {
|
|
1913
|
+
const sourceIterator = source[Symbol.asyncIterator]();
|
|
1914
|
+
const sharedSource = {
|
|
1915
|
+
[Symbol.asyncIterator]: () => sourceIterator
|
|
1916
|
+
};
|
|
1917
|
+
const outputIterator = transform(sharedSource)[Symbol.asyncIterator]();
|
|
1918
|
+
let returned = false;
|
|
1919
|
+
return {
|
|
1920
|
+
next: () => outputIterator.next(),
|
|
1921
|
+
async return() {
|
|
1922
|
+
if (returned) return { done: true, value: void 0 };
|
|
1923
|
+
returned = true;
|
|
1924
|
+
const sourceReturn = sourceIterator.return?.();
|
|
1925
|
+
const outputReturn = outputIterator.return?.();
|
|
1926
|
+
await Promise.all([sourceReturn, outputReturn]);
|
|
1927
|
+
return { done: true, value: void 0 };
|
|
1928
|
+
}
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
};
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
// src/client-transport.ts
|
|
1935
|
+
function createHttpClientTransport(options) {
|
|
1936
|
+
const transport = createFetchEventTransport({
|
|
1937
|
+
...options,
|
|
1938
|
+
mapEvent: (event) => parseClientStreamFrame(event, protocolOptions(options)),
|
|
1939
|
+
validateResponse(response) {
|
|
1940
|
+
if (response.headers.get("x-anvia-stream-protocol") !== CLIENT_STREAM_PROTOCOL) {
|
|
1941
|
+
throw new ClientProtocolError(
|
|
1942
|
+
`Expected x-anvia-stream-protocol: ${CLIENT_STREAM_PROTOCOL}.`
|
|
1943
|
+
);
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
});
|
|
1947
|
+
return {
|
|
1948
|
+
async *send(sendOptions) {
|
|
1949
|
+
const resume = sendOptions.resume ?? resumeCursorFromRequest(sendOptions.request);
|
|
1950
|
+
yield* validateFrameSequence(transport.send(sendOptions), resume);
|
|
1951
|
+
}
|
|
1952
|
+
};
|
|
1953
|
+
}
|
|
1954
|
+
function createDirectClientTransport(options) {
|
|
1955
|
+
return {
|
|
1956
|
+
async *send(sendOptions) {
|
|
1957
|
+
const resume = sendOptions.resume ?? resumeCursorFromRequest(sendOptions.request);
|
|
1958
|
+
if (resume !== void 0) {
|
|
1959
|
+
throw new ClientProtocolError("Direct client transports do not support resume cursors.");
|
|
1960
|
+
}
|
|
1961
|
+
const streamId = createClientId("stream");
|
|
1962
|
+
let eventId = 0;
|
|
1963
|
+
yield {
|
|
1964
|
+
type: "stream_start",
|
|
1965
|
+
protocol: CLIENT_STREAM_PROTOCOL,
|
|
1966
|
+
streamId,
|
|
1967
|
+
eventId: 0,
|
|
1968
|
+
resumable: false
|
|
1969
|
+
};
|
|
1970
|
+
let status = "completed";
|
|
1971
|
+
try {
|
|
1972
|
+
const events = await options.handler({
|
|
1973
|
+
request: sendOptions.request,
|
|
1974
|
+
...sendOptions.abortSignal === void 0 ? {} : { abortSignal: sendOptions.abortSignal },
|
|
1975
|
+
...sendOptions.headers === void 0 ? {} : { headers: sendOptions.headers }
|
|
1976
|
+
});
|
|
1977
|
+
const iterator = events[Symbol.asyncIterator]();
|
|
1978
|
+
let closePromise;
|
|
1979
|
+
const close = () => {
|
|
1980
|
+
closePromise ??= Promise.resolve(iterator.return?.());
|
|
1981
|
+
return closePromise;
|
|
1982
|
+
};
|
|
1983
|
+
const onAbort = () => {
|
|
1984
|
+
void close();
|
|
1985
|
+
};
|
|
1986
|
+
sendOptions.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
1987
|
+
try {
|
|
1988
|
+
while (!sendOptions.abortSignal?.aborted) {
|
|
1989
|
+
const next = await iterator.next();
|
|
1990
|
+
if (next.done) break;
|
|
1991
|
+
const event = parseClientStreamEvent(
|
|
1992
|
+
next.value,
|
|
1993
|
+
protocolOptions(options)
|
|
1994
|
+
);
|
|
1995
|
+
eventId += 1;
|
|
1996
|
+
yield { type: "stream_event", streamId, eventId, event };
|
|
1997
|
+
}
|
|
1998
|
+
} finally {
|
|
1999
|
+
sendOptions.abortSignal?.removeEventListener("abort", onAbort);
|
|
2000
|
+
await close();
|
|
2001
|
+
}
|
|
2002
|
+
} catch {
|
|
2003
|
+
status = "error";
|
|
2004
|
+
}
|
|
2005
|
+
yield { type: "stream_end", streamId, eventId, status };
|
|
2006
|
+
}
|
|
2007
|
+
};
|
|
2008
|
+
}
|
|
2009
|
+
async function* validateFrameSequence(frames, resume) {
|
|
2010
|
+
let streamId;
|
|
2011
|
+
let lastEventId = resume?.after ?? 0;
|
|
2012
|
+
let ended = false;
|
|
2013
|
+
for await (const frame of frames) {
|
|
2014
|
+
if (ended) throw new ClientProtocolError("Received a frame after stream_end.", frame);
|
|
2015
|
+
if (streamId === void 0) {
|
|
2016
|
+
if (frame.type !== "stream_start") {
|
|
2017
|
+
throw new ClientProtocolError("The first client stream frame must be stream_start.", frame);
|
|
2018
|
+
}
|
|
2019
|
+
streamId = frame.streamId;
|
|
2020
|
+
if (resume !== void 0 && frame.streamId !== resume.streamId) {
|
|
2021
|
+
throw new ClientProtocolError("Resume response streamId does not match the cursor.", frame);
|
|
2022
|
+
}
|
|
2023
|
+
if (resume !== void 0 && !frame.resumable) {
|
|
2024
|
+
throw new ClientProtocolError("Resume response must identify a resumable stream.", frame);
|
|
2025
|
+
}
|
|
2026
|
+
} else if (frame.type === "stream_start") {
|
|
2027
|
+
throw new ClientProtocolError("Received more than one stream_start frame.", frame);
|
|
2028
|
+
} else if (frame.streamId !== streamId) {
|
|
2029
|
+
throw new ClientProtocolError("Client streamId changed during the response.", frame);
|
|
2030
|
+
}
|
|
2031
|
+
if (frame.type === "stream_event") {
|
|
2032
|
+
if (frame.eventId !== lastEventId + 1) {
|
|
2033
|
+
throw new ClientProtocolError("Client stream event IDs must be contiguous.", frame);
|
|
2034
|
+
}
|
|
2035
|
+
lastEventId = frame.eventId;
|
|
2036
|
+
} else if (frame.type === "stream_end") {
|
|
2037
|
+
if (frame.eventId !== lastEventId) {
|
|
2038
|
+
throw new ClientProtocolError("stream_end has an invalid eventId.", frame);
|
|
2039
|
+
}
|
|
2040
|
+
ended = true;
|
|
2041
|
+
}
|
|
2042
|
+
yield frame;
|
|
2043
|
+
}
|
|
2044
|
+
if (streamId === void 0 || !ended) {
|
|
2045
|
+
throw new ClientProtocolError("Client stream ended without a complete frame sequence.");
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
function protocolOptions(options) {
|
|
2049
|
+
return {
|
|
2050
|
+
...options.metadataSchema === void 0 ? {} : { metadataSchema: options.metadataSchema },
|
|
2051
|
+
...options.dataSchemas === void 0 ? {} : { dataSchemas: options.dataSchemas }
|
|
2052
|
+
};
|
|
2053
|
+
}
|
|
2054
|
+
function resumeCursorFromRequest(value) {
|
|
2055
|
+
if (typeof value !== "object" || value === null || !("resume" in value)) return void 0;
|
|
2056
|
+
const resume = value.resume;
|
|
2057
|
+
if (typeof resume !== "object" || resume === null) return void 0;
|
|
2058
|
+
if (!("streamId" in resume) || !("after" in resume)) return void 0;
|
|
2059
|
+
return typeof resume.streamId === "string" && typeof resume.after === "number" && Number.isSafeInteger(resume.after) && resume.after >= 0 ? { streamId: resume.streamId, after: resume.after } : void 0;
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
// src/reducer.ts
|
|
2063
|
+
import { isJsonValue as isJsonValue4 } from "@anvia/core/completion";
|
|
2064
|
+
function applyClientStreamEvent(messages, event) {
|
|
2065
|
+
if (event.scope?.parentToolCallId !== void 0) {
|
|
2066
|
+
return messages;
|
|
2067
|
+
}
|
|
2068
|
+
switch (event.type) {
|
|
2069
|
+
case "message_start":
|
|
2070
|
+
return messages.some((message) => message.id === event.messageId) ? messages : [
|
|
2071
|
+
...messages,
|
|
2072
|
+
{
|
|
2073
|
+
id: event.messageId,
|
|
2074
|
+
role: event.role,
|
|
2075
|
+
parts: [],
|
|
2076
|
+
...event.metadata === void 0 ? {} : { metadata: event.metadata }
|
|
2077
|
+
}
|
|
2078
|
+
];
|
|
2079
|
+
case "text_start":
|
|
2080
|
+
return upsertPart(messages, event.messageId, {
|
|
2081
|
+
id: event.partId,
|
|
2082
|
+
type: "text",
|
|
2083
|
+
text: ""
|
|
2084
|
+
});
|
|
2085
|
+
case "text_delta":
|
|
2086
|
+
return updatePart(messages, event.messageId, event.partId, (part) => ({
|
|
2087
|
+
id: event.partId,
|
|
2088
|
+
type: "text",
|
|
2089
|
+
text: part?.type === "text" ? `${part.text}${event.delta}` : event.delta
|
|
2090
|
+
}));
|
|
2091
|
+
case "text_end":
|
|
2092
|
+
return updatePart(messages, event.messageId, event.partId, (part) => {
|
|
2093
|
+
const next = {
|
|
2094
|
+
id: event.partId,
|
|
2095
|
+
type: "text",
|
|
2096
|
+
text: event.text ?? (part?.type === "text" ? part.text : "")
|
|
2097
|
+
};
|
|
2098
|
+
if (event.signature !== void 0) next.signature = event.signature;
|
|
2099
|
+
return next;
|
|
2100
|
+
});
|
|
2101
|
+
case "reasoning_start":
|
|
2102
|
+
return upsertPart(messages, event.messageId, {
|
|
2103
|
+
id: event.partId,
|
|
2104
|
+
type: "reasoning",
|
|
2105
|
+
text: "",
|
|
2106
|
+
...event.reasoningId === void 0 ? {} : { reasoningId: event.reasoningId }
|
|
2107
|
+
});
|
|
2108
|
+
case "reasoning_delta":
|
|
2109
|
+
return updatePart(messages, event.messageId, event.partId, (part) => {
|
|
2110
|
+
const reasoning = {
|
|
2111
|
+
id: event.partId,
|
|
2112
|
+
type: "reasoning",
|
|
2113
|
+
text: part?.type === "reasoning" ? `${part.text}${event.delta}` : event.delta,
|
|
2114
|
+
...part?.type === "reasoning" && part.reasoningId !== void 0 ? { reasoningId: part.reasoningId } : {}
|
|
2115
|
+
};
|
|
2116
|
+
const content = appendReasoningContent(
|
|
2117
|
+
part?.type === "reasoning" ? part.content : void 0,
|
|
2118
|
+
event
|
|
2119
|
+
);
|
|
2120
|
+
if (content !== void 0) reasoning.content = content;
|
|
2121
|
+
return reasoning;
|
|
2122
|
+
});
|
|
2123
|
+
case "reasoning_end":
|
|
2124
|
+
return updatePart(messages, event.messageId, event.partId, (part) => ({
|
|
2125
|
+
id: event.partId,
|
|
2126
|
+
type: "reasoning",
|
|
2127
|
+
text: event.text ?? (part?.type === "reasoning" ? part.text : ""),
|
|
2128
|
+
...part?.type === "reasoning" && part.reasoningId !== void 0 ? { reasoningId: part.reasoningId } : {},
|
|
2129
|
+
...event.content !== void 0 ? { content: event.content } : part?.type === "reasoning" && part.content !== void 0 ? { content: part.content } : {}
|
|
2130
|
+
}));
|
|
2131
|
+
case "tool_call_start": {
|
|
2132
|
+
const part = {
|
|
2133
|
+
id: event.partId,
|
|
2134
|
+
type: "tool",
|
|
2135
|
+
toolName: event.toolName ?? "",
|
|
2136
|
+
toolCallId: event.toolCallId,
|
|
2137
|
+
state: "input-streaming",
|
|
2138
|
+
input: ""
|
|
2139
|
+
};
|
|
2140
|
+
if (event.callId !== void 0) part.callId = event.callId;
|
|
2141
|
+
if (event.turn !== void 0) part.turn = event.turn;
|
|
2142
|
+
return upsertPart(messages, event.messageId, part);
|
|
2143
|
+
}
|
|
2144
|
+
case "tool_call_delta":
|
|
2145
|
+
return updatePart(messages, event.messageId, event.partId, (current) => {
|
|
2146
|
+
const part = current?.type === "tool" ? { ...current } : {
|
|
2147
|
+
id: event.partId,
|
|
2148
|
+
type: "tool",
|
|
2149
|
+
toolName: event.toolName ?? "",
|
|
2150
|
+
toolCallId: event.toolCallId,
|
|
2151
|
+
state: "input-streaming"
|
|
2152
|
+
};
|
|
2153
|
+
const previous = typeof part.input === "string" ? part.input : "";
|
|
2154
|
+
part.input = event.mode === "replace" ? event.delta : `${previous}${event.delta}`;
|
|
2155
|
+
part.state = "input-streaming";
|
|
2156
|
+
if (event.toolName !== void 0) part.toolName = event.toolName;
|
|
2157
|
+
if (event.callId !== void 0) part.callId = event.callId;
|
|
2158
|
+
if (event.signature !== void 0) part.signature = event.signature;
|
|
2159
|
+
if (event.turn !== void 0) part.turn = event.turn;
|
|
2160
|
+
return part;
|
|
2161
|
+
});
|
|
2162
|
+
case "tool_call_end": {
|
|
2163
|
+
const part = {
|
|
2164
|
+
id: event.partId,
|
|
2165
|
+
type: "tool",
|
|
2166
|
+
toolName: event.toolName,
|
|
2167
|
+
toolCallId: event.toolCallId,
|
|
2168
|
+
state: "input-available",
|
|
2169
|
+
input: event.input
|
|
2170
|
+
};
|
|
2171
|
+
if (event.callId !== void 0) part.callId = event.callId;
|
|
2172
|
+
if (event.turn !== void 0) part.turn = event.turn;
|
|
2173
|
+
if (event.signature !== void 0) part.signature = event.signature;
|
|
2174
|
+
return upsertPart(messages, event.messageId, part);
|
|
2175
|
+
}
|
|
2176
|
+
case "tool_result":
|
|
2177
|
+
return updatePart(messages, event.messageId, event.partId, (current) => {
|
|
2178
|
+
const part = current?.type === "tool" ? { ...current } : {
|
|
2179
|
+
id: event.partId,
|
|
2180
|
+
type: "tool",
|
|
2181
|
+
toolName: event.toolName,
|
|
2182
|
+
toolCallId: event.toolCallId,
|
|
2183
|
+
state: "input-available"
|
|
2184
|
+
};
|
|
2185
|
+
if (event.callId !== void 0) part.callId = event.callId;
|
|
2186
|
+
if (event.internalCallId !== void 0) part.internalCallId = event.internalCallId;
|
|
2187
|
+
if (event.input !== void 0) part.input = event.input;
|
|
2188
|
+
if (event.turn !== void 0) part.turn = event.turn;
|
|
2189
|
+
if (event.result.status === "error") {
|
|
2190
|
+
part.state = "error";
|
|
2191
|
+
part.error = event.result.error;
|
|
2192
|
+
} else {
|
|
2193
|
+
part.state = "output-available";
|
|
2194
|
+
part.output = event.result.output;
|
|
2195
|
+
if (event.result.content !== void 0) part.resultContent = event.result.content;
|
|
2196
|
+
}
|
|
2197
|
+
return part;
|
|
2198
|
+
});
|
|
2199
|
+
case "source":
|
|
2200
|
+
return upsertPart(messages, event.messageId, {
|
|
2201
|
+
id: event.partId,
|
|
2202
|
+
type: "source",
|
|
2203
|
+
source: event.source
|
|
2204
|
+
});
|
|
2205
|
+
case "attachment":
|
|
2206
|
+
return upsertPart(messages, event.messageId, {
|
|
2207
|
+
id: event.partId,
|
|
2208
|
+
type: "attachment",
|
|
2209
|
+
attachment: event.attachment
|
|
2210
|
+
});
|
|
2211
|
+
case "data":
|
|
2212
|
+
if (event.transient === true) return messages;
|
|
2213
|
+
return appendToLastAssistant(messages, {
|
|
2214
|
+
id: createClientId("data"),
|
|
2215
|
+
type: "data",
|
|
2216
|
+
name: event.name,
|
|
2217
|
+
data: event.data
|
|
2218
|
+
});
|
|
2219
|
+
case "message_end":
|
|
2220
|
+
return messages.map((message) => {
|
|
2221
|
+
if (message.id !== event.messageId) return message;
|
|
2222
|
+
const metadata = mergeMetadata(message.metadata, event.metadata);
|
|
2223
|
+
const generation = mergeGeneration(message.generation, {
|
|
2224
|
+
runId: event.runId,
|
|
2225
|
+
...event.usage === void 0 ? {} : { usage: event.usage },
|
|
2226
|
+
...event.contextUsage === void 0 ? {} : { contextUsage: event.contextUsage }
|
|
2227
|
+
});
|
|
2228
|
+
return {
|
|
2229
|
+
...message,
|
|
2230
|
+
...event.parts === void 0 ? {} : { parts: reconcileFinalParts(message.parts, event.parts) },
|
|
2231
|
+
...event.modelMessageId === void 0 ? {} : { modelMessageId: event.modelMessageId },
|
|
2232
|
+
...metadata === void 0 ? {} : { metadata },
|
|
2233
|
+
generation
|
|
2234
|
+
};
|
|
2235
|
+
});
|
|
2236
|
+
case "run_end":
|
|
2237
|
+
return updateLastAssistantGeneration(messages, {
|
|
2238
|
+
runId: event.runId,
|
|
2239
|
+
status: event.status,
|
|
2240
|
+
...event.usage === void 0 ? {} : { usage: event.usage },
|
|
2241
|
+
...event.contextUsage === void 0 ? {} : { contextUsage: event.contextUsage },
|
|
2242
|
+
...event.trace === void 0 ? {} : { trace: event.trace },
|
|
2243
|
+
...event.memoryCompaction === void 0 ? {} : { memoryCompaction: event.memoryCompaction }
|
|
2244
|
+
});
|
|
2245
|
+
case "error":
|
|
2246
|
+
return appendToLastAssistant(messages, {
|
|
2247
|
+
id: createClientId("error"),
|
|
2248
|
+
type: "error",
|
|
2249
|
+
error: event.error
|
|
2250
|
+
});
|
|
2251
|
+
default:
|
|
2252
|
+
return messages;
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
function reconcileFinalParts(current, final) {
|
|
2256
|
+
const clientOnly = current.filter(
|
|
2257
|
+
(part) => part.type === "source" || part.type === "data" || part.type === "error"
|
|
2258
|
+
);
|
|
2259
|
+
return [...final, ...clientOnly];
|
|
2260
|
+
}
|
|
2261
|
+
function appendReasoningContent(current, event) {
|
|
2262
|
+
if (event.contentType === void 0 && event.signature === void 0) return current;
|
|
2263
|
+
const type = event.contentType ?? "text";
|
|
2264
|
+
const next = [...current ?? []];
|
|
2265
|
+
const last = next.at(-1);
|
|
2266
|
+
if (type === "text") {
|
|
2267
|
+
if (last?.type === "text" && last.signature === event.signature) {
|
|
2268
|
+
next[next.length - 1] = { ...last, text: `${last.text}${event.delta}` };
|
|
2269
|
+
} else {
|
|
2270
|
+
next.push({
|
|
2271
|
+
type,
|
|
2272
|
+
text: event.delta,
|
|
2273
|
+
...event.signature === void 0 ? {} : { signature: event.signature }
|
|
2274
|
+
});
|
|
2275
|
+
}
|
|
2276
|
+
return next;
|
|
2277
|
+
}
|
|
2278
|
+
if (type === "summary") {
|
|
2279
|
+
if (last?.type === "summary") {
|
|
2280
|
+
next[next.length - 1] = { ...last, text: `${last.text}${event.delta}` };
|
|
2281
|
+
} else next.push({ type, text: event.delta });
|
|
2282
|
+
return next;
|
|
2283
|
+
}
|
|
2284
|
+
if (type === "encrypted") {
|
|
2285
|
+
if (last?.type === "encrypted") {
|
|
2286
|
+
next[next.length - 1] = { ...last, data: `${last.data}${event.delta}` };
|
|
2287
|
+
} else next.push({ type, data: event.delta });
|
|
2288
|
+
return next;
|
|
2289
|
+
}
|
|
2290
|
+
if (last?.type === "redacted") {
|
|
2291
|
+
next[next.length - 1] = { ...last, data: `${last.data}${event.delta}` };
|
|
2292
|
+
} else next.push({ type, data: event.delta });
|
|
2293
|
+
return next;
|
|
2294
|
+
}
|
|
2295
|
+
function messageText(message) {
|
|
2296
|
+
return message.parts.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
|
|
2297
|
+
}
|
|
2298
|
+
function assistantText(messages) {
|
|
2299
|
+
const assistant = [...messages].reverse().find((message) => message.role === "assistant");
|
|
2300
|
+
return assistant === void 0 ? "" : messageText(assistant);
|
|
2301
|
+
}
|
|
2302
|
+
function upsertPart(messages, messageId, part) {
|
|
2303
|
+
return updatePart(messages, messageId, part.id, () => part);
|
|
2304
|
+
}
|
|
2305
|
+
function updatePart(messages, messageId, partId, update) {
|
|
2306
|
+
const current = ensureAssistant(messages, messageId);
|
|
2307
|
+
return current.map((message) => {
|
|
2308
|
+
if (message.id !== messageId) return message;
|
|
2309
|
+
const index = message.parts.findIndex((part) => part.id === partId);
|
|
2310
|
+
if (index === -1) return { ...message, parts: [...message.parts, update(void 0)] };
|
|
2311
|
+
const parts = [...message.parts];
|
|
2312
|
+
parts[index] = update(parts[index]);
|
|
2313
|
+
return { ...message, parts };
|
|
2314
|
+
});
|
|
2315
|
+
}
|
|
2316
|
+
function ensureAssistant(messages, messageId) {
|
|
2317
|
+
return messages.some((message) => message.id === messageId) ? messages : [...messages, { id: messageId, role: "assistant", parts: [] }];
|
|
2318
|
+
}
|
|
2319
|
+
function appendToLastAssistant(messages, part) {
|
|
2320
|
+
const index = findLastIndex(messages, (message2) => message2.role === "assistant");
|
|
2321
|
+
if (index === -1) {
|
|
2322
|
+
return [...messages, { id: createClientId("msg"), role: "assistant", parts: [part] }];
|
|
2323
|
+
}
|
|
2324
|
+
const next = [...messages];
|
|
2325
|
+
const message = next[index];
|
|
2326
|
+
next[index] = { ...message, parts: [...message.parts, part] };
|
|
2327
|
+
return next;
|
|
2328
|
+
}
|
|
2329
|
+
function updateLastAssistantGeneration(messages, value) {
|
|
2330
|
+
const index = findLastIndex(messages, (message2) => message2.role === "assistant");
|
|
2331
|
+
if (index === -1) return messages;
|
|
2332
|
+
const next = [...messages];
|
|
2333
|
+
const message = next[index];
|
|
2334
|
+
next[index] = { ...message, generation: mergeGeneration(message.generation, value) };
|
|
2335
|
+
return next;
|
|
2336
|
+
}
|
|
2337
|
+
function mergeMetadata(current, provided) {
|
|
2338
|
+
if (provided === void 0) return current;
|
|
2339
|
+
if (!isRecord2(current) || !isRecord2(provided)) return provided;
|
|
2340
|
+
const next = { ...current, ...provided };
|
|
2341
|
+
return isJsonValue4(next) ? next : provided;
|
|
2342
|
+
}
|
|
2343
|
+
function mergeGeneration(current, provided) {
|
|
2344
|
+
return {
|
|
2345
|
+
...current,
|
|
2346
|
+
...Object.fromEntries(Object.entries(provided).filter(([, value]) => value !== void 0))
|
|
2347
|
+
};
|
|
2348
|
+
}
|
|
2349
|
+
function findLastIndex(items, predicate) {
|
|
2350
|
+
for (let index = items.length - 1; index >= 0; index -= 1) {
|
|
2351
|
+
if (predicate(items[index])) return index;
|
|
2352
|
+
}
|
|
2353
|
+
return -1;
|
|
2354
|
+
}
|
|
2355
|
+
function isRecord2(value) {
|
|
2356
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2357
|
+
}
|
|
2358
|
+
export {
|
|
2359
|
+
CLIENT_STREAM_PROTOCOL,
|
|
2360
|
+
ClientProtocolError,
|
|
2361
|
+
agentToClientStream,
|
|
2362
|
+
applyClientStreamEvent,
|
|
2363
|
+
assistantText,
|
|
2364
|
+
completionToClientStream,
|
|
2365
|
+
createClientId,
|
|
2366
|
+
createDirectClientTransport,
|
|
2367
|
+
createHttpClientTransport,
|
|
2368
|
+
customAgentEventsToClientStream,
|
|
2369
|
+
maskedClientError,
|
|
2370
|
+
messageText,
|
|
2371
|
+
messagesToUIMessages,
|
|
2372
|
+
normalizeClientError,
|
|
2373
|
+
parseClientStreamEvent,
|
|
2374
|
+
parseClientStreamFrame,
|
|
2375
|
+
parseClientStreamRequest,
|
|
2376
|
+
parseUIMessage,
|
|
2377
|
+
parseUIMessages,
|
|
2378
|
+
uiMessagesToMessages
|
|
2379
|
+
};
|
|
2380
|
+
//# sourceMappingURL=index.js.map
|