@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/embed.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -309,6 +309,203 @@ function clearPersistedAgentSession(visitorSessionId, options) {
|
|
|
309
309
|
sessionStorage.removeItem(runtimeLastMessageKey(visitorSessionId, prefix));
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
+
// src/runtime/subagent-child-stream.ts
|
|
313
|
+
var INITIAL_RETRY_DELAY_MS = 100;
|
|
314
|
+
var MAX_RETRY_DELAY_MS = 2e3;
|
|
315
|
+
var MAX_CONSECUTIVE_RETRIES = 6;
|
|
316
|
+
function isRecord2(value) {
|
|
317
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
318
|
+
}
|
|
319
|
+
function parseError(value) {
|
|
320
|
+
if (!isRecord2(value)) return void 0;
|
|
321
|
+
const { code, message } = value;
|
|
322
|
+
if (typeof code !== "string" || typeof message !== "string") {
|
|
323
|
+
return void 0;
|
|
324
|
+
}
|
|
325
|
+
return { code, message };
|
|
326
|
+
}
|
|
327
|
+
function parseChildStreamEvent(value) {
|
|
328
|
+
if (!isRecord2(value) || typeof value.type !== "string") {
|
|
329
|
+
return { type: "other" };
|
|
330
|
+
}
|
|
331
|
+
if (value.type === "session.waiting" || value.type === "session.completed" || value.type === "session.failed") {
|
|
332
|
+
return { type: "session.boundary" };
|
|
333
|
+
}
|
|
334
|
+
if (value.type === "subagent.event" && isRecord2(value.data) && Object.hasOwn(value.data, "event")) {
|
|
335
|
+
return parseChildStreamEvent(value.data.event);
|
|
336
|
+
}
|
|
337
|
+
if (value.type === "subagent.called" && isRecord2(value.data)) {
|
|
338
|
+
const { childStreamPath } = value.data;
|
|
339
|
+
if (typeof childStreamPath === "string") {
|
|
340
|
+
return { childStreamPath, type: "subagent.called" };
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (value.type !== "action.result" || !isRecord2(value.data)) {
|
|
344
|
+
return { type: "other" };
|
|
345
|
+
}
|
|
346
|
+
const { data } = value;
|
|
347
|
+
if (data.status !== "completed" && data.status !== "failed" && data.status !== "rejected") {
|
|
348
|
+
return { type: "other" };
|
|
349
|
+
}
|
|
350
|
+
if (!isRecord2(data.result) || data.result.kind !== "tool-result") {
|
|
351
|
+
return { type: "other" };
|
|
352
|
+
}
|
|
353
|
+
const result = data.result;
|
|
354
|
+
if (typeof result.callId !== "string" || typeof result.toolName !== "string") {
|
|
355
|
+
return { type: "other" };
|
|
356
|
+
}
|
|
357
|
+
const error = parseError(data.error);
|
|
358
|
+
return {
|
|
359
|
+
type: "action.result",
|
|
360
|
+
hasOutput: Object.hasOwn(result, "output"),
|
|
361
|
+
result: {
|
|
362
|
+
callId: result.callId,
|
|
363
|
+
toolName: result.toolName,
|
|
364
|
+
status: data.status,
|
|
365
|
+
...Object.hasOwn(result, "output") ? { output: result.output } : {},
|
|
366
|
+
...error ? { error } : {}
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
async function* readNdjsonStream(body) {
|
|
371
|
+
const reader = body.getReader();
|
|
372
|
+
const decoder = new TextDecoder();
|
|
373
|
+
let buffer = "";
|
|
374
|
+
try {
|
|
375
|
+
while (true) {
|
|
376
|
+
const { done, value } = await reader.read();
|
|
377
|
+
buffer += decoder.decode(value, { stream: !done });
|
|
378
|
+
const lines = buffer.split("\n");
|
|
379
|
+
buffer = lines.pop() ?? "";
|
|
380
|
+
for (const line of lines) {
|
|
381
|
+
const trimmed2 = line.trim();
|
|
382
|
+
if (!trimmed2) continue;
|
|
383
|
+
try {
|
|
384
|
+
const parsed = JSON.parse(trimmed2);
|
|
385
|
+
yield parsed;
|
|
386
|
+
} catch {
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (done) break;
|
|
390
|
+
}
|
|
391
|
+
const trimmed = buffer.trim();
|
|
392
|
+
if (trimmed) {
|
|
393
|
+
try {
|
|
394
|
+
const parsed = JSON.parse(trimmed);
|
|
395
|
+
yield parsed;
|
|
396
|
+
} catch {
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
} finally {
|
|
400
|
+
reader.releaseLock();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
function streamPathAt(path, streamIndex) {
|
|
404
|
+
if (streamIndex === 0) return path;
|
|
405
|
+
return `${path}${path.includes("?") ? "&" : "?"}startIndex=${streamIndex}`;
|
|
406
|
+
}
|
|
407
|
+
function abortableDelay(delayMs, signal) {
|
|
408
|
+
if (signal.aborted) return Promise.resolve();
|
|
409
|
+
return new Promise((resolve) => {
|
|
410
|
+
const finish = () => {
|
|
411
|
+
clearTimeout(timeout);
|
|
412
|
+
signal.removeEventListener("abort", finish);
|
|
413
|
+
resolve();
|
|
414
|
+
};
|
|
415
|
+
const timeout = setTimeout(finish, delayMs);
|
|
416
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
var SubagentChildStreamCoordinator = class {
|
|
420
|
+
constructor(client, handlers, parentSignal) {
|
|
421
|
+
this.client = client;
|
|
422
|
+
this.handlers = handlers;
|
|
423
|
+
this.parentSignal = parentSignal;
|
|
424
|
+
}
|
|
425
|
+
client;
|
|
426
|
+
handlers;
|
|
427
|
+
parentSignal;
|
|
428
|
+
controllers = /* @__PURE__ */ new Map();
|
|
429
|
+
tasks = /* @__PURE__ */ new Map();
|
|
430
|
+
begin(event) {
|
|
431
|
+
this.beginPath(event.data.childStreamPath);
|
|
432
|
+
}
|
|
433
|
+
async waitForAll() {
|
|
434
|
+
let observedTaskCount = -1;
|
|
435
|
+
while (observedTaskCount !== this.tasks.size) {
|
|
436
|
+
observedTaskCount = this.tasks.size;
|
|
437
|
+
await Promise.all(this.tasks.values());
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
abortAll() {
|
|
441
|
+
for (const controller of this.controllers.values()) controller.abort();
|
|
442
|
+
this.controllers.clear();
|
|
443
|
+
}
|
|
444
|
+
beginPath(childStreamPath) {
|
|
445
|
+
if (this.tasks.has(childStreamPath)) return;
|
|
446
|
+
const controller = new AbortController();
|
|
447
|
+
const abort = () => controller.abort();
|
|
448
|
+
if (this.parentSignal.aborted) {
|
|
449
|
+
controller.abort();
|
|
450
|
+
} else {
|
|
451
|
+
this.parentSignal.addEventListener("abort", abort, { once: true });
|
|
452
|
+
}
|
|
453
|
+
this.controllers.set(childStreamPath, controller);
|
|
454
|
+
const task = this.consume(childStreamPath, controller.signal).finally(
|
|
455
|
+
() => {
|
|
456
|
+
this.parentSignal.removeEventListener("abort", abort);
|
|
457
|
+
if (this.controllers.get(childStreamPath) === controller) {
|
|
458
|
+
this.controllers.delete(childStreamPath);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
);
|
|
462
|
+
this.tasks.set(childStreamPath, task);
|
|
463
|
+
}
|
|
464
|
+
async consume(path, signal) {
|
|
465
|
+
let streamIndex = 0;
|
|
466
|
+
let consecutiveRetries = 0;
|
|
467
|
+
let retryDelayMs = INITIAL_RETRY_DELAY_MS;
|
|
468
|
+
while (!signal.aborted && consecutiveRetries < MAX_CONSECUTIVE_RETRIES) {
|
|
469
|
+
let receivedEvent = false;
|
|
470
|
+
try {
|
|
471
|
+
const response = await this.client.fetch(
|
|
472
|
+
streamPathAt(path, streamIndex),
|
|
473
|
+
{
|
|
474
|
+
cache: "no-store",
|
|
475
|
+
signal
|
|
476
|
+
}
|
|
477
|
+
);
|
|
478
|
+
if (!response.ok || response.body === null) {
|
|
479
|
+
await response.body?.cancel().catch(() => {
|
|
480
|
+
});
|
|
481
|
+
throw new Error(`Child stream returned ${response.status}.`);
|
|
482
|
+
}
|
|
483
|
+
for await (const rawEvent of readNdjsonStream(response.body)) {
|
|
484
|
+
if (signal.aborted) return;
|
|
485
|
+
receivedEvent = true;
|
|
486
|
+
streamIndex += 1;
|
|
487
|
+
const event = parseChildStreamEvent(rawEvent);
|
|
488
|
+
if (event.type === "session.boundary") return;
|
|
489
|
+
if (event.type === "subagent.called") {
|
|
490
|
+
this.beginPath(event.childStreamPath);
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
if (event.type !== "action.result") continue;
|
|
494
|
+
this.handlers.onToolResult?.(event.result);
|
|
495
|
+
if (event.hasOutput) {
|
|
496
|
+
this.handlers.onActionResult?.(event.result.output);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
} catch {
|
|
500
|
+
if (signal.aborted) return;
|
|
501
|
+
}
|
|
502
|
+
consecutiveRetries = receivedEvent ? 0 : consecutiveRetries + 1;
|
|
503
|
+
retryDelayMs = receivedEvent ? INITIAL_RETRY_DELAY_MS : Math.min(retryDelayMs * 2, MAX_RETRY_DELAY_MS);
|
|
504
|
+
await abortableDelay(retryDelayMs, signal);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
|
|
312
509
|
// src/runtime/tool-ui.ts
|
|
313
510
|
var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
|
|
314
511
|
var AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION = "webless.structured-tool-input.v1";
|
|
@@ -322,7 +519,7 @@ function formatAgentStructuredToolInput(surface, values) {
|
|
|
322
519
|
};
|
|
323
520
|
return `${AGENT_STRUCTURED_TOOL_INPUT_HEADER} ${JSON.stringify(payload)}`;
|
|
324
521
|
}
|
|
325
|
-
function
|
|
522
|
+
function isRecord3(value) {
|
|
326
523
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
327
524
|
}
|
|
328
525
|
function isJsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -371,7 +568,7 @@ function isFieldKind(value) {
|
|
|
371
568
|
].includes(value);
|
|
372
569
|
}
|
|
373
570
|
function parseField(value) {
|
|
374
|
-
if (!
|
|
571
|
+
if (!isRecord3(value)) return null;
|
|
375
572
|
if (!hasOnlyKeys(value, [
|
|
376
573
|
"description",
|
|
377
574
|
"kind",
|
|
@@ -422,7 +619,7 @@ function parseField(value) {
|
|
|
422
619
|
if (!Array.isArray(value.options) || value.options.length > 100)
|
|
423
620
|
return null;
|
|
424
621
|
for (const option of value.options) {
|
|
425
|
-
if (!
|
|
622
|
+
if (!isRecord3(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
|
|
426
623
|
return null;
|
|
427
624
|
}
|
|
428
625
|
}
|
|
@@ -445,7 +642,7 @@ function parseField(value) {
|
|
|
445
642
|
};
|
|
446
643
|
}
|
|
447
644
|
function parseStep(value) {
|
|
448
|
-
if (!
|
|
645
|
+
if (!isRecord3(value)) return null;
|
|
449
646
|
if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
|
|
450
647
|
return null;
|
|
451
648
|
}
|
|
@@ -465,7 +662,7 @@ function parseStep(value) {
|
|
|
465
662
|
};
|
|
466
663
|
}
|
|
467
664
|
function parseAction(value) {
|
|
468
|
-
if (!
|
|
665
|
+
if (!isRecord3(value)) return null;
|
|
469
666
|
if (!hasOnlyKeys(value, ["id", "label"])) return null;
|
|
470
667
|
const label = boundedString(value.label, 80);
|
|
471
668
|
if (value.id !== "submit" && value.id !== "back" && value.id !== "next" && value.id !== "reset" || !label) {
|
|
@@ -477,7 +674,7 @@ function parseAction(value) {
|
|
|
477
674
|
};
|
|
478
675
|
}
|
|
479
676
|
function parseAgentToolUiSurface(value) {
|
|
480
|
-
if (!
|
|
677
|
+
if (!isRecord3(value) || value.schemaVersion !== AGENT_TOOL_UI_SCHEMA_VERSION)
|
|
481
678
|
return null;
|
|
482
679
|
if (!hasOnlyKeys(value, [
|
|
483
680
|
"actions",
|
|
@@ -515,7 +712,7 @@ function parseAgentToolUiSurface(value) {
|
|
|
515
712
|
if (value.operationId !== void 0 && !operationId) return null;
|
|
516
713
|
if (value.requestId !== void 0 && !requestId) return null;
|
|
517
714
|
if (value.submitLabel !== void 0 && !submitLabel) return null;
|
|
518
|
-
const values = value.values !== void 0 &&
|
|
715
|
+
const values = value.values !== void 0 && isRecord3(value.values) ? value.values : void 0;
|
|
519
716
|
if (value.values !== void 0) {
|
|
520
717
|
if (!values || !Object.values(values).every((item) => isJsonValue(item)))
|
|
521
718
|
return null;
|
|
@@ -781,11 +978,14 @@ var AgentSession = class {
|
|
|
781
978
|
clientHost;
|
|
782
979
|
session;
|
|
783
980
|
activeResponse;
|
|
981
|
+
childStreams;
|
|
784
982
|
capability;
|
|
785
983
|
getActiveSessionId() {
|
|
786
984
|
return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
|
|
787
985
|
}
|
|
788
986
|
reset() {
|
|
987
|
+
this.childStreams?.abortAll();
|
|
988
|
+
this.childStreams = void 0;
|
|
789
989
|
if (this.activeResponse) {
|
|
790
990
|
void this.activeResponse.cancel().catch(() => {
|
|
791
991
|
});
|
|
@@ -881,6 +1081,12 @@ var AgentSession = class {
|
|
|
881
1081
|
this.persistSessionCursor(session);
|
|
882
1082
|
}
|
|
883
1083
|
this.activeResponse = response;
|
|
1084
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1085
|
+
client,
|
|
1086
|
+
handlers,
|
|
1087
|
+
signal
|
|
1088
|
+
);
|
|
1089
|
+
this.childStreams = childStreams;
|
|
884
1090
|
let streamIndex = session?.state.streamIndex ?? 0;
|
|
885
1091
|
let rendered = "";
|
|
886
1092
|
const workItems = /* @__PURE__ */ new Map();
|
|
@@ -888,6 +1094,7 @@ var AgentSession = class {
|
|
|
888
1094
|
try {
|
|
889
1095
|
for await (const event of response) {
|
|
890
1096
|
if (signal.aborted) break;
|
|
1097
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
891
1098
|
if (event.type === "input.requested") requestedInput = true;
|
|
892
1099
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
893
1100
|
streamIndex += 1;
|
|
@@ -900,8 +1107,11 @@ var AgentSession = class {
|
|
|
900
1107
|
);
|
|
901
1108
|
}
|
|
902
1109
|
}
|
|
1110
|
+
await childStreams.waitForAll();
|
|
903
1111
|
} finally {
|
|
1112
|
+
childStreams.abortAll();
|
|
904
1113
|
this.activeResponse = void 0;
|
|
1114
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
905
1115
|
if (session) {
|
|
906
1116
|
this.persistSessionCursor(session);
|
|
907
1117
|
}
|
|
@@ -937,63 +1147,80 @@ var AgentSession = class {
|
|
|
937
1147
|
}
|
|
938
1148
|
let rendered = renderTurn(turnEvents);
|
|
939
1149
|
const workItems = /* @__PURE__ */ new Map();
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
}
|
|
952
|
-
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
953
|
-
streamIndex: snapshot.session.streamIndex
|
|
954
|
-
});
|
|
955
|
-
this.session = session;
|
|
956
|
-
this.persistSessionCursor(session);
|
|
957
|
-
let snapshotBoundary;
|
|
958
|
-
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
959
|
-
const event = turnEvents[index];
|
|
960
|
-
if (event && isTurnBoundary(event)) {
|
|
961
|
-
snapshotBoundary = event;
|
|
962
|
-
break;
|
|
1150
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1151
|
+
client,
|
|
1152
|
+
handlers,
|
|
1153
|
+
signal
|
|
1154
|
+
);
|
|
1155
|
+
this.childStreams = childStreams;
|
|
1156
|
+
try {
|
|
1157
|
+
for (const event of turnEvents) {
|
|
1158
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1159
|
+
applyWorkEvent(event, handlers, workItems);
|
|
1160
|
+
emitVisitorInteractionEvent(event, handlers);
|
|
963
1161
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1162
|
+
if (rendered.startsWith(initialText)) {
|
|
1163
|
+
const missedText = rendered.slice(initialText.length);
|
|
1164
|
+
if (missedText) handlers.onDelta(missedText);
|
|
1165
|
+
} else if (initialText.startsWith(rendered)) {
|
|
1166
|
+
rendered = initialText;
|
|
1167
|
+
} else if (!initialText.startsWith(rendered)) {
|
|
1168
|
+
rendered = initialText + rendered;
|
|
1169
|
+
}
|
|
1170
|
+
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
1171
|
+
streamIndex: snapshot.session.streamIndex
|
|
1172
|
+
});
|
|
1173
|
+
this.session = session;
|
|
1174
|
+
this.persistSessionCursor(session);
|
|
1175
|
+
let snapshotBoundary;
|
|
1176
|
+
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
1177
|
+
const event = turnEvents[index];
|
|
1178
|
+
if (event && isTurnBoundary(event)) {
|
|
1179
|
+
snapshotBoundary = event;
|
|
1180
|
+
break;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
if (snapshotBoundary) {
|
|
1184
|
+
if (snapshotBoundary.type === "session.failed") {
|
|
1185
|
+
throw new Error(
|
|
1186
|
+
snapshotBoundary.data.message || snapshotBoundary.data.code
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
handlers.onComplete?.();
|
|
1190
|
+
await childStreams.waitForAll();
|
|
1191
|
+
if (!rendered.trim() && !hasInputRequest) {
|
|
1192
|
+
throw new Error("Empty response from runtime");
|
|
1193
|
+
}
|
|
1194
|
+
return rendered.trim();
|
|
1195
|
+
}
|
|
1196
|
+
let streamIndex = snapshot.session.streamIndex;
|
|
1197
|
+
for await (const event of session.stream({ signal })) {
|
|
1198
|
+
if (signal.aborted) break;
|
|
1199
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1200
|
+
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1201
|
+
streamIndex += 1;
|
|
1202
|
+
savePersistedAgentSession(
|
|
1203
|
+
this.visitorSessionId,
|
|
1204
|
+
session.state.sessionId,
|
|
1205
|
+
streamIndex,
|
|
1206
|
+
this.storeOptions
|
|
969
1207
|
);
|
|
1208
|
+
if (isTurnBoundary(event)) break;
|
|
970
1209
|
}
|
|
971
|
-
|
|
972
|
-
|
|
1210
|
+
await childStreams.waitForAll();
|
|
1211
|
+
session = client.sessions.attach(session.state.sessionId, {
|
|
1212
|
+
streamIndex
|
|
1213
|
+
});
|
|
1214
|
+
this.session = session;
|
|
1215
|
+
this.persistSessionCursor(session);
|
|
1216
|
+
if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
|
|
973
1217
|
throw new Error("Empty response from runtime");
|
|
974
1218
|
}
|
|
975
1219
|
return rendered.trim();
|
|
1220
|
+
} finally {
|
|
1221
|
+
childStreams.abortAll();
|
|
1222
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
976
1223
|
}
|
|
977
|
-
let streamIndex = snapshot.session.streamIndex;
|
|
978
|
-
for await (const event of session.stream({ signal })) {
|
|
979
|
-
if (signal.aborted) break;
|
|
980
|
-
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
981
|
-
streamIndex += 1;
|
|
982
|
-
savePersistedAgentSession(
|
|
983
|
-
this.visitorSessionId,
|
|
984
|
-
session.state.sessionId,
|
|
985
|
-
streamIndex,
|
|
986
|
-
this.storeOptions
|
|
987
|
-
);
|
|
988
|
-
if (isTurnBoundary(event)) break;
|
|
989
|
-
}
|
|
990
|
-
session = client.sessions.attach(session.state.sessionId, { streamIndex });
|
|
991
|
-
this.session = session;
|
|
992
|
-
this.persistSessionCursor(session);
|
|
993
|
-
if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
|
|
994
|
-
throw new Error("Empty response from runtime");
|
|
995
|
-
}
|
|
996
|
-
return rendered.trim();
|
|
997
1224
|
}
|
|
998
1225
|
async respondTurn(responses, signal, handlers) {
|
|
999
1226
|
const client = this.ensureClient();
|
|
@@ -1014,6 +1241,12 @@ var AgentSession = class {
|
|
|
1014
1241
|
() => session.respond(inputResponses, { signal })
|
|
1015
1242
|
);
|
|
1016
1243
|
this.activeResponse = response;
|
|
1244
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1245
|
+
client,
|
|
1246
|
+
handlers,
|
|
1247
|
+
signal
|
|
1248
|
+
);
|
|
1249
|
+
this.childStreams = childStreams;
|
|
1017
1250
|
let streamIndex = session.state.streamIndex;
|
|
1018
1251
|
let rendered = "";
|
|
1019
1252
|
let requestedInput = false;
|
|
@@ -1021,6 +1254,7 @@ var AgentSession = class {
|
|
|
1021
1254
|
try {
|
|
1022
1255
|
for await (const event of response) {
|
|
1023
1256
|
if (signal.aborted) break;
|
|
1257
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1024
1258
|
if (event.type === "input.requested") requestedInput = true;
|
|
1025
1259
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1026
1260
|
streamIndex += 1;
|
|
@@ -1031,8 +1265,11 @@ var AgentSession = class {
|
|
|
1031
1265
|
this.storeOptions
|
|
1032
1266
|
);
|
|
1033
1267
|
}
|
|
1268
|
+
await childStreams.waitForAll();
|
|
1034
1269
|
} finally {
|
|
1270
|
+
childStreams.abortAll();
|
|
1035
1271
|
this.activeResponse = void 0;
|
|
1272
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
1036
1273
|
this.session = client.sessions.attach(session.state.sessionId, {
|
|
1037
1274
|
streamIndex
|
|
1038
1275
|
});
|
|
@@ -1044,6 +1281,7 @@ var AgentSession = class {
|
|
|
1044
1281
|
return rendered.trim();
|
|
1045
1282
|
}
|
|
1046
1283
|
cancelActive() {
|
|
1284
|
+
this.childStreams?.abortAll();
|
|
1047
1285
|
if (this.activeResponse) {
|
|
1048
1286
|
this.activeResponse.cancel().catch(() => {
|
|
1049
1287
|
});
|
|
@@ -1159,7 +1397,7 @@ var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1159
1397
|
"presentationKinds",
|
|
1160
1398
|
"ui"
|
|
1161
1399
|
]);
|
|
1162
|
-
function
|
|
1400
|
+
function isRecord4(value) {
|
|
1163
1401
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1164
1402
|
}
|
|
1165
1403
|
function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -1186,7 +1424,7 @@ function decodeEnvelope(value) {
|
|
|
1186
1424
|
}
|
|
1187
1425
|
function parseAgentToolResultEnvelope(value) {
|
|
1188
1426
|
const decoded = decodeEnvelope(value);
|
|
1189
|
-
if (!
|
|
1427
|
+
if (!isRecord4(decoded)) return null;
|
|
1190
1428
|
const keys = Object.keys(decoded);
|
|
1191
1429
|
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) {
|
|
1192
1430
|
return null;
|