@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/react.cjs
CHANGED
|
@@ -383,6 +383,203 @@ function clearPersistedAgentSession(visitorSessionId, options) {
|
|
|
383
383
|
sessionStorage.removeItem(runtimeLastMessageKey(visitorSessionId, prefix));
|
|
384
384
|
}
|
|
385
385
|
|
|
386
|
+
// src/runtime/subagent-child-stream.ts
|
|
387
|
+
var INITIAL_RETRY_DELAY_MS = 100;
|
|
388
|
+
var MAX_RETRY_DELAY_MS = 2e3;
|
|
389
|
+
var MAX_CONSECUTIVE_RETRIES = 6;
|
|
390
|
+
function isRecord2(value) {
|
|
391
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
392
|
+
}
|
|
393
|
+
function parseError(value) {
|
|
394
|
+
if (!isRecord2(value)) return void 0;
|
|
395
|
+
const { code, message } = value;
|
|
396
|
+
if (typeof code !== "string" || typeof message !== "string") {
|
|
397
|
+
return void 0;
|
|
398
|
+
}
|
|
399
|
+
return { code, message };
|
|
400
|
+
}
|
|
401
|
+
function parseChildStreamEvent(value) {
|
|
402
|
+
if (!isRecord2(value) || typeof value.type !== "string") {
|
|
403
|
+
return { type: "other" };
|
|
404
|
+
}
|
|
405
|
+
if (value.type === "session.waiting" || value.type === "session.completed" || value.type === "session.failed") {
|
|
406
|
+
return { type: "session.boundary" };
|
|
407
|
+
}
|
|
408
|
+
if (value.type === "subagent.event" && isRecord2(value.data) && Object.hasOwn(value.data, "event")) {
|
|
409
|
+
return parseChildStreamEvent(value.data.event);
|
|
410
|
+
}
|
|
411
|
+
if (value.type === "subagent.called" && isRecord2(value.data)) {
|
|
412
|
+
const { childStreamPath } = value.data;
|
|
413
|
+
if (typeof childStreamPath === "string") {
|
|
414
|
+
return { childStreamPath, type: "subagent.called" };
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (value.type !== "action.result" || !isRecord2(value.data)) {
|
|
418
|
+
return { type: "other" };
|
|
419
|
+
}
|
|
420
|
+
const { data } = value;
|
|
421
|
+
if (data.status !== "completed" && data.status !== "failed" && data.status !== "rejected") {
|
|
422
|
+
return { type: "other" };
|
|
423
|
+
}
|
|
424
|
+
if (!isRecord2(data.result) || data.result.kind !== "tool-result") {
|
|
425
|
+
return { type: "other" };
|
|
426
|
+
}
|
|
427
|
+
const result = data.result;
|
|
428
|
+
if (typeof result.callId !== "string" || typeof result.toolName !== "string") {
|
|
429
|
+
return { type: "other" };
|
|
430
|
+
}
|
|
431
|
+
const error = parseError(data.error);
|
|
432
|
+
return {
|
|
433
|
+
type: "action.result",
|
|
434
|
+
hasOutput: Object.hasOwn(result, "output"),
|
|
435
|
+
result: {
|
|
436
|
+
callId: result.callId,
|
|
437
|
+
toolName: result.toolName,
|
|
438
|
+
status: data.status,
|
|
439
|
+
...Object.hasOwn(result, "output") ? { output: result.output } : {},
|
|
440
|
+
...error ? { error } : {}
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
async function* readNdjsonStream(body) {
|
|
445
|
+
const reader = body.getReader();
|
|
446
|
+
const decoder = new TextDecoder();
|
|
447
|
+
let buffer = "";
|
|
448
|
+
try {
|
|
449
|
+
while (true) {
|
|
450
|
+
const { done, value } = await reader.read();
|
|
451
|
+
buffer += decoder.decode(value, { stream: !done });
|
|
452
|
+
const lines = buffer.split("\n");
|
|
453
|
+
buffer = lines.pop() ?? "";
|
|
454
|
+
for (const line of lines) {
|
|
455
|
+
const trimmed2 = line.trim();
|
|
456
|
+
if (!trimmed2) continue;
|
|
457
|
+
try {
|
|
458
|
+
const parsed = JSON.parse(trimmed2);
|
|
459
|
+
yield parsed;
|
|
460
|
+
} catch {
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
if (done) break;
|
|
464
|
+
}
|
|
465
|
+
const trimmed = buffer.trim();
|
|
466
|
+
if (trimmed) {
|
|
467
|
+
try {
|
|
468
|
+
const parsed = JSON.parse(trimmed);
|
|
469
|
+
yield parsed;
|
|
470
|
+
} catch {
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
} finally {
|
|
474
|
+
reader.releaseLock();
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
function streamPathAt(path, streamIndex) {
|
|
478
|
+
if (streamIndex === 0) return path;
|
|
479
|
+
return `${path}${path.includes("?") ? "&" : "?"}startIndex=${streamIndex}`;
|
|
480
|
+
}
|
|
481
|
+
function abortableDelay(delayMs, signal) {
|
|
482
|
+
if (signal.aborted) return Promise.resolve();
|
|
483
|
+
return new Promise((resolve) => {
|
|
484
|
+
const finish = () => {
|
|
485
|
+
clearTimeout(timeout);
|
|
486
|
+
signal.removeEventListener("abort", finish);
|
|
487
|
+
resolve();
|
|
488
|
+
};
|
|
489
|
+
const timeout = setTimeout(finish, delayMs);
|
|
490
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
var SubagentChildStreamCoordinator = class {
|
|
494
|
+
constructor(client, handlers, parentSignal) {
|
|
495
|
+
this.client = client;
|
|
496
|
+
this.handlers = handlers;
|
|
497
|
+
this.parentSignal = parentSignal;
|
|
498
|
+
}
|
|
499
|
+
client;
|
|
500
|
+
handlers;
|
|
501
|
+
parentSignal;
|
|
502
|
+
controllers = /* @__PURE__ */ new Map();
|
|
503
|
+
tasks = /* @__PURE__ */ new Map();
|
|
504
|
+
begin(event) {
|
|
505
|
+
this.beginPath(event.data.childStreamPath);
|
|
506
|
+
}
|
|
507
|
+
async waitForAll() {
|
|
508
|
+
let observedTaskCount = -1;
|
|
509
|
+
while (observedTaskCount !== this.tasks.size) {
|
|
510
|
+
observedTaskCount = this.tasks.size;
|
|
511
|
+
await Promise.all(this.tasks.values());
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
abortAll() {
|
|
515
|
+
for (const controller of this.controllers.values()) controller.abort();
|
|
516
|
+
this.controllers.clear();
|
|
517
|
+
}
|
|
518
|
+
beginPath(childStreamPath) {
|
|
519
|
+
if (this.tasks.has(childStreamPath)) return;
|
|
520
|
+
const controller = new AbortController();
|
|
521
|
+
const abort = () => controller.abort();
|
|
522
|
+
if (this.parentSignal.aborted) {
|
|
523
|
+
controller.abort();
|
|
524
|
+
} else {
|
|
525
|
+
this.parentSignal.addEventListener("abort", abort, { once: true });
|
|
526
|
+
}
|
|
527
|
+
this.controllers.set(childStreamPath, controller);
|
|
528
|
+
const task = this.consume(childStreamPath, controller.signal).finally(
|
|
529
|
+
() => {
|
|
530
|
+
this.parentSignal.removeEventListener("abort", abort);
|
|
531
|
+
if (this.controllers.get(childStreamPath) === controller) {
|
|
532
|
+
this.controllers.delete(childStreamPath);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
);
|
|
536
|
+
this.tasks.set(childStreamPath, task);
|
|
537
|
+
}
|
|
538
|
+
async consume(path, signal) {
|
|
539
|
+
let streamIndex = 0;
|
|
540
|
+
let consecutiveRetries = 0;
|
|
541
|
+
let retryDelayMs = INITIAL_RETRY_DELAY_MS;
|
|
542
|
+
while (!signal.aborted && consecutiveRetries < MAX_CONSECUTIVE_RETRIES) {
|
|
543
|
+
let receivedEvent = false;
|
|
544
|
+
try {
|
|
545
|
+
const response = await this.client.fetch(
|
|
546
|
+
streamPathAt(path, streamIndex),
|
|
547
|
+
{
|
|
548
|
+
cache: "no-store",
|
|
549
|
+
signal
|
|
550
|
+
}
|
|
551
|
+
);
|
|
552
|
+
if (!response.ok || response.body === null) {
|
|
553
|
+
await response.body?.cancel().catch(() => {
|
|
554
|
+
});
|
|
555
|
+
throw new Error(`Child stream returned ${response.status}.`);
|
|
556
|
+
}
|
|
557
|
+
for await (const rawEvent of readNdjsonStream(response.body)) {
|
|
558
|
+
if (signal.aborted) return;
|
|
559
|
+
receivedEvent = true;
|
|
560
|
+
streamIndex += 1;
|
|
561
|
+
const event = parseChildStreamEvent(rawEvent);
|
|
562
|
+
if (event.type === "session.boundary") return;
|
|
563
|
+
if (event.type === "subagent.called") {
|
|
564
|
+
this.beginPath(event.childStreamPath);
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
if (event.type !== "action.result") continue;
|
|
568
|
+
this.handlers.onToolResult?.(event.result);
|
|
569
|
+
if (event.hasOutput) {
|
|
570
|
+
this.handlers.onActionResult?.(event.result.output);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
} catch {
|
|
574
|
+
if (signal.aborted) return;
|
|
575
|
+
}
|
|
576
|
+
consecutiveRetries = receivedEvent ? 0 : consecutiveRetries + 1;
|
|
577
|
+
retryDelayMs = receivedEvent ? INITIAL_RETRY_DELAY_MS : Math.min(retryDelayMs * 2, MAX_RETRY_DELAY_MS);
|
|
578
|
+
await abortableDelay(retryDelayMs, signal);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
|
|
386
583
|
// src/runtime/tool-ui.ts
|
|
387
584
|
var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
|
|
388
585
|
var AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION = "webless.structured-tool-input.v1";
|
|
@@ -396,7 +593,7 @@ function formatAgentStructuredToolInput(surface, values) {
|
|
|
396
593
|
};
|
|
397
594
|
return `${AGENT_STRUCTURED_TOOL_INPUT_HEADER} ${JSON.stringify(payload)}`;
|
|
398
595
|
}
|
|
399
|
-
function
|
|
596
|
+
function isRecord3(value) {
|
|
400
597
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
401
598
|
}
|
|
402
599
|
function isJsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -445,7 +642,7 @@ function isFieldKind(value) {
|
|
|
445
642
|
].includes(value);
|
|
446
643
|
}
|
|
447
644
|
function parseField(value) {
|
|
448
|
-
if (!
|
|
645
|
+
if (!isRecord3(value)) return null;
|
|
449
646
|
if (!hasOnlyKeys(value, [
|
|
450
647
|
"description",
|
|
451
648
|
"kind",
|
|
@@ -496,7 +693,7 @@ function parseField(value) {
|
|
|
496
693
|
if (!Array.isArray(value.options) || value.options.length > 100)
|
|
497
694
|
return null;
|
|
498
695
|
for (const option of value.options) {
|
|
499
|
-
if (!
|
|
696
|
+
if (!isRecord3(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
|
|
500
697
|
return null;
|
|
501
698
|
}
|
|
502
699
|
}
|
|
@@ -519,7 +716,7 @@ function parseField(value) {
|
|
|
519
716
|
};
|
|
520
717
|
}
|
|
521
718
|
function parseStep(value) {
|
|
522
|
-
if (!
|
|
719
|
+
if (!isRecord3(value)) return null;
|
|
523
720
|
if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
|
|
524
721
|
return null;
|
|
525
722
|
}
|
|
@@ -539,7 +736,7 @@ function parseStep(value) {
|
|
|
539
736
|
};
|
|
540
737
|
}
|
|
541
738
|
function parseAction(value) {
|
|
542
|
-
if (!
|
|
739
|
+
if (!isRecord3(value)) return null;
|
|
543
740
|
if (!hasOnlyKeys(value, ["id", "label"])) return null;
|
|
544
741
|
const label = boundedString(value.label, 80);
|
|
545
742
|
if (value.id !== "submit" && value.id !== "back" && value.id !== "next" && value.id !== "reset" || !label) {
|
|
@@ -551,7 +748,7 @@ function parseAction(value) {
|
|
|
551
748
|
};
|
|
552
749
|
}
|
|
553
750
|
function parseAgentToolUiSurface(value) {
|
|
554
|
-
if (!
|
|
751
|
+
if (!isRecord3(value) || value.schemaVersion !== AGENT_TOOL_UI_SCHEMA_VERSION)
|
|
555
752
|
return null;
|
|
556
753
|
if (!hasOnlyKeys(value, [
|
|
557
754
|
"actions",
|
|
@@ -589,7 +786,7 @@ function parseAgentToolUiSurface(value) {
|
|
|
589
786
|
if (value.operationId !== void 0 && !operationId) return null;
|
|
590
787
|
if (value.requestId !== void 0 && !requestId) return null;
|
|
591
788
|
if (value.submitLabel !== void 0 && !submitLabel) return null;
|
|
592
|
-
const values = value.values !== void 0 &&
|
|
789
|
+
const values = value.values !== void 0 && isRecord3(value.values) ? value.values : void 0;
|
|
593
790
|
if (value.values !== void 0) {
|
|
594
791
|
if (!values || !Object.values(values).every((item) => isJsonValue(item)))
|
|
595
792
|
return null;
|
|
@@ -626,8 +823,7 @@ function applyMessageEvent(event, rendered, handlers, workItems) {
|
|
|
626
823
|
if (event.type === "message.completed") {
|
|
627
824
|
handlers.onComplete?.();
|
|
628
825
|
}
|
|
629
|
-
|
|
630
|
-
if (event.type === "input.requested") emitInputRequests(event, handlers);
|
|
826
|
+
emitVisitorInteractionEvent(event, handlers);
|
|
631
827
|
if (event.type !== "message.appended") return rendered;
|
|
632
828
|
const { messageDelta, messageSoFar } = event.data;
|
|
633
829
|
let delta = messageDelta;
|
|
@@ -677,6 +873,13 @@ function emitInputRequests(event, handlers) {
|
|
|
677
873
|
})
|
|
678
874
|
);
|
|
679
875
|
}
|
|
876
|
+
function emitVisitorInteractionEvent(event, handlers) {
|
|
877
|
+
if (event.type === "action.result") emitActionResult(event, handlers);
|
|
878
|
+
if (event.type === "input.requested") emitInputRequests(event, handlers);
|
|
879
|
+
if (event.type === "subagent.event") {
|
|
880
|
+
emitVisitorInteractionEvent(event.data.event, handlers);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
680
883
|
function isResumeTurnMessage(received, candidate) {
|
|
681
884
|
if (received === candidate) return true;
|
|
682
885
|
return Boolean(candidate) && received.endsWith(`
|
|
@@ -849,11 +1052,14 @@ var AgentSession = class {
|
|
|
849
1052
|
clientHost;
|
|
850
1053
|
session;
|
|
851
1054
|
activeResponse;
|
|
1055
|
+
childStreams;
|
|
852
1056
|
capability;
|
|
853
1057
|
getActiveSessionId() {
|
|
854
1058
|
return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
|
|
855
1059
|
}
|
|
856
1060
|
reset() {
|
|
1061
|
+
this.childStreams?.abortAll();
|
|
1062
|
+
this.childStreams = void 0;
|
|
857
1063
|
if (this.activeResponse) {
|
|
858
1064
|
void this.activeResponse.cancel().catch(() => {
|
|
859
1065
|
});
|
|
@@ -949,6 +1155,12 @@ var AgentSession = class {
|
|
|
949
1155
|
this.persistSessionCursor(session);
|
|
950
1156
|
}
|
|
951
1157
|
this.activeResponse = response;
|
|
1158
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1159
|
+
client,
|
|
1160
|
+
handlers,
|
|
1161
|
+
signal
|
|
1162
|
+
);
|
|
1163
|
+
this.childStreams = childStreams;
|
|
952
1164
|
let streamIndex = session?.state.streamIndex ?? 0;
|
|
953
1165
|
let rendered = "";
|
|
954
1166
|
const workItems = /* @__PURE__ */ new Map();
|
|
@@ -956,6 +1168,7 @@ var AgentSession = class {
|
|
|
956
1168
|
try {
|
|
957
1169
|
for await (const event of response) {
|
|
958
1170
|
if (signal.aborted) break;
|
|
1171
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
959
1172
|
if (event.type === "input.requested") requestedInput = true;
|
|
960
1173
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
961
1174
|
streamIndex += 1;
|
|
@@ -968,8 +1181,11 @@ var AgentSession = class {
|
|
|
968
1181
|
);
|
|
969
1182
|
}
|
|
970
1183
|
}
|
|
1184
|
+
await childStreams.waitForAll();
|
|
971
1185
|
} finally {
|
|
1186
|
+
childStreams.abortAll();
|
|
972
1187
|
this.activeResponse = void 0;
|
|
1188
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
973
1189
|
if (session) {
|
|
974
1190
|
this.persistSessionCursor(session);
|
|
975
1191
|
}
|
|
@@ -1005,64 +1221,80 @@ var AgentSession = class {
|
|
|
1005
1221
|
}
|
|
1006
1222
|
let rendered = renderTurn(turnEvents);
|
|
1007
1223
|
const workItems = /* @__PURE__ */ new Map();
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
rendered = initialText + rendered;
|
|
1020
|
-
}
|
|
1021
|
-
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
1022
|
-
streamIndex: snapshot.session.streamIndex
|
|
1023
|
-
});
|
|
1024
|
-
this.session = session;
|
|
1025
|
-
this.persistSessionCursor(session);
|
|
1026
|
-
let snapshotBoundary;
|
|
1027
|
-
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
1028
|
-
const event = turnEvents[index];
|
|
1029
|
-
if (event && isTurnBoundary(event)) {
|
|
1030
|
-
snapshotBoundary = event;
|
|
1031
|
-
break;
|
|
1224
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1225
|
+
client,
|
|
1226
|
+
handlers,
|
|
1227
|
+
signal
|
|
1228
|
+
);
|
|
1229
|
+
this.childStreams = childStreams;
|
|
1230
|
+
try {
|
|
1231
|
+
for (const event of turnEvents) {
|
|
1232
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1233
|
+
applyWorkEvent(event, handlers, workItems);
|
|
1234
|
+
emitVisitorInteractionEvent(event, handlers);
|
|
1032
1235
|
}
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1236
|
+
if (rendered.startsWith(initialText)) {
|
|
1237
|
+
const missedText = rendered.slice(initialText.length);
|
|
1238
|
+
if (missedText) handlers.onDelta(missedText);
|
|
1239
|
+
} else if (initialText.startsWith(rendered)) {
|
|
1240
|
+
rendered = initialText;
|
|
1241
|
+
} else if (!initialText.startsWith(rendered)) {
|
|
1242
|
+
rendered = initialText + rendered;
|
|
1243
|
+
}
|
|
1244
|
+
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
1245
|
+
streamIndex: snapshot.session.streamIndex
|
|
1246
|
+
});
|
|
1247
|
+
this.session = session;
|
|
1248
|
+
this.persistSessionCursor(session);
|
|
1249
|
+
let snapshotBoundary;
|
|
1250
|
+
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
1251
|
+
const event = turnEvents[index];
|
|
1252
|
+
if (event && isTurnBoundary(event)) {
|
|
1253
|
+
snapshotBoundary = event;
|
|
1254
|
+
break;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
if (snapshotBoundary) {
|
|
1258
|
+
if (snapshotBoundary.type === "session.failed") {
|
|
1259
|
+
throw new Error(
|
|
1260
|
+
snapshotBoundary.data.message || snapshotBoundary.data.code
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1263
|
+
handlers.onComplete?.();
|
|
1264
|
+
await childStreams.waitForAll();
|
|
1265
|
+
if (!rendered.trim() && !hasInputRequest) {
|
|
1266
|
+
throw new Error("Empty response from runtime");
|
|
1267
|
+
}
|
|
1268
|
+
return rendered.trim();
|
|
1269
|
+
}
|
|
1270
|
+
let streamIndex = snapshot.session.streamIndex;
|
|
1271
|
+
for await (const event of session.stream({ signal })) {
|
|
1272
|
+
if (signal.aborted) break;
|
|
1273
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1274
|
+
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1275
|
+
streamIndex += 1;
|
|
1276
|
+
savePersistedAgentSession(
|
|
1277
|
+
this.visitorSessionId,
|
|
1278
|
+
session.state.sessionId,
|
|
1279
|
+
streamIndex,
|
|
1280
|
+
this.storeOptions
|
|
1038
1281
|
);
|
|
1282
|
+
if (isTurnBoundary(event)) break;
|
|
1039
1283
|
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1284
|
+
await childStreams.waitForAll();
|
|
1285
|
+
session = client.sessions.attach(session.state.sessionId, {
|
|
1286
|
+
streamIndex
|
|
1287
|
+
});
|
|
1288
|
+
this.session = session;
|
|
1289
|
+
this.persistSessionCursor(session);
|
|
1290
|
+
if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
|
|
1042
1291
|
throw new Error("Empty response from runtime");
|
|
1043
1292
|
}
|
|
1044
1293
|
return rendered.trim();
|
|
1294
|
+
} finally {
|
|
1295
|
+
childStreams.abortAll();
|
|
1296
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
1045
1297
|
}
|
|
1046
|
-
let streamIndex = snapshot.session.streamIndex;
|
|
1047
|
-
for await (const event of session.stream({ signal })) {
|
|
1048
|
-
if (signal.aborted) break;
|
|
1049
|
-
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1050
|
-
streamIndex += 1;
|
|
1051
|
-
savePersistedAgentSession(
|
|
1052
|
-
this.visitorSessionId,
|
|
1053
|
-
session.state.sessionId,
|
|
1054
|
-
streamIndex,
|
|
1055
|
-
this.storeOptions
|
|
1056
|
-
);
|
|
1057
|
-
if (isTurnBoundary(event)) break;
|
|
1058
|
-
}
|
|
1059
|
-
session = client.sessions.attach(session.state.sessionId, { streamIndex });
|
|
1060
|
-
this.session = session;
|
|
1061
|
-
this.persistSessionCursor(session);
|
|
1062
|
-
if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
|
|
1063
|
-
throw new Error("Empty response from runtime");
|
|
1064
|
-
}
|
|
1065
|
-
return rendered.trim();
|
|
1066
1298
|
}
|
|
1067
1299
|
async respondTurn(responses, signal, handlers) {
|
|
1068
1300
|
const client = this.ensureClient();
|
|
@@ -1083,6 +1315,12 @@ var AgentSession = class {
|
|
|
1083
1315
|
() => session.respond(inputResponses, { signal })
|
|
1084
1316
|
);
|
|
1085
1317
|
this.activeResponse = response;
|
|
1318
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1319
|
+
client,
|
|
1320
|
+
handlers,
|
|
1321
|
+
signal
|
|
1322
|
+
);
|
|
1323
|
+
this.childStreams = childStreams;
|
|
1086
1324
|
let streamIndex = session.state.streamIndex;
|
|
1087
1325
|
let rendered = "";
|
|
1088
1326
|
let requestedInput = false;
|
|
@@ -1090,6 +1328,7 @@ var AgentSession = class {
|
|
|
1090
1328
|
try {
|
|
1091
1329
|
for await (const event of response) {
|
|
1092
1330
|
if (signal.aborted) break;
|
|
1331
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1093
1332
|
if (event.type === "input.requested") requestedInput = true;
|
|
1094
1333
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1095
1334
|
streamIndex += 1;
|
|
@@ -1100,8 +1339,11 @@ var AgentSession = class {
|
|
|
1100
1339
|
this.storeOptions
|
|
1101
1340
|
);
|
|
1102
1341
|
}
|
|
1342
|
+
await childStreams.waitForAll();
|
|
1103
1343
|
} finally {
|
|
1344
|
+
childStreams.abortAll();
|
|
1104
1345
|
this.activeResponse = void 0;
|
|
1346
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
1105
1347
|
this.session = client.sessions.attach(session.state.sessionId, {
|
|
1106
1348
|
streamIndex
|
|
1107
1349
|
});
|
|
@@ -1113,6 +1355,7 @@ var AgentSession = class {
|
|
|
1113
1355
|
return rendered.trim();
|
|
1114
1356
|
}
|
|
1115
1357
|
cancelActive() {
|
|
1358
|
+
this.childStreams?.abortAll();
|
|
1116
1359
|
if (this.activeResponse) {
|
|
1117
1360
|
this.activeResponse.cancel().catch(() => {
|
|
1118
1361
|
});
|
|
@@ -1951,7 +2194,7 @@ var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1951
2194
|
"presentationKinds",
|
|
1952
2195
|
"ui"
|
|
1953
2196
|
]);
|
|
1954
|
-
function
|
|
2197
|
+
function isRecord4(value) {
|
|
1955
2198
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1956
2199
|
}
|
|
1957
2200
|
function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -1978,7 +2221,7 @@ function decodeEnvelope(value) {
|
|
|
1978
2221
|
}
|
|
1979
2222
|
function parseAgentToolResultEnvelope(value) {
|
|
1980
2223
|
const decoded = decodeEnvelope(value);
|
|
1981
|
-
if (!
|
|
2224
|
+
if (!isRecord4(decoded)) return null;
|
|
1982
2225
|
const keys = Object.keys(decoded);
|
|
1983
2226
|
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) {
|
|
1984
2227
|
return null;
|
|
@@ -3978,7 +4221,7 @@ function ConfirmationCard({
|
|
|
3978
4221
|
// src/react/components/ToolInputCard/ToolInputCard.tsx
|
|
3979
4222
|
var import_react9 = require("react");
|
|
3980
4223
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
3981
|
-
function
|
|
4224
|
+
function isRecord5(value) {
|
|
3982
4225
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3983
4226
|
}
|
|
3984
4227
|
function pathSegments(path) {
|
|
@@ -3992,7 +4235,7 @@ function valueAtPath(root, path) {
|
|
|
3992
4235
|
current = Number.isInteger(index) ? current[index] : void 0;
|
|
3993
4236
|
continue;
|
|
3994
4237
|
}
|
|
3995
|
-
current =
|
|
4238
|
+
current = isRecord5(current) ? current[segment] : void 0;
|
|
3996
4239
|
}
|
|
3997
4240
|
return current;
|
|
3998
4241
|
}
|
|
@@ -4015,7 +4258,7 @@ function initialValues(surface) {
|
|
|
4015
4258
|
}
|
|
4016
4259
|
function cloneJsonValue(value) {
|
|
4017
4260
|
if (Array.isArray(value)) return value.map(cloneJsonValue);
|
|
4018
|
-
if (
|
|
4261
|
+
if (isRecord5(value)) {
|
|
4019
4262
|
return Object.fromEntries(
|
|
4020
4263
|
Object.entries(value).map(([key, item]) => [key, cloneJsonValue(item)])
|
|
4021
4264
|
);
|
|
@@ -4031,7 +4274,7 @@ function assignPath(target, path, value) {
|
|
|
4031
4274
|
return;
|
|
4032
4275
|
}
|
|
4033
4276
|
const existing = current[segment];
|
|
4034
|
-
if (!
|
|
4277
|
+
if (!isRecord5(existing)) current[segment] = {};
|
|
4035
4278
|
current = current[segment];
|
|
4036
4279
|
});
|
|
4037
4280
|
}
|
|
@@ -4327,7 +4570,7 @@ function ToolInputCard({
|
|
|
4327
4570
|
(field) => validateField(field, values[field.path] ?? "")
|
|
4328
4571
|
);
|
|
4329
4572
|
if (nextErrors.some(Boolean)) return;
|
|
4330
|
-
const result =
|
|
4573
|
+
const result = isRecord5(surface.values) ? cloneJsonValue(surface.values) : {};
|
|
4331
4574
|
for (const field of surface.fields) {
|
|
4332
4575
|
const parsed = parsedFieldValue(field, values[field.path] ?? "");
|
|
4333
4576
|
if (parsed !== void 0) assignPath(result, field.path, parsed);
|