@webless/agent 0.6.7 → 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-U5IPERNA.js → chunk-U2SU2CGF.js} +302 -59
- package/dist/chunk-U2SU2CGF.js.map +1 -0
- package/dist/embed.cjs +310 -67
- package/dist/embed.cjs.map +1 -1
- package/dist/embed.js +1 -1
- package/dist/index.cjs +305 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +305 -62
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +310 -67
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-U5IPERNA.js.map +0 -1
package/dist/embed.cjs
CHANGED
|
@@ -407,6 +407,203 @@ function clearPersistedAgentSession(visitorSessionId, options) {
|
|
|
407
407
|
sessionStorage.removeItem(runtimeLastMessageKey(visitorSessionId, prefix));
|
|
408
408
|
}
|
|
409
409
|
|
|
410
|
+
// src/runtime/subagent-child-stream.ts
|
|
411
|
+
var INITIAL_RETRY_DELAY_MS = 100;
|
|
412
|
+
var MAX_RETRY_DELAY_MS = 2e3;
|
|
413
|
+
var MAX_CONSECUTIVE_RETRIES = 6;
|
|
414
|
+
function isRecord2(value) {
|
|
415
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
416
|
+
}
|
|
417
|
+
function parseError(value) {
|
|
418
|
+
if (!isRecord2(value)) return void 0;
|
|
419
|
+
const { code, message } = value;
|
|
420
|
+
if (typeof code !== "string" || typeof message !== "string") {
|
|
421
|
+
return void 0;
|
|
422
|
+
}
|
|
423
|
+
return { code, message };
|
|
424
|
+
}
|
|
425
|
+
function parseChildStreamEvent(value) {
|
|
426
|
+
if (!isRecord2(value) || typeof value.type !== "string") {
|
|
427
|
+
return { type: "other" };
|
|
428
|
+
}
|
|
429
|
+
if (value.type === "session.waiting" || value.type === "session.completed" || value.type === "session.failed") {
|
|
430
|
+
return { type: "session.boundary" };
|
|
431
|
+
}
|
|
432
|
+
if (value.type === "subagent.event" && isRecord2(value.data) && Object.hasOwn(value.data, "event")) {
|
|
433
|
+
return parseChildStreamEvent(value.data.event);
|
|
434
|
+
}
|
|
435
|
+
if (value.type === "subagent.called" && isRecord2(value.data)) {
|
|
436
|
+
const { childStreamPath } = value.data;
|
|
437
|
+
if (typeof childStreamPath === "string") {
|
|
438
|
+
return { childStreamPath, type: "subagent.called" };
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
if (value.type !== "action.result" || !isRecord2(value.data)) {
|
|
442
|
+
return { type: "other" };
|
|
443
|
+
}
|
|
444
|
+
const { data } = value;
|
|
445
|
+
if (data.status !== "completed" && data.status !== "failed" && data.status !== "rejected") {
|
|
446
|
+
return { type: "other" };
|
|
447
|
+
}
|
|
448
|
+
if (!isRecord2(data.result) || data.result.kind !== "tool-result") {
|
|
449
|
+
return { type: "other" };
|
|
450
|
+
}
|
|
451
|
+
const result = data.result;
|
|
452
|
+
if (typeof result.callId !== "string" || typeof result.toolName !== "string") {
|
|
453
|
+
return { type: "other" };
|
|
454
|
+
}
|
|
455
|
+
const error = parseError(data.error);
|
|
456
|
+
return {
|
|
457
|
+
type: "action.result",
|
|
458
|
+
hasOutput: Object.hasOwn(result, "output"),
|
|
459
|
+
result: {
|
|
460
|
+
callId: result.callId,
|
|
461
|
+
toolName: result.toolName,
|
|
462
|
+
status: data.status,
|
|
463
|
+
...Object.hasOwn(result, "output") ? { output: result.output } : {},
|
|
464
|
+
...error ? { error } : {}
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
async function* readNdjsonStream(body) {
|
|
469
|
+
const reader = body.getReader();
|
|
470
|
+
const decoder = new TextDecoder();
|
|
471
|
+
let buffer = "";
|
|
472
|
+
try {
|
|
473
|
+
while (true) {
|
|
474
|
+
const { done, value } = await reader.read();
|
|
475
|
+
buffer += decoder.decode(value, { stream: !done });
|
|
476
|
+
const lines = buffer.split("\n");
|
|
477
|
+
buffer = lines.pop() ?? "";
|
|
478
|
+
for (const line of lines) {
|
|
479
|
+
const trimmed2 = line.trim();
|
|
480
|
+
if (!trimmed2) continue;
|
|
481
|
+
try {
|
|
482
|
+
const parsed = JSON.parse(trimmed2);
|
|
483
|
+
yield parsed;
|
|
484
|
+
} catch {
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
if (done) break;
|
|
488
|
+
}
|
|
489
|
+
const trimmed = buffer.trim();
|
|
490
|
+
if (trimmed) {
|
|
491
|
+
try {
|
|
492
|
+
const parsed = JSON.parse(trimmed);
|
|
493
|
+
yield parsed;
|
|
494
|
+
} catch {
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
} finally {
|
|
498
|
+
reader.releaseLock();
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
function streamPathAt(path, streamIndex) {
|
|
502
|
+
if (streamIndex === 0) return path;
|
|
503
|
+
return `${path}${path.includes("?") ? "&" : "?"}startIndex=${streamIndex}`;
|
|
504
|
+
}
|
|
505
|
+
function abortableDelay(delayMs, signal) {
|
|
506
|
+
if (signal.aborted) return Promise.resolve();
|
|
507
|
+
return new Promise((resolve) => {
|
|
508
|
+
const finish = () => {
|
|
509
|
+
clearTimeout(timeout);
|
|
510
|
+
signal.removeEventListener("abort", finish);
|
|
511
|
+
resolve();
|
|
512
|
+
};
|
|
513
|
+
const timeout = setTimeout(finish, delayMs);
|
|
514
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
var SubagentChildStreamCoordinator = class {
|
|
518
|
+
constructor(client, handlers, parentSignal) {
|
|
519
|
+
this.client = client;
|
|
520
|
+
this.handlers = handlers;
|
|
521
|
+
this.parentSignal = parentSignal;
|
|
522
|
+
}
|
|
523
|
+
client;
|
|
524
|
+
handlers;
|
|
525
|
+
parentSignal;
|
|
526
|
+
controllers = /* @__PURE__ */ new Map();
|
|
527
|
+
tasks = /* @__PURE__ */ new Map();
|
|
528
|
+
begin(event) {
|
|
529
|
+
this.beginPath(event.data.childStreamPath);
|
|
530
|
+
}
|
|
531
|
+
async waitForAll() {
|
|
532
|
+
let observedTaskCount = -1;
|
|
533
|
+
while (observedTaskCount !== this.tasks.size) {
|
|
534
|
+
observedTaskCount = this.tasks.size;
|
|
535
|
+
await Promise.all(this.tasks.values());
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
abortAll() {
|
|
539
|
+
for (const controller of this.controllers.values()) controller.abort();
|
|
540
|
+
this.controllers.clear();
|
|
541
|
+
}
|
|
542
|
+
beginPath(childStreamPath) {
|
|
543
|
+
if (this.tasks.has(childStreamPath)) return;
|
|
544
|
+
const controller = new AbortController();
|
|
545
|
+
const abort = () => controller.abort();
|
|
546
|
+
if (this.parentSignal.aborted) {
|
|
547
|
+
controller.abort();
|
|
548
|
+
} else {
|
|
549
|
+
this.parentSignal.addEventListener("abort", abort, { once: true });
|
|
550
|
+
}
|
|
551
|
+
this.controllers.set(childStreamPath, controller);
|
|
552
|
+
const task = this.consume(childStreamPath, controller.signal).finally(
|
|
553
|
+
() => {
|
|
554
|
+
this.parentSignal.removeEventListener("abort", abort);
|
|
555
|
+
if (this.controllers.get(childStreamPath) === controller) {
|
|
556
|
+
this.controllers.delete(childStreamPath);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
);
|
|
560
|
+
this.tasks.set(childStreamPath, task);
|
|
561
|
+
}
|
|
562
|
+
async consume(path, signal) {
|
|
563
|
+
let streamIndex = 0;
|
|
564
|
+
let consecutiveRetries = 0;
|
|
565
|
+
let retryDelayMs = INITIAL_RETRY_DELAY_MS;
|
|
566
|
+
while (!signal.aborted && consecutiveRetries < MAX_CONSECUTIVE_RETRIES) {
|
|
567
|
+
let receivedEvent = false;
|
|
568
|
+
try {
|
|
569
|
+
const response = await this.client.fetch(
|
|
570
|
+
streamPathAt(path, streamIndex),
|
|
571
|
+
{
|
|
572
|
+
cache: "no-store",
|
|
573
|
+
signal
|
|
574
|
+
}
|
|
575
|
+
);
|
|
576
|
+
if (!response.ok || response.body === null) {
|
|
577
|
+
await response.body?.cancel().catch(() => {
|
|
578
|
+
});
|
|
579
|
+
throw new Error(`Child stream returned ${response.status}.`);
|
|
580
|
+
}
|
|
581
|
+
for await (const rawEvent of readNdjsonStream(response.body)) {
|
|
582
|
+
if (signal.aborted) return;
|
|
583
|
+
receivedEvent = true;
|
|
584
|
+
streamIndex += 1;
|
|
585
|
+
const event = parseChildStreamEvent(rawEvent);
|
|
586
|
+
if (event.type === "session.boundary") return;
|
|
587
|
+
if (event.type === "subagent.called") {
|
|
588
|
+
this.beginPath(event.childStreamPath);
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
if (event.type !== "action.result") continue;
|
|
592
|
+
this.handlers.onToolResult?.(event.result);
|
|
593
|
+
if (event.hasOutput) {
|
|
594
|
+
this.handlers.onActionResult?.(event.result.output);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
} catch {
|
|
598
|
+
if (signal.aborted) return;
|
|
599
|
+
}
|
|
600
|
+
consecutiveRetries = receivedEvent ? 0 : consecutiveRetries + 1;
|
|
601
|
+
retryDelayMs = receivedEvent ? INITIAL_RETRY_DELAY_MS : Math.min(retryDelayMs * 2, MAX_RETRY_DELAY_MS);
|
|
602
|
+
await abortableDelay(retryDelayMs, signal);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
|
|
410
607
|
// src/runtime/tool-ui.ts
|
|
411
608
|
var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
|
|
412
609
|
var AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION = "webless.structured-tool-input.v1";
|
|
@@ -420,7 +617,7 @@ function formatAgentStructuredToolInput(surface, values) {
|
|
|
420
617
|
};
|
|
421
618
|
return `${AGENT_STRUCTURED_TOOL_INPUT_HEADER} ${JSON.stringify(payload)}`;
|
|
422
619
|
}
|
|
423
|
-
function
|
|
620
|
+
function isRecord3(value) {
|
|
424
621
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
425
622
|
}
|
|
426
623
|
function isJsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -469,7 +666,7 @@ function isFieldKind(value) {
|
|
|
469
666
|
].includes(value);
|
|
470
667
|
}
|
|
471
668
|
function parseField(value) {
|
|
472
|
-
if (!
|
|
669
|
+
if (!isRecord3(value)) return null;
|
|
473
670
|
if (!hasOnlyKeys(value, [
|
|
474
671
|
"description",
|
|
475
672
|
"kind",
|
|
@@ -520,7 +717,7 @@ function parseField(value) {
|
|
|
520
717
|
if (!Array.isArray(value.options) || value.options.length > 100)
|
|
521
718
|
return null;
|
|
522
719
|
for (const option of value.options) {
|
|
523
|
-
if (!
|
|
720
|
+
if (!isRecord3(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
|
|
524
721
|
return null;
|
|
525
722
|
}
|
|
526
723
|
}
|
|
@@ -543,7 +740,7 @@ function parseField(value) {
|
|
|
543
740
|
};
|
|
544
741
|
}
|
|
545
742
|
function parseStep(value) {
|
|
546
|
-
if (!
|
|
743
|
+
if (!isRecord3(value)) return null;
|
|
547
744
|
if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
|
|
548
745
|
return null;
|
|
549
746
|
}
|
|
@@ -563,7 +760,7 @@ function parseStep(value) {
|
|
|
563
760
|
};
|
|
564
761
|
}
|
|
565
762
|
function parseAction(value) {
|
|
566
|
-
if (!
|
|
763
|
+
if (!isRecord3(value)) return null;
|
|
567
764
|
if (!hasOnlyKeys(value, ["id", "label"])) return null;
|
|
568
765
|
const label = boundedString(value.label, 80);
|
|
569
766
|
if (value.id !== "submit" && value.id !== "back" && value.id !== "next" && value.id !== "reset" || !label) {
|
|
@@ -575,7 +772,7 @@ function parseAction(value) {
|
|
|
575
772
|
};
|
|
576
773
|
}
|
|
577
774
|
function parseAgentToolUiSurface(value) {
|
|
578
|
-
if (!
|
|
775
|
+
if (!isRecord3(value) || value.schemaVersion !== AGENT_TOOL_UI_SCHEMA_VERSION)
|
|
579
776
|
return null;
|
|
580
777
|
if (!hasOnlyKeys(value, [
|
|
581
778
|
"actions",
|
|
@@ -613,7 +810,7 @@ function parseAgentToolUiSurface(value) {
|
|
|
613
810
|
if (value.operationId !== void 0 && !operationId) return null;
|
|
614
811
|
if (value.requestId !== void 0 && !requestId) return null;
|
|
615
812
|
if (value.submitLabel !== void 0 && !submitLabel) return null;
|
|
616
|
-
const values = value.values !== void 0 &&
|
|
813
|
+
const values = value.values !== void 0 && isRecord3(value.values) ? value.values : void 0;
|
|
617
814
|
if (value.values !== void 0) {
|
|
618
815
|
if (!values || !Object.values(values).every((item) => isJsonValue(item)))
|
|
619
816
|
return null;
|
|
@@ -650,8 +847,7 @@ function applyMessageEvent(event, rendered, handlers, workItems) {
|
|
|
650
847
|
if (event.type === "message.completed") {
|
|
651
848
|
handlers.onComplete?.();
|
|
652
849
|
}
|
|
653
|
-
|
|
654
|
-
if (event.type === "input.requested") emitInputRequests(event, handlers);
|
|
850
|
+
emitVisitorInteractionEvent(event, handlers);
|
|
655
851
|
if (event.type !== "message.appended") return rendered;
|
|
656
852
|
const { messageDelta, messageSoFar } = event.data;
|
|
657
853
|
let delta = messageDelta;
|
|
@@ -701,6 +897,13 @@ function emitInputRequests(event, handlers) {
|
|
|
701
897
|
})
|
|
702
898
|
);
|
|
703
899
|
}
|
|
900
|
+
function emitVisitorInteractionEvent(event, handlers) {
|
|
901
|
+
if (event.type === "action.result") emitActionResult(event, handlers);
|
|
902
|
+
if (event.type === "input.requested") emitInputRequests(event, handlers);
|
|
903
|
+
if (event.type === "subagent.event") {
|
|
904
|
+
emitVisitorInteractionEvent(event.data.event, handlers);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
704
907
|
function isResumeTurnMessage(received, candidate) {
|
|
705
908
|
if (received === candidate) return true;
|
|
706
909
|
return Boolean(candidate) && received.endsWith(`
|
|
@@ -873,11 +1076,14 @@ var AgentSession = class {
|
|
|
873
1076
|
clientHost;
|
|
874
1077
|
session;
|
|
875
1078
|
activeResponse;
|
|
1079
|
+
childStreams;
|
|
876
1080
|
capability;
|
|
877
1081
|
getActiveSessionId() {
|
|
878
1082
|
return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
|
|
879
1083
|
}
|
|
880
1084
|
reset() {
|
|
1085
|
+
this.childStreams?.abortAll();
|
|
1086
|
+
this.childStreams = void 0;
|
|
881
1087
|
if (this.activeResponse) {
|
|
882
1088
|
void this.activeResponse.cancel().catch(() => {
|
|
883
1089
|
});
|
|
@@ -973,6 +1179,12 @@ var AgentSession = class {
|
|
|
973
1179
|
this.persistSessionCursor(session);
|
|
974
1180
|
}
|
|
975
1181
|
this.activeResponse = response;
|
|
1182
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1183
|
+
client,
|
|
1184
|
+
handlers,
|
|
1185
|
+
signal
|
|
1186
|
+
);
|
|
1187
|
+
this.childStreams = childStreams;
|
|
976
1188
|
let streamIndex = session?.state.streamIndex ?? 0;
|
|
977
1189
|
let rendered = "";
|
|
978
1190
|
const workItems = /* @__PURE__ */ new Map();
|
|
@@ -980,6 +1192,7 @@ var AgentSession = class {
|
|
|
980
1192
|
try {
|
|
981
1193
|
for await (const event of response) {
|
|
982
1194
|
if (signal.aborted) break;
|
|
1195
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
983
1196
|
if (event.type === "input.requested") requestedInput = true;
|
|
984
1197
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
985
1198
|
streamIndex += 1;
|
|
@@ -992,8 +1205,11 @@ var AgentSession = class {
|
|
|
992
1205
|
);
|
|
993
1206
|
}
|
|
994
1207
|
}
|
|
1208
|
+
await childStreams.waitForAll();
|
|
995
1209
|
} finally {
|
|
1210
|
+
childStreams.abortAll();
|
|
996
1211
|
this.activeResponse = void 0;
|
|
1212
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
997
1213
|
if (session) {
|
|
998
1214
|
this.persistSessionCursor(session);
|
|
999
1215
|
}
|
|
@@ -1029,64 +1245,80 @@ var AgentSession = class {
|
|
|
1029
1245
|
}
|
|
1030
1246
|
let rendered = renderTurn(turnEvents);
|
|
1031
1247
|
const workItems = /* @__PURE__ */ new Map();
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
rendered = initialText + rendered;
|
|
1044
|
-
}
|
|
1045
|
-
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
1046
|
-
streamIndex: snapshot.session.streamIndex
|
|
1047
|
-
});
|
|
1048
|
-
this.session = session;
|
|
1049
|
-
this.persistSessionCursor(session);
|
|
1050
|
-
let snapshotBoundary;
|
|
1051
|
-
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
1052
|
-
const event = turnEvents[index];
|
|
1053
|
-
if (event && isTurnBoundary(event)) {
|
|
1054
|
-
snapshotBoundary = event;
|
|
1055
|
-
break;
|
|
1248
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1249
|
+
client,
|
|
1250
|
+
handlers,
|
|
1251
|
+
signal
|
|
1252
|
+
);
|
|
1253
|
+
this.childStreams = childStreams;
|
|
1254
|
+
try {
|
|
1255
|
+
for (const event of turnEvents) {
|
|
1256
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1257
|
+
applyWorkEvent(event, handlers, workItems);
|
|
1258
|
+
emitVisitorInteractionEvent(event, handlers);
|
|
1056
1259
|
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1260
|
+
if (rendered.startsWith(initialText)) {
|
|
1261
|
+
const missedText = rendered.slice(initialText.length);
|
|
1262
|
+
if (missedText) handlers.onDelta(missedText);
|
|
1263
|
+
} else if (initialText.startsWith(rendered)) {
|
|
1264
|
+
rendered = initialText;
|
|
1265
|
+
} else if (!initialText.startsWith(rendered)) {
|
|
1266
|
+
rendered = initialText + rendered;
|
|
1267
|
+
}
|
|
1268
|
+
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
1269
|
+
streamIndex: snapshot.session.streamIndex
|
|
1270
|
+
});
|
|
1271
|
+
this.session = session;
|
|
1272
|
+
this.persistSessionCursor(session);
|
|
1273
|
+
let snapshotBoundary;
|
|
1274
|
+
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
1275
|
+
const event = turnEvents[index];
|
|
1276
|
+
if (event && isTurnBoundary(event)) {
|
|
1277
|
+
snapshotBoundary = event;
|
|
1278
|
+
break;
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
if (snapshotBoundary) {
|
|
1282
|
+
if (snapshotBoundary.type === "session.failed") {
|
|
1283
|
+
throw new Error(
|
|
1284
|
+
snapshotBoundary.data.message || snapshotBoundary.data.code
|
|
1285
|
+
);
|
|
1286
|
+
}
|
|
1287
|
+
handlers.onComplete?.();
|
|
1288
|
+
await childStreams.waitForAll();
|
|
1289
|
+
if (!rendered.trim() && !hasInputRequest) {
|
|
1290
|
+
throw new Error("Empty response from runtime");
|
|
1291
|
+
}
|
|
1292
|
+
return rendered.trim();
|
|
1293
|
+
}
|
|
1294
|
+
let streamIndex = snapshot.session.streamIndex;
|
|
1295
|
+
for await (const event of session.stream({ signal })) {
|
|
1296
|
+
if (signal.aborted) break;
|
|
1297
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1298
|
+
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1299
|
+
streamIndex += 1;
|
|
1300
|
+
savePersistedAgentSession(
|
|
1301
|
+
this.visitorSessionId,
|
|
1302
|
+
session.state.sessionId,
|
|
1303
|
+
streamIndex,
|
|
1304
|
+
this.storeOptions
|
|
1062
1305
|
);
|
|
1306
|
+
if (isTurnBoundary(event)) break;
|
|
1063
1307
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1308
|
+
await childStreams.waitForAll();
|
|
1309
|
+
session = client.sessions.attach(session.state.sessionId, {
|
|
1310
|
+
streamIndex
|
|
1311
|
+
});
|
|
1312
|
+
this.session = session;
|
|
1313
|
+
this.persistSessionCursor(session);
|
|
1314
|
+
if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
|
|
1066
1315
|
throw new Error("Empty response from runtime");
|
|
1067
1316
|
}
|
|
1068
1317
|
return rendered.trim();
|
|
1318
|
+
} finally {
|
|
1319
|
+
childStreams.abortAll();
|
|
1320
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
1069
1321
|
}
|
|
1070
|
-
let streamIndex = snapshot.session.streamIndex;
|
|
1071
|
-
for await (const event of session.stream({ signal })) {
|
|
1072
|
-
if (signal.aborted) break;
|
|
1073
|
-
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1074
|
-
streamIndex += 1;
|
|
1075
|
-
savePersistedAgentSession(
|
|
1076
|
-
this.visitorSessionId,
|
|
1077
|
-
session.state.sessionId,
|
|
1078
|
-
streamIndex,
|
|
1079
|
-
this.storeOptions
|
|
1080
|
-
);
|
|
1081
|
-
if (isTurnBoundary(event)) break;
|
|
1082
|
-
}
|
|
1083
|
-
session = client.sessions.attach(session.state.sessionId, { streamIndex });
|
|
1084
|
-
this.session = session;
|
|
1085
|
-
this.persistSessionCursor(session);
|
|
1086
|
-
if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
|
|
1087
|
-
throw new Error("Empty response from runtime");
|
|
1088
|
-
}
|
|
1089
|
-
return rendered.trim();
|
|
1090
1322
|
}
|
|
1091
1323
|
async respondTurn(responses, signal, handlers) {
|
|
1092
1324
|
const client = this.ensureClient();
|
|
@@ -1107,6 +1339,12 @@ var AgentSession = class {
|
|
|
1107
1339
|
() => session.respond(inputResponses, { signal })
|
|
1108
1340
|
);
|
|
1109
1341
|
this.activeResponse = response;
|
|
1342
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1343
|
+
client,
|
|
1344
|
+
handlers,
|
|
1345
|
+
signal
|
|
1346
|
+
);
|
|
1347
|
+
this.childStreams = childStreams;
|
|
1110
1348
|
let streamIndex = session.state.streamIndex;
|
|
1111
1349
|
let rendered = "";
|
|
1112
1350
|
let requestedInput = false;
|
|
@@ -1114,6 +1352,7 @@ var AgentSession = class {
|
|
|
1114
1352
|
try {
|
|
1115
1353
|
for await (const event of response) {
|
|
1116
1354
|
if (signal.aborted) break;
|
|
1355
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1117
1356
|
if (event.type === "input.requested") requestedInput = true;
|
|
1118
1357
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1119
1358
|
streamIndex += 1;
|
|
@@ -1124,8 +1363,11 @@ var AgentSession = class {
|
|
|
1124
1363
|
this.storeOptions
|
|
1125
1364
|
);
|
|
1126
1365
|
}
|
|
1366
|
+
await childStreams.waitForAll();
|
|
1127
1367
|
} finally {
|
|
1368
|
+
childStreams.abortAll();
|
|
1128
1369
|
this.activeResponse = void 0;
|
|
1370
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
1129
1371
|
this.session = client.sessions.attach(session.state.sessionId, {
|
|
1130
1372
|
streamIndex
|
|
1131
1373
|
});
|
|
@@ -1137,6 +1379,7 @@ var AgentSession = class {
|
|
|
1137
1379
|
return rendered.trim();
|
|
1138
1380
|
}
|
|
1139
1381
|
cancelActive() {
|
|
1382
|
+
this.childStreams?.abortAll();
|
|
1140
1383
|
if (this.activeResponse) {
|
|
1141
1384
|
this.activeResponse.cancel().catch(() => {
|
|
1142
1385
|
});
|
|
@@ -1975,7 +2218,7 @@ var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1975
2218
|
"presentationKinds",
|
|
1976
2219
|
"ui"
|
|
1977
2220
|
]);
|
|
1978
|
-
function
|
|
2221
|
+
function isRecord4(value) {
|
|
1979
2222
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1980
2223
|
}
|
|
1981
2224
|
function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -2002,7 +2245,7 @@ function decodeEnvelope(value) {
|
|
|
2002
2245
|
}
|
|
2003
2246
|
function parseAgentToolResultEnvelope(value) {
|
|
2004
2247
|
const decoded = decodeEnvelope(value);
|
|
2005
|
-
if (!
|
|
2248
|
+
if (!isRecord4(decoded)) return null;
|
|
2006
2249
|
const keys = Object.keys(decoded);
|
|
2007
2250
|
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) {
|
|
2008
2251
|
return null;
|
|
@@ -3986,7 +4229,7 @@ function ConfirmationCard({
|
|
|
3986
4229
|
// src/react/components/ToolInputCard/ToolInputCard.tsx
|
|
3987
4230
|
var import_react9 = require("react");
|
|
3988
4231
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
3989
|
-
function
|
|
4232
|
+
function isRecord5(value) {
|
|
3990
4233
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3991
4234
|
}
|
|
3992
4235
|
function pathSegments(path) {
|
|
@@ -4000,7 +4243,7 @@ function valueAtPath(root, path) {
|
|
|
4000
4243
|
current = Number.isInteger(index) ? current[index] : void 0;
|
|
4001
4244
|
continue;
|
|
4002
4245
|
}
|
|
4003
|
-
current =
|
|
4246
|
+
current = isRecord5(current) ? current[segment] : void 0;
|
|
4004
4247
|
}
|
|
4005
4248
|
return current;
|
|
4006
4249
|
}
|
|
@@ -4023,7 +4266,7 @@ function initialValues(surface) {
|
|
|
4023
4266
|
}
|
|
4024
4267
|
function cloneJsonValue(value) {
|
|
4025
4268
|
if (Array.isArray(value)) return value.map(cloneJsonValue);
|
|
4026
|
-
if (
|
|
4269
|
+
if (isRecord5(value)) {
|
|
4027
4270
|
return Object.fromEntries(
|
|
4028
4271
|
Object.entries(value).map(([key, item]) => [key, cloneJsonValue(item)])
|
|
4029
4272
|
);
|
|
@@ -4039,7 +4282,7 @@ function assignPath(target, path, value) {
|
|
|
4039
4282
|
return;
|
|
4040
4283
|
}
|
|
4041
4284
|
const existing = current[segment];
|
|
4042
|
-
if (!
|
|
4285
|
+
if (!isRecord5(existing)) current[segment] = {};
|
|
4043
4286
|
current = current[segment];
|
|
4044
4287
|
});
|
|
4045
4288
|
}
|
|
@@ -4335,7 +4578,7 @@ function ToolInputCard({
|
|
|
4335
4578
|
(field) => validateField(field, values[field.path] ?? "")
|
|
4336
4579
|
);
|
|
4337
4580
|
if (nextErrors.some(Boolean)) return;
|
|
4338
|
-
const result =
|
|
4581
|
+
const result = isRecord5(surface.values) ? cloneJsonValue(surface.values) : {};
|
|
4339
4582
|
for (const field of surface.fields) {
|
|
4340
4583
|
const parsed = parsedFieldValue(field, values[field.path] ?? "");
|
|
4341
4584
|
if (parsed !== void 0) assignPath(result, field.path, parsed);
|