@m8tes/sdk 0.1.0-alpha.1
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/CHANGELOG.md +100 -0
- package/LICENSE +21 -0
- package/README.md +160 -0
- package/dist/chunk-UFQQNUFE.js +1083 -0
- package/dist/chunk-UFQQNUFE.js.map +1 -0
- package/dist/fixtures.cjs +297 -0
- package/dist/fixtures.cjs.map +1 -0
- package/dist/fixtures.d.cts +81 -0
- package/dist/fixtures.d.ts +81 -0
- package/dist/fixtures.js +295 -0
- package/dist/fixtures.js.map +1 -0
- package/dist/index.cjs +1783 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +937 -0
- package/dist/index.d.ts +937 -0
- package/dist/index.js +672 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol/index.cjs +1109 -0
- package/dist/protocol/index.cjs.map +1 -0
- package/dist/protocol/index.d.cts +576 -0
- package/dist/protocol/index.d.ts +576 -0
- package/dist/protocol/index.js +3 -0
- package/dist/protocol/index.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,1083 @@
|
|
|
1
|
+
// src/protocol/events.ts
|
|
2
|
+
var PROTOCOL_VERSION = "m8tes.stream.v2";
|
|
3
|
+
var TERMINAL_EVENT_TYPES = [
|
|
4
|
+
"run-finish",
|
|
5
|
+
"run-error",
|
|
6
|
+
"run-cancelled"
|
|
7
|
+
];
|
|
8
|
+
function isTerminalEvent(event) {
|
|
9
|
+
return TERMINAL_EVENT_TYPES.includes(event.type);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// src/protocol/sse-parser.ts
|
|
13
|
+
function splitConcatenatedJson(payload) {
|
|
14
|
+
const out = [];
|
|
15
|
+
let depth = 0;
|
|
16
|
+
let inString = false;
|
|
17
|
+
let escaped = false;
|
|
18
|
+
let start = -1;
|
|
19
|
+
let lastEnd = 0;
|
|
20
|
+
for (let i = 0; i < payload.length; i++) {
|
|
21
|
+
const ch = payload.charAt(i);
|
|
22
|
+
if (start === -1) {
|
|
23
|
+
if (ch === "{" || ch === "[") {
|
|
24
|
+
start = i;
|
|
25
|
+
depth = 1;
|
|
26
|
+
inString = false;
|
|
27
|
+
escaped = false;
|
|
28
|
+
}
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (inString) {
|
|
32
|
+
if (escaped) escaped = false;
|
|
33
|
+
else if (ch === "\\") escaped = true;
|
|
34
|
+
else if (ch === '"') inString = false;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (ch === '"') {
|
|
38
|
+
inString = true;
|
|
39
|
+
} else if (ch === "{" || ch === "[") {
|
|
40
|
+
depth++;
|
|
41
|
+
} else if (ch === "}" || ch === "]") {
|
|
42
|
+
depth--;
|
|
43
|
+
if (depth === 0) {
|
|
44
|
+
out.push(payload.slice(start, i + 1));
|
|
45
|
+
start = -1;
|
|
46
|
+
lastEnd = i + 1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (start !== -1) {
|
|
51
|
+
out.push(payload.slice(start));
|
|
52
|
+
} else {
|
|
53
|
+
const tail = payload.slice(lastEnd).trim();
|
|
54
|
+
if (tail !== "") out.push(tail);
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
function frameDataPayload(frameText) {
|
|
59
|
+
const dataLines = [];
|
|
60
|
+
for (const rawLine of frameText.split("\n")) {
|
|
61
|
+
const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
|
|
62
|
+
if (line === "" || line.charAt(0) === ":") continue;
|
|
63
|
+
if (line.startsWith("data:")) {
|
|
64
|
+
let value = line.slice(5);
|
|
65
|
+
if (value.charAt(0) === " ") value = value.slice(1);
|
|
66
|
+
dataLines.push(value);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (dataLines.length === 0) return null;
|
|
70
|
+
return dataLines.join("\n");
|
|
71
|
+
}
|
|
72
|
+
function parsePayload(payload, onMalformed) {
|
|
73
|
+
const out = [];
|
|
74
|
+
for (const candidate of splitConcatenatedJson(payload)) {
|
|
75
|
+
try {
|
|
76
|
+
const parsed = JSON.parse(candidate);
|
|
77
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
78
|
+
out.push(parsed);
|
|
79
|
+
} else {
|
|
80
|
+
onMalformed?.(candidate, new Error("frame is not a JSON object"));
|
|
81
|
+
}
|
|
82
|
+
} catch (err) {
|
|
83
|
+
onMalformed?.(candidate, err);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
function createSseDecoder(opts = {}) {
|
|
89
|
+
let buf = "";
|
|
90
|
+
function ingest(chunk) {
|
|
91
|
+
buf += chunk;
|
|
92
|
+
let tail = "";
|
|
93
|
+
if (buf.endsWith("\r")) {
|
|
94
|
+
tail = "\r";
|
|
95
|
+
buf = buf.slice(0, -1);
|
|
96
|
+
}
|
|
97
|
+
buf = buf.replace(/\r\n?/g, "\n") + tail;
|
|
98
|
+
}
|
|
99
|
+
function drain(final) {
|
|
100
|
+
const frames = [];
|
|
101
|
+
let sep = buf.indexOf("\n\n");
|
|
102
|
+
while (sep !== -1) {
|
|
103
|
+
const frameText = buf.slice(0, sep);
|
|
104
|
+
buf = buf.slice(sep + 2);
|
|
105
|
+
const payload = frameDataPayload(frameText);
|
|
106
|
+
if (payload !== null) frames.push(...parsePayload(payload, opts.onMalformed));
|
|
107
|
+
sep = buf.indexOf("\n\n");
|
|
108
|
+
}
|
|
109
|
+
if (final && buf.trim() !== "") {
|
|
110
|
+
const payload = frameDataPayload(buf);
|
|
111
|
+
if (payload !== null) frames.push(...parsePayload(payload, opts.onMalformed));
|
|
112
|
+
buf = "";
|
|
113
|
+
}
|
|
114
|
+
return frames;
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
/** Feed a chunk; returns the wire frames it completed. */
|
|
118
|
+
push(chunk) {
|
|
119
|
+
ingest(chunk);
|
|
120
|
+
return drain(false);
|
|
121
|
+
},
|
|
122
|
+
/** Flush a trailing unterminated frame at end-of-stream. */
|
|
123
|
+
flush() {
|
|
124
|
+
if (buf.endsWith("\r")) buf = `${buf.slice(0, -1)}
|
|
125
|
+
`;
|
|
126
|
+
return drain(true);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function parseSse(text, opts = {}) {
|
|
131
|
+
const dec = createSseDecoder(opts);
|
|
132
|
+
return [...dec.push(text), ...dec.flush()];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// src/protocol/normalizer.ts
|
|
136
|
+
var ASK_USER_QUESTION = "AskUserQuestion";
|
|
137
|
+
var SANDBOX_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
138
|
+
"SANDBOX_BOOT_TIMEOUT",
|
|
139
|
+
"SANDBOX_QUOTA_EXHAUSTED",
|
|
140
|
+
"SANDBOX_UNAVAILABLE",
|
|
141
|
+
"SNAPSHOT_VERSION_MISMATCH",
|
|
142
|
+
"AGENT_RUNNER_DIED",
|
|
143
|
+
"RUNNER_LIFECYCLE_ERROR"
|
|
144
|
+
]);
|
|
145
|
+
var str = (o, k) => typeof o[k] === "string" ? o[k] : void 0;
|
|
146
|
+
var num = (o, k) => typeof o[k] === "number" ? o[k] : void 0;
|
|
147
|
+
var bool = (o, k) => typeof o[k] === "boolean" ? o[k] : void 0;
|
|
148
|
+
var obj = (o, k) => {
|
|
149
|
+
const v = o[k];
|
|
150
|
+
return v !== null && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
151
|
+
};
|
|
152
|
+
var arr = (o, k) => Array.isArray(o[k]) ? o[k] : void 0;
|
|
153
|
+
function blockKindFromType(t) {
|
|
154
|
+
switch (t) {
|
|
155
|
+
case "text":
|
|
156
|
+
return "text";
|
|
157
|
+
case "thinking":
|
|
158
|
+
case "reasoning":
|
|
159
|
+
return "reasoning";
|
|
160
|
+
case "plan":
|
|
161
|
+
return "plan";
|
|
162
|
+
case "tool_use":
|
|
163
|
+
case "server_tool_use":
|
|
164
|
+
return "tool_use";
|
|
165
|
+
default:
|
|
166
|
+
return "other";
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
var blockEndType = {
|
|
170
|
+
text: "text-end",
|
|
171
|
+
reasoning: "reasoning-end",
|
|
172
|
+
plan: "plan-end"
|
|
173
|
+
};
|
|
174
|
+
var blockStartType = {
|
|
175
|
+
text: "text-start",
|
|
176
|
+
reasoning: "reasoning-start",
|
|
177
|
+
plan: "plan-start"
|
|
178
|
+
};
|
|
179
|
+
var blockDeltaType = {
|
|
180
|
+
text: "text-delta",
|
|
181
|
+
reasoning: "reasoning-delta",
|
|
182
|
+
plan: "plan-delta"
|
|
183
|
+
};
|
|
184
|
+
function createNormalizer() {
|
|
185
|
+
let seq = 0;
|
|
186
|
+
let open = /* @__PURE__ */ new Set();
|
|
187
|
+
let seen = /* @__PURE__ */ new Set();
|
|
188
|
+
let blockKind = /* @__PURE__ */ new Map();
|
|
189
|
+
let currentMessageId = null;
|
|
190
|
+
let activeTextBlockId = null;
|
|
191
|
+
let lastToolId = null;
|
|
192
|
+
let lastQuestionToolId = null;
|
|
193
|
+
let anyContentStreamed = false;
|
|
194
|
+
let runStartEmitted = false;
|
|
195
|
+
let terminalEmitted = false;
|
|
196
|
+
function reset() {
|
|
197
|
+
seq = 0;
|
|
198
|
+
open = /* @__PURE__ */ new Set();
|
|
199
|
+
seen = /* @__PURE__ */ new Set();
|
|
200
|
+
blockKind = /* @__PURE__ */ new Map();
|
|
201
|
+
currentMessageId = null;
|
|
202
|
+
activeTextBlockId = null;
|
|
203
|
+
lastToolId = null;
|
|
204
|
+
lastQuestionToolId = null;
|
|
205
|
+
anyContentStreamed = false;
|
|
206
|
+
runStartEmitted = false;
|
|
207
|
+
terminalEmitted = false;
|
|
208
|
+
}
|
|
209
|
+
function emitContentBlockStart(f, out) {
|
|
210
|
+
const id = str(f, "id");
|
|
211
|
+
if (!id) return;
|
|
212
|
+
const kind = blockKindFromType(str(f, "block_type") ?? str(f, "type"));
|
|
213
|
+
const key = kind === "tool_use" ? `tool:${id}` : `block:${id}`;
|
|
214
|
+
if (open.has(key) || seen.has(key)) return;
|
|
215
|
+
blockKind.set(id, kind);
|
|
216
|
+
if (kind === "tool_use") {
|
|
217
|
+
const name = str(f, "name") ?? "";
|
|
218
|
+
if (name === ASK_USER_QUESTION) lastQuestionToolId = id;
|
|
219
|
+
else lastToolId = id;
|
|
220
|
+
open.add(key);
|
|
221
|
+
out.push({
|
|
222
|
+
type: "tool-input-start",
|
|
223
|
+
toolCallId: id,
|
|
224
|
+
toolName: name,
|
|
225
|
+
messageId: currentMessageId ?? "",
|
|
226
|
+
state: "input-streaming"
|
|
227
|
+
});
|
|
228
|
+
} else if (kind === "text" || kind === "reasoning" || kind === "plan") {
|
|
229
|
+
open.add(key);
|
|
230
|
+
if (kind === "text") activeTextBlockId = id;
|
|
231
|
+
anyContentStreamed = true;
|
|
232
|
+
out.push({
|
|
233
|
+
type: blockStartType[kind],
|
|
234
|
+
id,
|
|
235
|
+
messageId: currentMessageId ?? ""
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function emitContentBlockDelta(f, out) {
|
|
240
|
+
const id = str(f, "id");
|
|
241
|
+
if (!id) return;
|
|
242
|
+
const delta = obj(f, "delta");
|
|
243
|
+
if (!delta) return;
|
|
244
|
+
const dType = str(delta, "type");
|
|
245
|
+
if (dType === "input_json_delta") {
|
|
246
|
+
const key2 = `tool:${id}`;
|
|
247
|
+
if (seen.has(key2)) return;
|
|
248
|
+
const partial = str(delta, "partial_json") ?? "";
|
|
249
|
+
if (partial === "") return;
|
|
250
|
+
if (!open.has(key2)) {
|
|
251
|
+
open.add(key2);
|
|
252
|
+
blockKind.set(id, "tool_use");
|
|
253
|
+
}
|
|
254
|
+
out.push({
|
|
255
|
+
type: "tool-input-delta",
|
|
256
|
+
toolCallId: id,
|
|
257
|
+
inputTextDelta: partial,
|
|
258
|
+
state: "input-streaming"
|
|
259
|
+
});
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
let kind = null;
|
|
263
|
+
if (dType === "text_delta") kind = "text";
|
|
264
|
+
else if (dType === "thinking_delta" || dType === "reasoning_delta")
|
|
265
|
+
kind = "reasoning";
|
|
266
|
+
else if (dType === "plan_delta") kind = "plan";
|
|
267
|
+
if (!kind) return;
|
|
268
|
+
const key = `block:${id}`;
|
|
269
|
+
if (seen.has(key)) return;
|
|
270
|
+
const text = kind === "reasoning" ? str(delta, "thinking") ?? str(delta, "text") ?? "" : kind === "plan" ? str(delta, "text") ?? str(delta, "plan") ?? "" : str(delta, "text") ?? "";
|
|
271
|
+
if (text === "") return;
|
|
272
|
+
if (!open.has(key)) {
|
|
273
|
+
open.add(key);
|
|
274
|
+
blockKind.set(id, kind);
|
|
275
|
+
if (kind === "text") activeTextBlockId = id;
|
|
276
|
+
anyContentStreamed = true;
|
|
277
|
+
}
|
|
278
|
+
out.push({ type: blockDeltaType[kind], id, delta: text, messageId: currentMessageId ?? "" });
|
|
279
|
+
}
|
|
280
|
+
function emitContentBlockStop(f, out) {
|
|
281
|
+
const id = str(f, "id");
|
|
282
|
+
if (!id) return;
|
|
283
|
+
const kind = blockKind.get(id) ?? "other";
|
|
284
|
+
if (kind === "tool_use") {
|
|
285
|
+
seen.add(`tool:${id}`);
|
|
286
|
+
open.delete(`tool:${id}`);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (kind === "text" || kind === "reasoning" || kind === "plan") {
|
|
290
|
+
const key = `block:${id}`;
|
|
291
|
+
open.delete(key);
|
|
292
|
+
if (seen.has(key)) return;
|
|
293
|
+
seen.add(key);
|
|
294
|
+
if (activeTextBlockId === id) activeTextBlockId = null;
|
|
295
|
+
out.push({ type: blockEndType[kind], id, messageId: currentMessageId ?? "" });
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function emitMessageDelta(f, out) {
|
|
299
|
+
const delta = obj(f, "delta");
|
|
300
|
+
if (!delta) return;
|
|
301
|
+
const text = str(delta, "text") ?? "";
|
|
302
|
+
if (text === "" || !activeTextBlockId) return;
|
|
303
|
+
const key = `block:${activeTextBlockId}`;
|
|
304
|
+
if (seen.has(key)) return;
|
|
305
|
+
out.push({
|
|
306
|
+
type: "text-delta",
|
|
307
|
+
id: activeTextBlockId,
|
|
308
|
+
delta: text,
|
|
309
|
+
messageId: currentMessageId ?? ""
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
function emitStandaloneToolUse(f, out) {
|
|
313
|
+
const id = str(f, "id");
|
|
314
|
+
if (!id) return;
|
|
315
|
+
const name = str(f, "name") ?? "";
|
|
316
|
+
if (name === ASK_USER_QUESTION) lastQuestionToolId = id;
|
|
317
|
+
else if (name) lastToolId = id;
|
|
318
|
+
if ("input" in f) {
|
|
319
|
+
const key = `toolinput:${id}`;
|
|
320
|
+
if (seen.has(key)) return;
|
|
321
|
+
seen.add(key);
|
|
322
|
+
out.push({
|
|
323
|
+
type: "tool-input-available",
|
|
324
|
+
toolCallId: id,
|
|
325
|
+
toolName: name,
|
|
326
|
+
input: f["input"],
|
|
327
|
+
state: "input-available"
|
|
328
|
+
});
|
|
329
|
+
} else {
|
|
330
|
+
const partial = str(f, "input_text");
|
|
331
|
+
if (partial && !seen.has(`tool:${id}`)) {
|
|
332
|
+
out.push({
|
|
333
|
+
type: "tool-input-delta",
|
|
334
|
+
toolCallId: id,
|
|
335
|
+
inputTextDelta: partial,
|
|
336
|
+
state: "input-streaming"
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
function emitToolResult(f, out) {
|
|
342
|
+
const id = str(f, "tool_use_id");
|
|
343
|
+
if (!id) return;
|
|
344
|
+
const key = `tool_result:${id}`;
|
|
345
|
+
if (seen.has(key)) return;
|
|
346
|
+
seen.add(key);
|
|
347
|
+
const isError = bool(f, "is_error") ?? false;
|
|
348
|
+
const output = "content" in f ? f["content"] : f["result"];
|
|
349
|
+
out.push({
|
|
350
|
+
type: "tool-output-available",
|
|
351
|
+
toolCallId: id,
|
|
352
|
+
output,
|
|
353
|
+
isError,
|
|
354
|
+
state: isError ? "output-error" : "output-available"
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
function emitApprovalGate(f, out) {
|
|
358
|
+
const requestId = str(f, "request_id");
|
|
359
|
+
if (!requestId) return;
|
|
360
|
+
const toolName = str(f, "tool_name") ?? "";
|
|
361
|
+
const timeoutSeconds = num(f, "timeout_seconds") ?? 0;
|
|
362
|
+
const toolInput = f["tool_input"];
|
|
363
|
+
if (toolName === ASK_USER_QUESTION) {
|
|
364
|
+
const key = `question:${requestId}`;
|
|
365
|
+
if (seen.has(key)) return;
|
|
366
|
+
seen.add(key);
|
|
367
|
+
const ti = obj(f, "tool_input");
|
|
368
|
+
const questions = ((ti && arr(ti, "questions")) ?? []).flatMap((q) => {
|
|
369
|
+
if (q === null || typeof q !== "object") return [];
|
|
370
|
+
const qq = q;
|
|
371
|
+
const options = (arr(qq, "options") ?? []).flatMap((o) => {
|
|
372
|
+
if (typeof o === "string") return [{ label: o }];
|
|
373
|
+
if (o === null || typeof o !== "object") return [];
|
|
374
|
+
const label = str(o, "label");
|
|
375
|
+
if (!label) return [];
|
|
376
|
+
const description = str(o, "description");
|
|
377
|
+
return [description === void 0 ? { label } : { label, description }];
|
|
378
|
+
});
|
|
379
|
+
return [{ ...qq, question: str(qq, "question") ?? "", options }];
|
|
380
|
+
});
|
|
381
|
+
out.push({
|
|
382
|
+
type: "question",
|
|
383
|
+
requestId,
|
|
384
|
+
toolCallId: str(f, "tool_use_id") ?? lastQuestionToolId ?? "",
|
|
385
|
+
questions,
|
|
386
|
+
timeoutSeconds
|
|
387
|
+
});
|
|
388
|
+
} else {
|
|
389
|
+
const key = `approval:${requestId}`;
|
|
390
|
+
if (seen.has(key)) return;
|
|
391
|
+
seen.add(key);
|
|
392
|
+
out.push({
|
|
393
|
+
type: "approval-request",
|
|
394
|
+
requestId,
|
|
395
|
+
// The frame's own tool_use_id is authoritative (live awaiting_approval
|
|
396
|
+
// carries it; rejoin permission_request does too as of the run_join
|
|
397
|
+
// fix). The last-tool inference is only a fallback — with PARALLEL tool
|
|
398
|
+
// calls it can name the wrong tool.
|
|
399
|
+
toolCallId: str(f, "tool_use_id") ?? lastToolId ?? void 0,
|
|
400
|
+
toolName,
|
|
401
|
+
toolInput,
|
|
402
|
+
timeoutSeconds
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
function emitSnapshot(f, out) {
|
|
407
|
+
const messageId = str(f, "message_id") ?? currentMessageId ?? "";
|
|
408
|
+
const blocks = arr(f, "content_blocks") ?? [];
|
|
409
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
410
|
+
const raw = blocks[i];
|
|
411
|
+
if (raw === null || typeof raw !== "object") continue;
|
|
412
|
+
const b = raw;
|
|
413
|
+
const bType = str(b, "type");
|
|
414
|
+
const kind = blockKindFromType(bType);
|
|
415
|
+
if (kind === "text" || kind === "reasoning" || kind === "plan") {
|
|
416
|
+
let id = str(b, "id");
|
|
417
|
+
if (!id) {
|
|
418
|
+
if (anyContentStreamed) continue;
|
|
419
|
+
id = `${messageId}:snap:${i}`;
|
|
420
|
+
}
|
|
421
|
+
const key = `block:${id}`;
|
|
422
|
+
if (seen.has(key)) continue;
|
|
423
|
+
if (open.has(key)) {
|
|
424
|
+
open.delete(key);
|
|
425
|
+
seen.add(key);
|
|
426
|
+
if (activeTextBlockId === id) activeTextBlockId = null;
|
|
427
|
+
out.push({ type: blockEndType[kind], id, messageId });
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
seen.add(key);
|
|
431
|
+
out.push({ type: blockStartType[kind], id, messageId });
|
|
432
|
+
const text = kind === "reasoning" ? str(b, "thinking") ?? str(b, "text") ?? "" : kind === "plan" ? str(b, "plan") ?? str(b, "text") ?? "" : str(b, "text") ?? "";
|
|
433
|
+
if (text !== "") out.push({ type: blockDeltaType[kind], id, delta: text, messageId });
|
|
434
|
+
out.push({ type: blockEndType[kind], id, messageId });
|
|
435
|
+
} else if (bType === "tool_use") {
|
|
436
|
+
const id = str(b, "id");
|
|
437
|
+
if (!id || seen.has(`toolinput:${id}`)) continue;
|
|
438
|
+
seen.add(`toolinput:${id}`);
|
|
439
|
+
out.push({
|
|
440
|
+
type: "tool-input-available",
|
|
441
|
+
toolCallId: id,
|
|
442
|
+
toolName: str(b, "name") ?? "",
|
|
443
|
+
input: b["input"],
|
|
444
|
+
state: "input-available"
|
|
445
|
+
});
|
|
446
|
+
} else if (bType === "tool_result") {
|
|
447
|
+
const id = str(b, "tool_use_id");
|
|
448
|
+
if (!id || seen.has(`tool_result:${id}`)) continue;
|
|
449
|
+
seen.add(`tool_result:${id}`);
|
|
450
|
+
const isError = bool(b, "is_error") ?? false;
|
|
451
|
+
out.push({
|
|
452
|
+
type: "tool-output-available",
|
|
453
|
+
toolCallId: id,
|
|
454
|
+
output: "content" in b ? b["content"] : b["result"],
|
|
455
|
+
isError,
|
|
456
|
+
state: isError ? "output-error" : "output-available"
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
function emitNotice(out, level, source, message, detail) {
|
|
462
|
+
out.push(detail === void 0 ? { type: "notice", level, source, message } : { type: "notice", level, source, message, detail });
|
|
463
|
+
}
|
|
464
|
+
function handle(frame, out) {
|
|
465
|
+
const type = str(frame, "type") ?? "";
|
|
466
|
+
switch (type) {
|
|
467
|
+
/* ---- dropped no-ops ---- */
|
|
468
|
+
case "keep-alive":
|
|
469
|
+
case "ping":
|
|
470
|
+
case "RUNNER_DIAG":
|
|
471
|
+
case "sdk_init":
|
|
472
|
+
case "sandbox_metrics":
|
|
473
|
+
return;
|
|
474
|
+
/* ---- run lifecycle ---- */
|
|
475
|
+
case "metadata": {
|
|
476
|
+
if (runStartEmitted) return;
|
|
477
|
+
runStartEmitted = true;
|
|
478
|
+
const sandboxId = str(frame, "sandbox_id") ?? null;
|
|
479
|
+
const sandboxEnabled = bool(frame, "sandbox_enabled") ?? false;
|
|
480
|
+
out.push({
|
|
481
|
+
type: "run-start",
|
|
482
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
483
|
+
runId: num(frame, "run_id") ?? null,
|
|
484
|
+
runUuid: str(frame, "run_uuid") ?? null,
|
|
485
|
+
mode: str(frame, "mode") === "task" ? "task" : "chat",
|
|
486
|
+
...str(frame, "agent_name") ? { agentName: str(frame, "agent_name") } : {},
|
|
487
|
+
...num(frame, "instance_id") !== void 0 ? { instanceId: num(frame, "instance_id") } : {},
|
|
488
|
+
...num(frame, "task_id") !== void 0 ? { taskId: num(frame, "task_id") } : {},
|
|
489
|
+
...str(frame, "status") ? { status: str(frame, "status") } : {},
|
|
490
|
+
sandbox: { id: sandboxId, enabled: sandboxEnabled }
|
|
491
|
+
});
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
case "run_metrics": {
|
|
495
|
+
out.push({
|
|
496
|
+
type: "run-metrics",
|
|
497
|
+
model: str(frame, "model") ?? "",
|
|
498
|
+
executionTimeMs: num(frame, "execution_time_ms") ?? 0,
|
|
499
|
+
inputTokens: num(frame, "input_tokens_used") ?? 0,
|
|
500
|
+
outputTokens: num(frame, "output_tokens_used") ?? 0,
|
|
501
|
+
costUsd: num(frame, "claude_token_cost_usd") ?? null,
|
|
502
|
+
sdkCostUsd: num(frame, "sdk_total_cost_usd") ?? null,
|
|
503
|
+
stopReason: str(frame, "stop_reason") ?? null,
|
|
504
|
+
completionState: str(frame, "completion_state") ?? "",
|
|
505
|
+
unresolvedToolUseIds: (arr(frame, "unresolved_tool_use_ids") ?? []).filter(
|
|
506
|
+
(x) => typeof x === "string"
|
|
507
|
+
),
|
|
508
|
+
messageCount: num(frame, "message_count") ?? 0,
|
|
509
|
+
...obj(frame, "diagnostics") ? { diagnostics: obj(frame, "diagnostics") } : {}
|
|
510
|
+
});
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
case "done": {
|
|
514
|
+
if (terminalEmitted) return;
|
|
515
|
+
terminalEmitted = true;
|
|
516
|
+
const completionState = str(frame, "completion_state") ?? "complete";
|
|
517
|
+
out.push({
|
|
518
|
+
type: "run-finish",
|
|
519
|
+
status: completionState === "complete" ? "complete" : "incomplete",
|
|
520
|
+
completionState,
|
|
521
|
+
unresolvedToolUseIds: (arr(frame, "unresolved_tool_use_ids") ?? []).filter(
|
|
522
|
+
(x) => typeof x === "string"
|
|
523
|
+
),
|
|
524
|
+
stopReason: str(frame, "stop_reason") ?? null,
|
|
525
|
+
terminalCompletionSeen: bool(frame, "terminal_completion_seen") ?? false,
|
|
526
|
+
messageCount: num(frame, "message_count") ?? 0
|
|
527
|
+
});
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
case "cancelled": {
|
|
531
|
+
if (terminalEmitted) return;
|
|
532
|
+
terminalEmitted = true;
|
|
533
|
+
out.push({ type: "run-cancelled", runId: num(frame, "run_id") ?? null });
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
case "error":
|
|
537
|
+
case "AGENT_RUNNER_DIED":
|
|
538
|
+
case "RUNNER_LIFECYCLE_ERROR":
|
|
539
|
+
case "SANDBOX_BOOT_TIMEOUT":
|
|
540
|
+
case "SANDBOX_QUOTA_EXHAUSTED":
|
|
541
|
+
case "SANDBOX_UNAVAILABLE":
|
|
542
|
+
case "SNAPSHOT_VERSION_MISMATCH": {
|
|
543
|
+
if (terminalEmitted) return;
|
|
544
|
+
terminalEmitted = true;
|
|
545
|
+
const code = SANDBOX_ERROR_CODES.has(type) ? type : null;
|
|
546
|
+
out.push({
|
|
547
|
+
type: "run-error",
|
|
548
|
+
error: str(frame, "error") ?? str(frame, "message") ?? type,
|
|
549
|
+
message: str(frame, "message") ?? "Agent execution failed",
|
|
550
|
+
code,
|
|
551
|
+
fatal: true
|
|
552
|
+
});
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
case "sdk_error": {
|
|
556
|
+
emitNotice(out, "warning", "system", str(frame, "error") ?? "SDK error");
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
case "sdk_success": {
|
|
560
|
+
if (bool(frame, "is_error") !== true) {
|
|
561
|
+
out.push({ type: "unknown", wireType: type });
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
if (terminalEmitted) return;
|
|
565
|
+
terminalEmitted = true;
|
|
566
|
+
out.push({
|
|
567
|
+
type: "run-error",
|
|
568
|
+
error: str(frame, "subtype") ?? "sdk_error",
|
|
569
|
+
message: str(frame, "result") ?? "The model provider returned an error.",
|
|
570
|
+
code: null,
|
|
571
|
+
fatal: true
|
|
572
|
+
});
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
/* ---- message lifecycle ---- */
|
|
576
|
+
case "message_start": {
|
|
577
|
+
const msg = obj(frame, "message");
|
|
578
|
+
const id = (msg && str(msg, "id")) ?? str(frame, "message_id");
|
|
579
|
+
if (!id) return;
|
|
580
|
+
currentMessageId = id;
|
|
581
|
+
const key = `message:${id}`;
|
|
582
|
+
if (seen.has(key)) return;
|
|
583
|
+
seen.add(key);
|
|
584
|
+
const usage = msg && obj(msg, "usage");
|
|
585
|
+
out.push({
|
|
586
|
+
type: "message-start",
|
|
587
|
+
messageId: id,
|
|
588
|
+
role: "assistant",
|
|
589
|
+
...usage ? { usage: { inputTokens: num(usage, "input_tokens") ?? 0, outputTokens: num(usage, "output_tokens") ?? 0 } } : {}
|
|
590
|
+
});
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
case "message_stop":
|
|
594
|
+
case "message_complete": {
|
|
595
|
+
const id = str(frame, "message_id") ?? currentMessageId;
|
|
596
|
+
if (!id) return;
|
|
597
|
+
const key = `message:${id}:end`;
|
|
598
|
+
if (seen.has(key)) return;
|
|
599
|
+
seen.add(key);
|
|
600
|
+
const usage = obj(frame, "usage");
|
|
601
|
+
out.push({
|
|
602
|
+
type: "message-end",
|
|
603
|
+
messageId: id,
|
|
604
|
+
...usage ? { usage: { inputTokens: num(usage, "input_tokens") ?? 0, outputTokens: num(usage, "output_tokens") ?? 0 } } : {}
|
|
605
|
+
});
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
case "message_snapshot":
|
|
609
|
+
emitSnapshot(frame, out);
|
|
610
|
+
return;
|
|
611
|
+
/* ---- content blocks ---- */
|
|
612
|
+
case "content_block_start":
|
|
613
|
+
emitContentBlockStart(frame, out);
|
|
614
|
+
return;
|
|
615
|
+
case "content_block_delta":
|
|
616
|
+
emitContentBlockDelta(frame, out);
|
|
617
|
+
return;
|
|
618
|
+
case "content_block_stop":
|
|
619
|
+
emitContentBlockStop(frame, out);
|
|
620
|
+
return;
|
|
621
|
+
case "message_delta":
|
|
622
|
+
emitMessageDelta(frame, out);
|
|
623
|
+
return;
|
|
624
|
+
/* ---- tools ---- */
|
|
625
|
+
case "tool_use":
|
|
626
|
+
emitStandaloneToolUse(frame, out);
|
|
627
|
+
return;
|
|
628
|
+
case "tool_result":
|
|
629
|
+
emitToolResult(frame, out);
|
|
630
|
+
return;
|
|
631
|
+
/* ---- standalone reasoning / plan: passthrough as `unknown` for v1 ----
|
|
632
|
+
* These top-level (non-content_block) frames carry full content with no
|
|
633
|
+
* wire id, so they cannot be deduped across a rejoin and two bursts would
|
|
634
|
+
* collide on a synthetic id. Block-based reasoning (content_block
|
|
635
|
+
* reasoning_delta) is the dedupe-safe path and IS handled. Surface these
|
|
636
|
+
* raw until their real wire behavior is confirmed (CONTRACT.md open Q). */
|
|
637
|
+
/* ---- HITL ---- */
|
|
638
|
+
case "awaiting_approval":
|
|
639
|
+
case "permission_request":
|
|
640
|
+
emitApprovalGate(frame, out);
|
|
641
|
+
return;
|
|
642
|
+
/* ---- sandbox + notices ---- */
|
|
643
|
+
case "sandbox-connecting":
|
|
644
|
+
out.push({
|
|
645
|
+
type: "sandbox-status",
|
|
646
|
+
phase: "connecting",
|
|
647
|
+
message: str(frame, "message") ?? "Connecting to sandbox",
|
|
648
|
+
runId: num(frame, "run_id") ?? null
|
|
649
|
+
});
|
|
650
|
+
return;
|
|
651
|
+
case "sandbox-connected":
|
|
652
|
+
out.push({
|
|
653
|
+
type: "sandbox-status",
|
|
654
|
+
phase: "connected",
|
|
655
|
+
message: str(frame, "message") ?? "Connected to sandbox",
|
|
656
|
+
runId: num(frame, "run_id") ?? null,
|
|
657
|
+
...str(frame, "sandbox_id") !== void 0 ? { sandboxId: str(frame, "sandbox_id") } : {},
|
|
658
|
+
...num(frame, "duration_ms") !== void 0 ? { durationMs: num(frame, "duration_ms") } : {}
|
|
659
|
+
});
|
|
660
|
+
return;
|
|
661
|
+
case "stderr":
|
|
662
|
+
emitNotice(out, "info", "stderr", str(frame, "message") ?? "");
|
|
663
|
+
return;
|
|
664
|
+
case "mcp_error":
|
|
665
|
+
case "mcp_auth_failed":
|
|
666
|
+
emitNotice(out, "warning", "mcp", str(frame, "message") ?? str(frame, "error") ?? "MCP error", str(frame, "detail"));
|
|
667
|
+
return;
|
|
668
|
+
case "rate_limit": {
|
|
669
|
+
const info = obj(frame, "rate_limit_info");
|
|
670
|
+
const status = (info && str(info, "status")) ?? "allowed";
|
|
671
|
+
emitNotice(out, status === "rejected" ? "warning" : "info", "rate_limit", `Rate limit: ${status}`);
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
case "compact_boundary":
|
|
675
|
+
out.push({
|
|
676
|
+
type: "compact-boundary",
|
|
677
|
+
trigger: str(frame, "trigger") === "manual" ? "manual" : "auto",
|
|
678
|
+
preTokens: num(frame, "pre_tokens") ?? 0
|
|
679
|
+
});
|
|
680
|
+
return;
|
|
681
|
+
/* ---- passthrough ---- */
|
|
682
|
+
default:
|
|
683
|
+
out.push({ type: "unknown", wireType: type });
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return {
|
|
688
|
+
push(frame) {
|
|
689
|
+
const partials = [];
|
|
690
|
+
handle(frame, partials);
|
|
691
|
+
return partials.map(
|
|
692
|
+
(e) => ({ ...e, seq: seq++, raw: frame })
|
|
693
|
+
);
|
|
694
|
+
},
|
|
695
|
+
reset
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// src/protocol/accumulator.ts
|
|
700
|
+
var initialConversationState = {
|
|
701
|
+
runId: null,
|
|
702
|
+
runUuid: null,
|
|
703
|
+
agentName: null,
|
|
704
|
+
status: "idle",
|
|
705
|
+
messages: [],
|
|
706
|
+
pendingApproval: null,
|
|
707
|
+
pendingQuestion: null,
|
|
708
|
+
finishStopReason: null,
|
|
709
|
+
error: null
|
|
710
|
+
};
|
|
711
|
+
function lastAssistantIndex(messages) {
|
|
712
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
713
|
+
if (messages[i].role === "assistant") return i;
|
|
714
|
+
}
|
|
715
|
+
return -1;
|
|
716
|
+
}
|
|
717
|
+
function withMessageParts(state, messageId, role, fn) {
|
|
718
|
+
const messages = state.messages.slice();
|
|
719
|
+
let idx = messageId ? messages.findIndex((m) => m.id === messageId) : lastAssistantIndex(messages);
|
|
720
|
+
if (idx === -1) {
|
|
721
|
+
messages.push({ id: messageId || `m:${messages.length}`, role, parts: [] });
|
|
722
|
+
idx = messages.length - 1;
|
|
723
|
+
}
|
|
724
|
+
const msg = messages[idx];
|
|
725
|
+
messages[idx] = { ...msg, parts: fn(msg.parts) };
|
|
726
|
+
return { ...state, messages };
|
|
727
|
+
}
|
|
728
|
+
var isTextLike = (p) => p.kind === "text" || p.kind === "reasoning" || p.kind === "plan";
|
|
729
|
+
function ensureTextPart(parts, kind, id) {
|
|
730
|
+
if (parts.some((p) => isTextLike(p) && p.id === id)) return parts;
|
|
731
|
+
return [...parts, { kind, id, text: "" }];
|
|
732
|
+
}
|
|
733
|
+
function applyTextDelta(parts, kind, id, delta) {
|
|
734
|
+
const i = parts.findIndex((p2) => isTextLike(p2) && p2.id === id);
|
|
735
|
+
if (i === -1) return [...parts, { kind, id, text: delta }];
|
|
736
|
+
const p = parts[i];
|
|
737
|
+
const next = parts.slice();
|
|
738
|
+
next[i] = { ...p, text: p.text + delta };
|
|
739
|
+
return next;
|
|
740
|
+
}
|
|
741
|
+
function updateToolPart(state, toolCallId, toolName, patch) {
|
|
742
|
+
const messages = state.messages.slice();
|
|
743
|
+
for (let mi = 0; mi < messages.length; mi++) {
|
|
744
|
+
const parts = messages[mi].parts;
|
|
745
|
+
const pi = parts.findIndex((p) => p.kind === "tool" && p.toolCallId === toolCallId);
|
|
746
|
+
if (pi !== -1) {
|
|
747
|
+
const np = parts.slice();
|
|
748
|
+
np[pi] = patch(parts[pi]);
|
|
749
|
+
messages[mi] = { ...messages[mi], parts: np };
|
|
750
|
+
return { ...state, messages };
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
let idx = lastAssistantIndex(messages);
|
|
754
|
+
if (idx === -1) {
|
|
755
|
+
messages.push({ id: `m:${messages.length}`, role: "assistant", parts: [] });
|
|
756
|
+
idx = messages.length - 1;
|
|
757
|
+
}
|
|
758
|
+
const base = {
|
|
759
|
+
kind: "tool",
|
|
760
|
+
toolCallId,
|
|
761
|
+
toolName: toolName ?? "",
|
|
762
|
+
state: "input-streaming",
|
|
763
|
+
inputText: ""
|
|
764
|
+
};
|
|
765
|
+
messages[idx] = { ...messages[idx], parts: [...messages[idx].parts, patch(base)] };
|
|
766
|
+
return { ...state, messages };
|
|
767
|
+
}
|
|
768
|
+
function resume(status) {
|
|
769
|
+
return status === "awaiting_approval" || status === "awaiting_input" ? "running" : status;
|
|
770
|
+
}
|
|
771
|
+
function accumulate(state, e) {
|
|
772
|
+
switch (e.type) {
|
|
773
|
+
case "run-start":
|
|
774
|
+
return {
|
|
775
|
+
...state,
|
|
776
|
+
runId: e.runId,
|
|
777
|
+
runUuid: e.runUuid,
|
|
778
|
+
agentName: e.agentName ?? state.agentName ?? null,
|
|
779
|
+
status: "running",
|
|
780
|
+
error: null,
|
|
781
|
+
// A retry re-drives the turn: the previous attempt's outcome row
|
|
782
|
+
// ("Response truncated", "Request declined") must not survive it.
|
|
783
|
+
finishStopReason: null
|
|
784
|
+
};
|
|
785
|
+
case "run-status":
|
|
786
|
+
return { ...state, status: e.status };
|
|
787
|
+
case "message-start":
|
|
788
|
+
return withMessageParts(state, e.messageId, e.role, (p) => p);
|
|
789
|
+
case "text-start":
|
|
790
|
+
return {
|
|
791
|
+
...withMessageParts(state, e.messageId, "assistant", (p) => ensureTextPart(p, "text", e.id)),
|
|
792
|
+
status: resume(state.status)
|
|
793
|
+
};
|
|
794
|
+
case "text-delta":
|
|
795
|
+
return {
|
|
796
|
+
...withMessageParts(state, e.messageId, "assistant", (p) => applyTextDelta(p, "text", e.id, e.delta)),
|
|
797
|
+
status: resume(state.status)
|
|
798
|
+
};
|
|
799
|
+
case "reasoning-start":
|
|
800
|
+
return withMessageParts(state, e.messageId, "assistant", (p) => ensureTextPart(p, "reasoning", e.id));
|
|
801
|
+
case "reasoning-delta":
|
|
802
|
+
return withMessageParts(state, e.messageId, "assistant", (p) => applyTextDelta(p, "reasoning", e.id, e.delta));
|
|
803
|
+
case "plan-start":
|
|
804
|
+
return withMessageParts(state, e.messageId, "assistant", (p) => ensureTextPart(p, "plan", e.id));
|
|
805
|
+
case "plan-delta":
|
|
806
|
+
return withMessageParts(state, e.messageId, "assistant", (p) => applyTextDelta(p, "plan", e.id, e.delta));
|
|
807
|
+
case "text-end":
|
|
808
|
+
case "reasoning-end":
|
|
809
|
+
case "plan-end":
|
|
810
|
+
case "message-end":
|
|
811
|
+
return state;
|
|
812
|
+
case "tool-input-start":
|
|
813
|
+
return {
|
|
814
|
+
...withMessageParts(
|
|
815
|
+
state,
|
|
816
|
+
e.messageId,
|
|
817
|
+
"assistant",
|
|
818
|
+
(p) => p.some((x) => x.kind === "tool" && x.toolCallId === e.toolCallId) ? p : [
|
|
819
|
+
...p,
|
|
820
|
+
{
|
|
821
|
+
kind: "tool",
|
|
822
|
+
toolCallId: e.toolCallId,
|
|
823
|
+
toolName: e.toolName,
|
|
824
|
+
state: "input-streaming",
|
|
825
|
+
inputText: ""
|
|
826
|
+
}
|
|
827
|
+
]
|
|
828
|
+
),
|
|
829
|
+
status: resume(state.status)
|
|
830
|
+
};
|
|
831
|
+
case "tool-input-delta":
|
|
832
|
+
return updateToolPart(state, e.toolCallId, void 0, (t) => ({
|
|
833
|
+
...t,
|
|
834
|
+
inputText: t.inputText + e.inputTextDelta,
|
|
835
|
+
state: "input-streaming"
|
|
836
|
+
}));
|
|
837
|
+
case "tool-input-available":
|
|
838
|
+
return updateToolPart(state, e.toolCallId, e.toolName, (t) => ({
|
|
839
|
+
...t,
|
|
840
|
+
input: e.input,
|
|
841
|
+
state: "input-available"
|
|
842
|
+
}));
|
|
843
|
+
case "tool-output-available": {
|
|
844
|
+
const s = updateToolPart(state, e.toolCallId, void 0, (t) => ({
|
|
845
|
+
...t,
|
|
846
|
+
output: e.output,
|
|
847
|
+
isError: e.isError,
|
|
848
|
+
state: e.state
|
|
849
|
+
}));
|
|
850
|
+
const pendingApproval = s.pendingApproval && s.pendingApproval.toolCallId === e.toolCallId ? null : s.pendingApproval;
|
|
851
|
+
const pendingQuestion = s.pendingQuestion && s.pendingQuestion.toolCallId === e.toolCallId ? null : s.pendingQuestion;
|
|
852
|
+
return { ...s, pendingApproval, pendingQuestion, status: resume(s.status) };
|
|
853
|
+
}
|
|
854
|
+
case "approval-request":
|
|
855
|
+
return { ...state, pendingApproval: e, status: "awaiting_approval" };
|
|
856
|
+
case "approval-resolved":
|
|
857
|
+
return state.pendingApproval && state.pendingApproval.requestId === e.requestId ? { ...state, pendingApproval: null } : state;
|
|
858
|
+
case "question":
|
|
859
|
+
return { ...state, pendingQuestion: e, status: "awaiting_input" };
|
|
860
|
+
case "run-finish":
|
|
861
|
+
return { ...state, status: e.status, pendingApproval: null, pendingQuestion: null };
|
|
862
|
+
case "run-error":
|
|
863
|
+
return {
|
|
864
|
+
...state,
|
|
865
|
+
status: "error",
|
|
866
|
+
error: {
|
|
867
|
+
message: e.message,
|
|
868
|
+
code: e.code,
|
|
869
|
+
...e.apiStatus !== void 0 ? { apiStatus: e.apiStatus } : {},
|
|
870
|
+
...e.apiDetails !== void 0 ? { apiDetails: e.apiDetails } : {}
|
|
871
|
+
},
|
|
872
|
+
pendingApproval: null,
|
|
873
|
+
pendingQuestion: null
|
|
874
|
+
};
|
|
875
|
+
case "run-cancelled":
|
|
876
|
+
return { ...state, status: "cancelled", pendingApproval: null, pendingQuestion: null };
|
|
877
|
+
case "sandbox-status": {
|
|
878
|
+
const withStatus = e.phase === "connecting" && state.status === "idle" ? { ...state, status: "connecting" } : state;
|
|
879
|
+
if (e.phase === "connecting") {
|
|
880
|
+
return withMessageParts(withStatus, "", "assistant", (p) => [
|
|
881
|
+
...p,
|
|
882
|
+
{ kind: "sandbox", id: `sb:${p.length}`, phase: "connecting" }
|
|
883
|
+
]);
|
|
884
|
+
}
|
|
885
|
+
const messages = withStatus.messages.slice();
|
|
886
|
+
for (let mi = messages.length - 1; mi >= 0; mi--) {
|
|
887
|
+
const parts = messages[mi].parts;
|
|
888
|
+
for (let pi = parts.length - 1; pi >= 0; pi--) {
|
|
889
|
+
const part = parts[pi];
|
|
890
|
+
if (part.kind === "sandbox" && part.phase === "connecting") {
|
|
891
|
+
const np = parts.slice();
|
|
892
|
+
np[pi] = { ...part, phase: "connected", ...e.durationMs !== void 0 ? { durationMs: e.durationMs } : {} };
|
|
893
|
+
messages[mi] = { ...messages[mi], parts: np };
|
|
894
|
+
return { ...withStatus, messages };
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
return withMessageParts(withStatus, "", "assistant", (p) => [
|
|
899
|
+
...p,
|
|
900
|
+
{ kind: "sandbox", id: `sb:${p.length}`, phase: "connected", ...e.durationMs !== void 0 ? { durationMs: e.durationMs } : {} }
|
|
901
|
+
]);
|
|
902
|
+
}
|
|
903
|
+
case "notice":
|
|
904
|
+
if (e.level !== "warning") return state;
|
|
905
|
+
return withMessageParts(state, "", "assistant", (p) => [
|
|
906
|
+
...p,
|
|
907
|
+
{ kind: "notice", id: `n:${p.length}`, level: e.level, source: e.source, message: e.message }
|
|
908
|
+
]);
|
|
909
|
+
case "compact-boundary":
|
|
910
|
+
return withMessageParts(state, "", "assistant", (p) => [
|
|
911
|
+
...p,
|
|
912
|
+
{ kind: "compact", id: `c:${p.length}`, trigger: e.trigger, preTokens: e.preTokens }
|
|
913
|
+
]);
|
|
914
|
+
case "run-metrics":
|
|
915
|
+
return e.stopReason === "refusal" || e.stopReason === "max_tokens" ? { ...state, finishStopReason: e.stopReason } : state;
|
|
916
|
+
case "unknown":
|
|
917
|
+
return state;
|
|
918
|
+
default:
|
|
919
|
+
return state;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
function createAccumulator() {
|
|
923
|
+
let state = initialConversationState;
|
|
924
|
+
return {
|
|
925
|
+
get state() {
|
|
926
|
+
return state;
|
|
927
|
+
},
|
|
928
|
+
apply(event) {
|
|
929
|
+
state = accumulate(state, event);
|
|
930
|
+
return state;
|
|
931
|
+
},
|
|
932
|
+
addUserMessage(text) {
|
|
933
|
+
const id = `u:${state.messages.length}`;
|
|
934
|
+
state = {
|
|
935
|
+
...state,
|
|
936
|
+
messages: [...state.messages, { id, role: "user", parts: [{ kind: "text", id, text }] }]
|
|
937
|
+
};
|
|
938
|
+
return state;
|
|
939
|
+
},
|
|
940
|
+
reset() {
|
|
941
|
+
state = initialConversationState;
|
|
942
|
+
}
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// src/protocol/errors.ts
|
|
947
|
+
var M8tesApiError = class extends Error {
|
|
948
|
+
type;
|
|
949
|
+
code;
|
|
950
|
+
status;
|
|
951
|
+
requestId;
|
|
952
|
+
details;
|
|
953
|
+
docUrl;
|
|
954
|
+
errorCode;
|
|
955
|
+
retryAfter;
|
|
956
|
+
constructor(message, f) {
|
|
957
|
+
super(message);
|
|
958
|
+
this.name = "M8tesApiError";
|
|
959
|
+
this.type = f.type;
|
|
960
|
+
this.code = f.code;
|
|
961
|
+
this.status = f.status;
|
|
962
|
+
this.requestId = f.requestId;
|
|
963
|
+
this.details = f.details;
|
|
964
|
+
this.docUrl = f.docUrl;
|
|
965
|
+
this.errorCode = f.errorCode;
|
|
966
|
+
this.retryAfter = f.retryAfter;
|
|
967
|
+
}
|
|
968
|
+
};
|
|
969
|
+
var ValidationError = class extends M8tesApiError {
|
|
970
|
+
constructor(message, f) {
|
|
971
|
+
super(message, f);
|
|
972
|
+
this.name = "ValidationError";
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
var AuthenticationError = class extends M8tesApiError {
|
|
976
|
+
constructor(message, f) {
|
|
977
|
+
super(message, f);
|
|
978
|
+
this.name = "AuthenticationError";
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
var BillingError = class extends M8tesApiError {
|
|
982
|
+
constructor(message, f) {
|
|
983
|
+
super(message, f);
|
|
984
|
+
this.name = "BillingError";
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
var PermissionDeniedError = class extends M8tesApiError {
|
|
988
|
+
constructor(message, f) {
|
|
989
|
+
super(message, f);
|
|
990
|
+
this.name = "PermissionDeniedError";
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
var NotFoundError = class extends M8tesApiError {
|
|
994
|
+
constructor(message, f) {
|
|
995
|
+
super(message, f);
|
|
996
|
+
this.name = "NotFoundError";
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
var ConflictError = class extends M8tesApiError {
|
|
1000
|
+
constructor(message, f) {
|
|
1001
|
+
super(message, f);
|
|
1002
|
+
this.name = "ConflictError";
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
var RunNotStreamingError = class extends ConflictError {
|
|
1006
|
+
constructor(message, f) {
|
|
1007
|
+
super(message, f);
|
|
1008
|
+
this.name = "RunNotStreamingError";
|
|
1009
|
+
}
|
|
1010
|
+
};
|
|
1011
|
+
var RateLimitError = class extends M8tesApiError {
|
|
1012
|
+
constructor(message, f) {
|
|
1013
|
+
super(message, f);
|
|
1014
|
+
this.name = "RateLimitError";
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
1017
|
+
var APIError = class extends M8tesApiError {
|
|
1018
|
+
constructor(message, f) {
|
|
1019
|
+
super(message, f);
|
|
1020
|
+
this.name = "APIError";
|
|
1021
|
+
}
|
|
1022
|
+
};
|
|
1023
|
+
var RunFailedError = class extends M8tesApiError {
|
|
1024
|
+
constructor(message, f) {
|
|
1025
|
+
super(message, f);
|
|
1026
|
+
this.name = "RunFailedError";
|
|
1027
|
+
}
|
|
1028
|
+
};
|
|
1029
|
+
var STATUS_MAP = {
|
|
1030
|
+
400: ValidationError,
|
|
1031
|
+
401: AuthenticationError,
|
|
1032
|
+
402: BillingError,
|
|
1033
|
+
403: PermissionDeniedError,
|
|
1034
|
+
404: NotFoundError,
|
|
1035
|
+
409: ConflictError,
|
|
1036
|
+
422: ValidationError,
|
|
1037
|
+
429: RateLimitError
|
|
1038
|
+
};
|
|
1039
|
+
function parseRetryAfter(raw) {
|
|
1040
|
+
if (!raw) return void 0;
|
|
1041
|
+
const seconds = Number(raw);
|
|
1042
|
+
return Number.isFinite(seconds) ? seconds : void 0;
|
|
1043
|
+
}
|
|
1044
|
+
function str2(o, key) {
|
|
1045
|
+
return typeof o[key] === "string" ? o[key] : void 0;
|
|
1046
|
+
}
|
|
1047
|
+
function parseErrorEnvelope(status, body, headers) {
|
|
1048
|
+
const e = body !== null && typeof body === "object" && "error" in body && typeof body.error === "object" ? body.error ?? {} : {};
|
|
1049
|
+
const details = e["details"];
|
|
1050
|
+
const errorCode = details !== null && typeof details === "object" ? str2(details, "error_code") : void 0;
|
|
1051
|
+
return {
|
|
1052
|
+
message: str2(e, "message") ?? `Request failed (${status})`,
|
|
1053
|
+
fields: {
|
|
1054
|
+
type: str2(e, "type") ?? "api_error",
|
|
1055
|
+
code: typeof e["code"] === "number" ? e["code"] : status,
|
|
1056
|
+
status,
|
|
1057
|
+
requestId: str2(e, "request_id") ?? headers?.get("x-request-id") ?? void 0,
|
|
1058
|
+
details,
|
|
1059
|
+
docUrl: str2(e, "doc_url"),
|
|
1060
|
+
errorCode,
|
|
1061
|
+
retryAfter: parseRetryAfter(headers?.get("retry-after"))
|
|
1062
|
+
}
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
function errorClassForStatus(status, opts = {}) {
|
|
1066
|
+
if (status === 409 && opts.conflictIsNotStreaming) return RunNotStreamingError;
|
|
1067
|
+
return STATUS_MAP[status] ?? APIError;
|
|
1068
|
+
}
|
|
1069
|
+
async function errorFromResponse(res, opts = {}) {
|
|
1070
|
+
let body;
|
|
1071
|
+
try {
|
|
1072
|
+
body = await res.json();
|
|
1073
|
+
} catch {
|
|
1074
|
+
body = void 0;
|
|
1075
|
+
}
|
|
1076
|
+
const { message, fields } = parseErrorEnvelope(res.status, body, res.headers);
|
|
1077
|
+
const Cls = errorClassForStatus(res.status, opts);
|
|
1078
|
+
return new Cls(message, fields);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
export { APIError, AuthenticationError, BillingError, ConflictError, M8tesApiError, NotFoundError, PROTOCOL_VERSION, PermissionDeniedError, RateLimitError, RunFailedError, RunNotStreamingError, TERMINAL_EVENT_TYPES, ValidationError, accumulate, createAccumulator, createNormalizer, createSseDecoder, errorClassForStatus, errorFromResponse, initialConversationState, isTerminalEvent, parseErrorEnvelope, parseRetryAfter, parseSse, splitConcatenatedJson };
|
|
1082
|
+
//# sourceMappingURL=chunk-UFQQNUFE.js.map
|
|
1083
|
+
//# sourceMappingURL=chunk-UFQQNUFE.js.map
|