@webless/agent 0.6.8 → 0.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-CXIKIQJL.js → chunk-U2SU2CGF.js} +294 -56
- package/dist/chunk-U2SU2CGF.js.map +1 -0
- package/dist/embed.cjs +302 -64
- package/dist/embed.cjs.map +1 -1
- package/dist/embed.js +1 -1
- package/dist/index.cjs +297 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +297 -59
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +302 -64
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-CXIKIQJL.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -268,6 +268,203 @@ function clearPersistedAgentSession(visitorSessionId, options) {
|
|
|
268
268
|
sessionStorage.removeItem(runtimeLastMessageKey(visitorSessionId, prefix));
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
+
// src/runtime/subagent-child-stream.ts
|
|
272
|
+
var INITIAL_RETRY_DELAY_MS = 100;
|
|
273
|
+
var MAX_RETRY_DELAY_MS = 2e3;
|
|
274
|
+
var MAX_CONSECUTIVE_RETRIES = 6;
|
|
275
|
+
function isRecord2(value) {
|
|
276
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
277
|
+
}
|
|
278
|
+
function parseError(value) {
|
|
279
|
+
if (!isRecord2(value)) return void 0;
|
|
280
|
+
const { code, message } = value;
|
|
281
|
+
if (typeof code !== "string" || typeof message !== "string") {
|
|
282
|
+
return void 0;
|
|
283
|
+
}
|
|
284
|
+
return { code, message };
|
|
285
|
+
}
|
|
286
|
+
function parseChildStreamEvent(value) {
|
|
287
|
+
if (!isRecord2(value) || typeof value.type !== "string") {
|
|
288
|
+
return { type: "other" };
|
|
289
|
+
}
|
|
290
|
+
if (value.type === "session.waiting" || value.type === "session.completed" || value.type === "session.failed") {
|
|
291
|
+
return { type: "session.boundary" };
|
|
292
|
+
}
|
|
293
|
+
if (value.type === "subagent.event" && isRecord2(value.data) && Object.hasOwn(value.data, "event")) {
|
|
294
|
+
return parseChildStreamEvent(value.data.event);
|
|
295
|
+
}
|
|
296
|
+
if (value.type === "subagent.called" && isRecord2(value.data)) {
|
|
297
|
+
const { childStreamPath } = value.data;
|
|
298
|
+
if (typeof childStreamPath === "string") {
|
|
299
|
+
return { childStreamPath, type: "subagent.called" };
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (value.type !== "action.result" || !isRecord2(value.data)) {
|
|
303
|
+
return { type: "other" };
|
|
304
|
+
}
|
|
305
|
+
const { data } = value;
|
|
306
|
+
if (data.status !== "completed" && data.status !== "failed" && data.status !== "rejected") {
|
|
307
|
+
return { type: "other" };
|
|
308
|
+
}
|
|
309
|
+
if (!isRecord2(data.result) || data.result.kind !== "tool-result") {
|
|
310
|
+
return { type: "other" };
|
|
311
|
+
}
|
|
312
|
+
const result = data.result;
|
|
313
|
+
if (typeof result.callId !== "string" || typeof result.toolName !== "string") {
|
|
314
|
+
return { type: "other" };
|
|
315
|
+
}
|
|
316
|
+
const error = parseError(data.error);
|
|
317
|
+
return {
|
|
318
|
+
type: "action.result",
|
|
319
|
+
hasOutput: Object.hasOwn(result, "output"),
|
|
320
|
+
result: {
|
|
321
|
+
callId: result.callId,
|
|
322
|
+
toolName: result.toolName,
|
|
323
|
+
status: data.status,
|
|
324
|
+
...Object.hasOwn(result, "output") ? { output: result.output } : {},
|
|
325
|
+
...error ? { error } : {}
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
async function* readNdjsonStream(body) {
|
|
330
|
+
const reader = body.getReader();
|
|
331
|
+
const decoder = new TextDecoder();
|
|
332
|
+
let buffer = "";
|
|
333
|
+
try {
|
|
334
|
+
while (true) {
|
|
335
|
+
const { done, value } = await reader.read();
|
|
336
|
+
buffer += decoder.decode(value, { stream: !done });
|
|
337
|
+
const lines = buffer.split("\n");
|
|
338
|
+
buffer = lines.pop() ?? "";
|
|
339
|
+
for (const line of lines) {
|
|
340
|
+
const trimmed2 = line.trim();
|
|
341
|
+
if (!trimmed2) continue;
|
|
342
|
+
try {
|
|
343
|
+
const parsed = JSON.parse(trimmed2);
|
|
344
|
+
yield parsed;
|
|
345
|
+
} catch {
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (done) break;
|
|
349
|
+
}
|
|
350
|
+
const trimmed = buffer.trim();
|
|
351
|
+
if (trimmed) {
|
|
352
|
+
try {
|
|
353
|
+
const parsed = JSON.parse(trimmed);
|
|
354
|
+
yield parsed;
|
|
355
|
+
} catch {
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
} finally {
|
|
359
|
+
reader.releaseLock();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function streamPathAt(path, streamIndex) {
|
|
363
|
+
if (streamIndex === 0) return path;
|
|
364
|
+
return `${path}${path.includes("?") ? "&" : "?"}startIndex=${streamIndex}`;
|
|
365
|
+
}
|
|
366
|
+
function abortableDelay(delayMs, signal) {
|
|
367
|
+
if (signal.aborted) return Promise.resolve();
|
|
368
|
+
return new Promise((resolve) => {
|
|
369
|
+
const finish = () => {
|
|
370
|
+
clearTimeout(timeout);
|
|
371
|
+
signal.removeEventListener("abort", finish);
|
|
372
|
+
resolve();
|
|
373
|
+
};
|
|
374
|
+
const timeout = setTimeout(finish, delayMs);
|
|
375
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
var SubagentChildStreamCoordinator = class {
|
|
379
|
+
constructor(client, handlers, parentSignal) {
|
|
380
|
+
this.client = client;
|
|
381
|
+
this.handlers = handlers;
|
|
382
|
+
this.parentSignal = parentSignal;
|
|
383
|
+
}
|
|
384
|
+
client;
|
|
385
|
+
handlers;
|
|
386
|
+
parentSignal;
|
|
387
|
+
controllers = /* @__PURE__ */ new Map();
|
|
388
|
+
tasks = /* @__PURE__ */ new Map();
|
|
389
|
+
begin(event) {
|
|
390
|
+
this.beginPath(event.data.childStreamPath);
|
|
391
|
+
}
|
|
392
|
+
async waitForAll() {
|
|
393
|
+
let observedTaskCount = -1;
|
|
394
|
+
while (observedTaskCount !== this.tasks.size) {
|
|
395
|
+
observedTaskCount = this.tasks.size;
|
|
396
|
+
await Promise.all(this.tasks.values());
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
abortAll() {
|
|
400
|
+
for (const controller of this.controllers.values()) controller.abort();
|
|
401
|
+
this.controllers.clear();
|
|
402
|
+
}
|
|
403
|
+
beginPath(childStreamPath) {
|
|
404
|
+
if (this.tasks.has(childStreamPath)) return;
|
|
405
|
+
const controller = new AbortController();
|
|
406
|
+
const abort = () => controller.abort();
|
|
407
|
+
if (this.parentSignal.aborted) {
|
|
408
|
+
controller.abort();
|
|
409
|
+
} else {
|
|
410
|
+
this.parentSignal.addEventListener("abort", abort, { once: true });
|
|
411
|
+
}
|
|
412
|
+
this.controllers.set(childStreamPath, controller);
|
|
413
|
+
const task = this.consume(childStreamPath, controller.signal).finally(
|
|
414
|
+
() => {
|
|
415
|
+
this.parentSignal.removeEventListener("abort", abort);
|
|
416
|
+
if (this.controllers.get(childStreamPath) === controller) {
|
|
417
|
+
this.controllers.delete(childStreamPath);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
);
|
|
421
|
+
this.tasks.set(childStreamPath, task);
|
|
422
|
+
}
|
|
423
|
+
async consume(path, signal) {
|
|
424
|
+
let streamIndex = 0;
|
|
425
|
+
let consecutiveRetries = 0;
|
|
426
|
+
let retryDelayMs = INITIAL_RETRY_DELAY_MS;
|
|
427
|
+
while (!signal.aborted && consecutiveRetries < MAX_CONSECUTIVE_RETRIES) {
|
|
428
|
+
let receivedEvent = false;
|
|
429
|
+
try {
|
|
430
|
+
const response = await this.client.fetch(
|
|
431
|
+
streamPathAt(path, streamIndex),
|
|
432
|
+
{
|
|
433
|
+
cache: "no-store",
|
|
434
|
+
signal
|
|
435
|
+
}
|
|
436
|
+
);
|
|
437
|
+
if (!response.ok || response.body === null) {
|
|
438
|
+
await response.body?.cancel().catch(() => {
|
|
439
|
+
});
|
|
440
|
+
throw new Error(`Child stream returned ${response.status}.`);
|
|
441
|
+
}
|
|
442
|
+
for await (const rawEvent of readNdjsonStream(response.body)) {
|
|
443
|
+
if (signal.aborted) return;
|
|
444
|
+
receivedEvent = true;
|
|
445
|
+
streamIndex += 1;
|
|
446
|
+
const event = parseChildStreamEvent(rawEvent);
|
|
447
|
+
if (event.type === "session.boundary") return;
|
|
448
|
+
if (event.type === "subagent.called") {
|
|
449
|
+
this.beginPath(event.childStreamPath);
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
if (event.type !== "action.result") continue;
|
|
453
|
+
this.handlers.onToolResult?.(event.result);
|
|
454
|
+
if (event.hasOutput) {
|
|
455
|
+
this.handlers.onActionResult?.(event.result.output);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
} catch {
|
|
459
|
+
if (signal.aborted) return;
|
|
460
|
+
}
|
|
461
|
+
consecutiveRetries = receivedEvent ? 0 : consecutiveRetries + 1;
|
|
462
|
+
retryDelayMs = receivedEvent ? INITIAL_RETRY_DELAY_MS : Math.min(retryDelayMs * 2, MAX_RETRY_DELAY_MS);
|
|
463
|
+
await abortableDelay(retryDelayMs, signal);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
|
|
271
468
|
// src/runtime/tool-ui.ts
|
|
272
469
|
var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
|
|
273
470
|
var AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION = "webless.structured-tool-input.v1";
|
|
@@ -281,7 +478,7 @@ function formatAgentStructuredToolInput(surface, values) {
|
|
|
281
478
|
};
|
|
282
479
|
return `${AGENT_STRUCTURED_TOOL_INPUT_HEADER} ${JSON.stringify(payload)}`;
|
|
283
480
|
}
|
|
284
|
-
function
|
|
481
|
+
function isRecord3(value) {
|
|
285
482
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
286
483
|
}
|
|
287
484
|
function isJsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -330,7 +527,7 @@ function isFieldKind(value) {
|
|
|
330
527
|
].includes(value);
|
|
331
528
|
}
|
|
332
529
|
function parseField(value) {
|
|
333
|
-
if (!
|
|
530
|
+
if (!isRecord3(value)) return null;
|
|
334
531
|
if (!hasOnlyKeys(value, [
|
|
335
532
|
"description",
|
|
336
533
|
"kind",
|
|
@@ -381,7 +578,7 @@ function parseField(value) {
|
|
|
381
578
|
if (!Array.isArray(value.options) || value.options.length > 100)
|
|
382
579
|
return null;
|
|
383
580
|
for (const option of value.options) {
|
|
384
|
-
if (!
|
|
581
|
+
if (!isRecord3(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
|
|
385
582
|
return null;
|
|
386
583
|
}
|
|
387
584
|
}
|
|
@@ -404,7 +601,7 @@ function parseField(value) {
|
|
|
404
601
|
};
|
|
405
602
|
}
|
|
406
603
|
function parseStep(value) {
|
|
407
|
-
if (!
|
|
604
|
+
if (!isRecord3(value)) return null;
|
|
408
605
|
if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
|
|
409
606
|
return null;
|
|
410
607
|
}
|
|
@@ -424,7 +621,7 @@ function parseStep(value) {
|
|
|
424
621
|
};
|
|
425
622
|
}
|
|
426
623
|
function parseAction(value) {
|
|
427
|
-
if (!
|
|
624
|
+
if (!isRecord3(value)) return null;
|
|
428
625
|
if (!hasOnlyKeys(value, ["id", "label"])) return null;
|
|
429
626
|
const label = boundedString(value.label, 80);
|
|
430
627
|
if (value.id !== "submit" && value.id !== "back" && value.id !== "next" && value.id !== "reset" || !label) {
|
|
@@ -436,7 +633,7 @@ function parseAction(value) {
|
|
|
436
633
|
};
|
|
437
634
|
}
|
|
438
635
|
function parseAgentToolUiSurface(value) {
|
|
439
|
-
if (!
|
|
636
|
+
if (!isRecord3(value) || value.schemaVersion !== AGENT_TOOL_UI_SCHEMA_VERSION)
|
|
440
637
|
return null;
|
|
441
638
|
if (!hasOnlyKeys(value, [
|
|
442
639
|
"actions",
|
|
@@ -474,7 +671,7 @@ function parseAgentToolUiSurface(value) {
|
|
|
474
671
|
if (value.operationId !== void 0 && !operationId) return null;
|
|
475
672
|
if (value.requestId !== void 0 && !requestId) return null;
|
|
476
673
|
if (value.submitLabel !== void 0 && !submitLabel) return null;
|
|
477
|
-
const values = value.values !== void 0 &&
|
|
674
|
+
const values = value.values !== void 0 && isRecord3(value.values) ? value.values : void 0;
|
|
478
675
|
if (value.values !== void 0) {
|
|
479
676
|
if (!values || !Object.values(values).every((item) => isJsonValue(item)))
|
|
480
677
|
return null;
|
|
@@ -740,11 +937,14 @@ var AgentSession = class {
|
|
|
740
937
|
clientHost;
|
|
741
938
|
session;
|
|
742
939
|
activeResponse;
|
|
940
|
+
childStreams;
|
|
743
941
|
capability;
|
|
744
942
|
getActiveSessionId() {
|
|
745
943
|
return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
|
|
746
944
|
}
|
|
747
945
|
reset() {
|
|
946
|
+
this.childStreams?.abortAll();
|
|
947
|
+
this.childStreams = void 0;
|
|
748
948
|
if (this.activeResponse) {
|
|
749
949
|
void this.activeResponse.cancel().catch(() => {
|
|
750
950
|
});
|
|
@@ -840,6 +1040,12 @@ var AgentSession = class {
|
|
|
840
1040
|
this.persistSessionCursor(session);
|
|
841
1041
|
}
|
|
842
1042
|
this.activeResponse = response;
|
|
1043
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1044
|
+
client,
|
|
1045
|
+
handlers,
|
|
1046
|
+
signal
|
|
1047
|
+
);
|
|
1048
|
+
this.childStreams = childStreams;
|
|
843
1049
|
let streamIndex = session?.state.streamIndex ?? 0;
|
|
844
1050
|
let rendered = "";
|
|
845
1051
|
const workItems = /* @__PURE__ */ new Map();
|
|
@@ -847,6 +1053,7 @@ var AgentSession = class {
|
|
|
847
1053
|
try {
|
|
848
1054
|
for await (const event of response) {
|
|
849
1055
|
if (signal.aborted) break;
|
|
1056
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
850
1057
|
if (event.type === "input.requested") requestedInput = true;
|
|
851
1058
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
852
1059
|
streamIndex += 1;
|
|
@@ -859,8 +1066,11 @@ var AgentSession = class {
|
|
|
859
1066
|
);
|
|
860
1067
|
}
|
|
861
1068
|
}
|
|
1069
|
+
await childStreams.waitForAll();
|
|
862
1070
|
} finally {
|
|
1071
|
+
childStreams.abortAll();
|
|
863
1072
|
this.activeResponse = void 0;
|
|
1073
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
864
1074
|
if (session) {
|
|
865
1075
|
this.persistSessionCursor(session);
|
|
866
1076
|
}
|
|
@@ -896,63 +1106,80 @@ var AgentSession = class {
|
|
|
896
1106
|
}
|
|
897
1107
|
let rendered = renderTurn(turnEvents);
|
|
898
1108
|
const workItems = /* @__PURE__ */ new Map();
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
}
|
|
911
|
-
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
912
|
-
streamIndex: snapshot.session.streamIndex
|
|
913
|
-
});
|
|
914
|
-
this.session = session;
|
|
915
|
-
this.persistSessionCursor(session);
|
|
916
|
-
let snapshotBoundary;
|
|
917
|
-
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
918
|
-
const event = turnEvents[index];
|
|
919
|
-
if (event && isTurnBoundary(event)) {
|
|
920
|
-
snapshotBoundary = event;
|
|
921
|
-
break;
|
|
1109
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1110
|
+
client,
|
|
1111
|
+
handlers,
|
|
1112
|
+
signal
|
|
1113
|
+
);
|
|
1114
|
+
this.childStreams = childStreams;
|
|
1115
|
+
try {
|
|
1116
|
+
for (const event of turnEvents) {
|
|
1117
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1118
|
+
applyWorkEvent(event, handlers, workItems);
|
|
1119
|
+
emitVisitorInteractionEvent(event, handlers);
|
|
922
1120
|
}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1121
|
+
if (rendered.startsWith(initialText)) {
|
|
1122
|
+
const missedText = rendered.slice(initialText.length);
|
|
1123
|
+
if (missedText) handlers.onDelta(missedText);
|
|
1124
|
+
} else if (initialText.startsWith(rendered)) {
|
|
1125
|
+
rendered = initialText;
|
|
1126
|
+
} else if (!initialText.startsWith(rendered)) {
|
|
1127
|
+
rendered = initialText + rendered;
|
|
1128
|
+
}
|
|
1129
|
+
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
1130
|
+
streamIndex: snapshot.session.streamIndex
|
|
1131
|
+
});
|
|
1132
|
+
this.session = session;
|
|
1133
|
+
this.persistSessionCursor(session);
|
|
1134
|
+
let snapshotBoundary;
|
|
1135
|
+
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
1136
|
+
const event = turnEvents[index];
|
|
1137
|
+
if (event && isTurnBoundary(event)) {
|
|
1138
|
+
snapshotBoundary = event;
|
|
1139
|
+
break;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
if (snapshotBoundary) {
|
|
1143
|
+
if (snapshotBoundary.type === "session.failed") {
|
|
1144
|
+
throw new Error(
|
|
1145
|
+
snapshotBoundary.data.message || snapshotBoundary.data.code
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
handlers.onComplete?.();
|
|
1149
|
+
await childStreams.waitForAll();
|
|
1150
|
+
if (!rendered.trim() && !hasInputRequest) {
|
|
1151
|
+
throw new Error("Empty response from runtime");
|
|
1152
|
+
}
|
|
1153
|
+
return rendered.trim();
|
|
1154
|
+
}
|
|
1155
|
+
let streamIndex = snapshot.session.streamIndex;
|
|
1156
|
+
for await (const event of session.stream({ signal })) {
|
|
1157
|
+
if (signal.aborted) break;
|
|
1158
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1159
|
+
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1160
|
+
streamIndex += 1;
|
|
1161
|
+
savePersistedAgentSession(
|
|
1162
|
+
this.visitorSessionId,
|
|
1163
|
+
session.state.sessionId,
|
|
1164
|
+
streamIndex,
|
|
1165
|
+
this.storeOptions
|
|
928
1166
|
);
|
|
1167
|
+
if (isTurnBoundary(event)) break;
|
|
929
1168
|
}
|
|
930
|
-
|
|
931
|
-
|
|
1169
|
+
await childStreams.waitForAll();
|
|
1170
|
+
session = client.sessions.attach(session.state.sessionId, {
|
|
1171
|
+
streamIndex
|
|
1172
|
+
});
|
|
1173
|
+
this.session = session;
|
|
1174
|
+
this.persistSessionCursor(session);
|
|
1175
|
+
if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
|
|
932
1176
|
throw new Error("Empty response from runtime");
|
|
933
1177
|
}
|
|
934
1178
|
return rendered.trim();
|
|
1179
|
+
} finally {
|
|
1180
|
+
childStreams.abortAll();
|
|
1181
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
935
1182
|
}
|
|
936
|
-
let streamIndex = snapshot.session.streamIndex;
|
|
937
|
-
for await (const event of session.stream({ signal })) {
|
|
938
|
-
if (signal.aborted) break;
|
|
939
|
-
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
940
|
-
streamIndex += 1;
|
|
941
|
-
savePersistedAgentSession(
|
|
942
|
-
this.visitorSessionId,
|
|
943
|
-
session.state.sessionId,
|
|
944
|
-
streamIndex,
|
|
945
|
-
this.storeOptions
|
|
946
|
-
);
|
|
947
|
-
if (isTurnBoundary(event)) break;
|
|
948
|
-
}
|
|
949
|
-
session = client.sessions.attach(session.state.sessionId, { streamIndex });
|
|
950
|
-
this.session = session;
|
|
951
|
-
this.persistSessionCursor(session);
|
|
952
|
-
if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
|
|
953
|
-
throw new Error("Empty response from runtime");
|
|
954
|
-
}
|
|
955
|
-
return rendered.trim();
|
|
956
1183
|
}
|
|
957
1184
|
async respondTurn(responses, signal, handlers) {
|
|
958
1185
|
const client = this.ensureClient();
|
|
@@ -973,6 +1200,12 @@ var AgentSession = class {
|
|
|
973
1200
|
() => session.respond(inputResponses, { signal })
|
|
974
1201
|
);
|
|
975
1202
|
this.activeResponse = response;
|
|
1203
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1204
|
+
client,
|
|
1205
|
+
handlers,
|
|
1206
|
+
signal
|
|
1207
|
+
);
|
|
1208
|
+
this.childStreams = childStreams;
|
|
976
1209
|
let streamIndex = session.state.streamIndex;
|
|
977
1210
|
let rendered = "";
|
|
978
1211
|
let requestedInput = false;
|
|
@@ -980,6 +1213,7 @@ var AgentSession = class {
|
|
|
980
1213
|
try {
|
|
981
1214
|
for await (const event of response) {
|
|
982
1215
|
if (signal.aborted) break;
|
|
1216
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
983
1217
|
if (event.type === "input.requested") requestedInput = true;
|
|
984
1218
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
985
1219
|
streamIndex += 1;
|
|
@@ -990,8 +1224,11 @@ var AgentSession = class {
|
|
|
990
1224
|
this.storeOptions
|
|
991
1225
|
);
|
|
992
1226
|
}
|
|
1227
|
+
await childStreams.waitForAll();
|
|
993
1228
|
} finally {
|
|
1229
|
+
childStreams.abortAll();
|
|
994
1230
|
this.activeResponse = void 0;
|
|
1231
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
995
1232
|
this.session = client.sessions.attach(session.state.sessionId, {
|
|
996
1233
|
streamIndex
|
|
997
1234
|
});
|
|
@@ -1003,6 +1240,7 @@ var AgentSession = class {
|
|
|
1003
1240
|
return rendered.trim();
|
|
1004
1241
|
}
|
|
1005
1242
|
cancelActive() {
|
|
1243
|
+
this.childStreams?.abortAll();
|
|
1006
1244
|
if (this.activeResponse) {
|
|
1007
1245
|
this.activeResponse.cancel().catch(() => {
|
|
1008
1246
|
});
|
|
@@ -1118,7 +1356,7 @@ var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1118
1356
|
"presentationKinds",
|
|
1119
1357
|
"ui"
|
|
1120
1358
|
]);
|
|
1121
|
-
function
|
|
1359
|
+
function isRecord4(value) {
|
|
1122
1360
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1123
1361
|
}
|
|
1124
1362
|
function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -1145,7 +1383,7 @@ function decodeEnvelope(value) {
|
|
|
1145
1383
|
}
|
|
1146
1384
|
function parseAgentToolResultEnvelope(value) {
|
|
1147
1385
|
const decoded = decodeEnvelope(value);
|
|
1148
|
-
if (!
|
|
1386
|
+
if (!isRecord4(decoded)) return null;
|
|
1149
1387
|
const keys = Object.keys(decoded);
|
|
1150
1388
|
if (keys.some((key) => !ENVELOPE_KEYS.has(key)) || decoded.schemaVersion !== "webless.tool-result.v1" || !isJsonValue2(decoded.output) || !Array.isArray(decoded.presentationKinds) || decoded.presentationKinds.length < 1 || decoded.presentationKinds.length > 16) {
|
|
1151
1389
|
return null;
|