@webless/agent 0.6.8 → 0.6.10
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-NEI5GKGH.js} +322 -71
- package/dist/chunk-NEI5GKGH.js.map +1 -0
- package/dist/embed.cjs +312 -67
- 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 +312 -67
- 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.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;
|
|
@@ -879,11 +1076,14 @@ var AgentSession = class {
|
|
|
879
1076
|
clientHost;
|
|
880
1077
|
session;
|
|
881
1078
|
activeResponse;
|
|
1079
|
+
childStreams;
|
|
882
1080
|
capability;
|
|
883
1081
|
getActiveSessionId() {
|
|
884
1082
|
return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
|
|
885
1083
|
}
|
|
886
1084
|
reset() {
|
|
1085
|
+
this.childStreams?.abortAll();
|
|
1086
|
+
this.childStreams = void 0;
|
|
887
1087
|
if (this.activeResponse) {
|
|
888
1088
|
void this.activeResponse.cancel().catch(() => {
|
|
889
1089
|
});
|
|
@@ -979,6 +1179,12 @@ var AgentSession = class {
|
|
|
979
1179
|
this.persistSessionCursor(session);
|
|
980
1180
|
}
|
|
981
1181
|
this.activeResponse = response;
|
|
1182
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1183
|
+
client,
|
|
1184
|
+
handlers,
|
|
1185
|
+
signal
|
|
1186
|
+
);
|
|
1187
|
+
this.childStreams = childStreams;
|
|
982
1188
|
let streamIndex = session?.state.streamIndex ?? 0;
|
|
983
1189
|
let rendered = "";
|
|
984
1190
|
const workItems = /* @__PURE__ */ new Map();
|
|
@@ -986,6 +1192,7 @@ var AgentSession = class {
|
|
|
986
1192
|
try {
|
|
987
1193
|
for await (const event of response) {
|
|
988
1194
|
if (signal.aborted) break;
|
|
1195
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
989
1196
|
if (event.type === "input.requested") requestedInput = true;
|
|
990
1197
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
991
1198
|
streamIndex += 1;
|
|
@@ -998,8 +1205,11 @@ var AgentSession = class {
|
|
|
998
1205
|
);
|
|
999
1206
|
}
|
|
1000
1207
|
}
|
|
1208
|
+
await childStreams.waitForAll();
|
|
1001
1209
|
} finally {
|
|
1210
|
+
childStreams.abortAll();
|
|
1002
1211
|
this.activeResponse = void 0;
|
|
1212
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
1003
1213
|
if (session) {
|
|
1004
1214
|
this.persistSessionCursor(session);
|
|
1005
1215
|
}
|
|
@@ -1035,63 +1245,80 @@ var AgentSession = class {
|
|
|
1035
1245
|
}
|
|
1036
1246
|
let rendered = renderTurn(turnEvents);
|
|
1037
1247
|
const workItems = /* @__PURE__ */ new Map();
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
}
|
|
1050
|
-
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
1051
|
-
streamIndex: snapshot.session.streamIndex
|
|
1052
|
-
});
|
|
1053
|
-
this.session = session;
|
|
1054
|
-
this.persistSessionCursor(session);
|
|
1055
|
-
let snapshotBoundary;
|
|
1056
|
-
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
1057
|
-
const event = turnEvents[index];
|
|
1058
|
-
if (event && isTurnBoundary(event)) {
|
|
1059
|
-
snapshotBoundary = event;
|
|
1060
|
-
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);
|
|
1061
1259
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
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
|
|
1067
1305
|
);
|
|
1306
|
+
if (isTurnBoundary(event)) break;
|
|
1068
1307
|
}
|
|
1069
|
-
|
|
1070
|
-
|
|
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) {
|
|
1071
1315
|
throw new Error("Empty response from runtime");
|
|
1072
1316
|
}
|
|
1073
1317
|
return rendered.trim();
|
|
1318
|
+
} finally {
|
|
1319
|
+
childStreams.abortAll();
|
|
1320
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
1074
1321
|
}
|
|
1075
|
-
let streamIndex = snapshot.session.streamIndex;
|
|
1076
|
-
for await (const event of session.stream({ signal })) {
|
|
1077
|
-
if (signal.aborted) break;
|
|
1078
|
-
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1079
|
-
streamIndex += 1;
|
|
1080
|
-
savePersistedAgentSession(
|
|
1081
|
-
this.visitorSessionId,
|
|
1082
|
-
session.state.sessionId,
|
|
1083
|
-
streamIndex,
|
|
1084
|
-
this.storeOptions
|
|
1085
|
-
);
|
|
1086
|
-
if (isTurnBoundary(event)) break;
|
|
1087
|
-
}
|
|
1088
|
-
session = client.sessions.attach(session.state.sessionId, { streamIndex });
|
|
1089
|
-
this.session = session;
|
|
1090
|
-
this.persistSessionCursor(session);
|
|
1091
|
-
if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
|
|
1092
|
-
throw new Error("Empty response from runtime");
|
|
1093
|
-
}
|
|
1094
|
-
return rendered.trim();
|
|
1095
1322
|
}
|
|
1096
1323
|
async respondTurn(responses, signal, handlers) {
|
|
1097
1324
|
const client = this.ensureClient();
|
|
@@ -1112,6 +1339,12 @@ var AgentSession = class {
|
|
|
1112
1339
|
() => session.respond(inputResponses, { signal })
|
|
1113
1340
|
);
|
|
1114
1341
|
this.activeResponse = response;
|
|
1342
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1343
|
+
client,
|
|
1344
|
+
handlers,
|
|
1345
|
+
signal
|
|
1346
|
+
);
|
|
1347
|
+
this.childStreams = childStreams;
|
|
1115
1348
|
let streamIndex = session.state.streamIndex;
|
|
1116
1349
|
let rendered = "";
|
|
1117
1350
|
let requestedInput = false;
|
|
@@ -1119,6 +1352,7 @@ var AgentSession = class {
|
|
|
1119
1352
|
try {
|
|
1120
1353
|
for await (const event of response) {
|
|
1121
1354
|
if (signal.aborted) break;
|
|
1355
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1122
1356
|
if (event.type === "input.requested") requestedInput = true;
|
|
1123
1357
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1124
1358
|
streamIndex += 1;
|
|
@@ -1129,8 +1363,11 @@ var AgentSession = class {
|
|
|
1129
1363
|
this.storeOptions
|
|
1130
1364
|
);
|
|
1131
1365
|
}
|
|
1366
|
+
await childStreams.waitForAll();
|
|
1132
1367
|
} finally {
|
|
1368
|
+
childStreams.abortAll();
|
|
1133
1369
|
this.activeResponse = void 0;
|
|
1370
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
1134
1371
|
this.session = client.sessions.attach(session.state.sessionId, {
|
|
1135
1372
|
streamIndex
|
|
1136
1373
|
});
|
|
@@ -1142,6 +1379,7 @@ var AgentSession = class {
|
|
|
1142
1379
|
return rendered.trim();
|
|
1143
1380
|
}
|
|
1144
1381
|
cancelActive() {
|
|
1382
|
+
this.childStreams?.abortAll();
|
|
1145
1383
|
if (this.activeResponse) {
|
|
1146
1384
|
this.activeResponse.cancel().catch(() => {
|
|
1147
1385
|
});
|
|
@@ -1980,7 +2218,7 @@ var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1980
2218
|
"presentationKinds",
|
|
1981
2219
|
"ui"
|
|
1982
2220
|
]);
|
|
1983
|
-
function
|
|
2221
|
+
function isRecord4(value) {
|
|
1984
2222
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1985
2223
|
}
|
|
1986
2224
|
function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -2007,7 +2245,7 @@ function decodeEnvelope(value) {
|
|
|
2007
2245
|
}
|
|
2008
2246
|
function parseAgentToolResultEnvelope(value) {
|
|
2009
2247
|
const decoded = decodeEnvelope(value);
|
|
2010
|
-
if (!
|
|
2248
|
+
if (!isRecord4(decoded)) return null;
|
|
2011
2249
|
const keys = Object.keys(decoded);
|
|
2012
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) {
|
|
2013
2251
|
return null;
|
|
@@ -3540,7 +3778,14 @@ function BookingCard({
|
|
|
3540
3778
|
const [startTime, setStartTime] = (0, import_react7.useState)("");
|
|
3541
3779
|
const [name, setName] = (0, import_react7.useState)("");
|
|
3542
3780
|
const [email, setEmail] = (0, import_react7.useState)("");
|
|
3781
|
+
const activeStepRef = (0, import_react7.useRef)(null);
|
|
3782
|
+
const previousStepRef = (0, import_react7.useRef)(step);
|
|
3543
3783
|
const stepIndex = BOOKING_STEPS.findIndex((item) => item.id === step);
|
|
3784
|
+
(0, import_react7.useEffect)(() => {
|
|
3785
|
+
if (previousStepRef.current === step) return;
|
|
3786
|
+
previousStepRef.current = step;
|
|
3787
|
+
activeStepRef.current?.scrollIntoView({ block: "nearest" });
|
|
3788
|
+
}, [step]);
|
|
3544
3789
|
const slots = (0, import_react7.useMemo)(
|
|
3545
3790
|
() => bookingSlotsForEventType(offer.slots, eventTypeUri),
|
|
3546
3791
|
[eventTypeUri, offer.slots]
|
|
@@ -3634,7 +3879,7 @@ function BookingCard({
|
|
|
3634
3879
|
},
|
|
3635
3880
|
item.id
|
|
3636
3881
|
)) }),
|
|
3637
|
-
step === "date" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
|
|
3882
|
+
step === "date" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
|
|
3638
3883
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: selectedType?.name || "Pick a date" }),
|
|
3639
3884
|
timeZone ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "booking-card__tz", children: [
|
|
3640
3885
|
"Times in ",
|
|
@@ -3724,7 +3969,7 @@ function BookingCard({
|
|
|
3724
3969
|
}
|
|
3725
3970
|
)
|
|
3726
3971
|
] }, "date") : null,
|
|
3727
|
-
step === "time" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
|
|
3972
|
+
step === "time" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
|
|
3728
3973
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
|
|
3729
3974
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3730
3975
|
"button",
|
|
@@ -3755,7 +4000,7 @@ function BookingCard({
|
|
|
3755
4000
|
slot.startTime
|
|
3756
4001
|
)) })
|
|
3757
4002
|
] }, "time") : null,
|
|
3758
|
-
step === "details" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
|
|
4003
|
+
step === "details" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
|
|
3759
4004
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
|
|
3760
4005
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3761
4006
|
"button",
|
|
@@ -3991,7 +4236,7 @@ function ConfirmationCard({
|
|
|
3991
4236
|
// src/react/components/ToolInputCard/ToolInputCard.tsx
|
|
3992
4237
|
var import_react9 = require("react");
|
|
3993
4238
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
3994
|
-
function
|
|
4239
|
+
function isRecord5(value) {
|
|
3995
4240
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3996
4241
|
}
|
|
3997
4242
|
function pathSegments(path) {
|
|
@@ -4005,7 +4250,7 @@ function valueAtPath(root, path) {
|
|
|
4005
4250
|
current = Number.isInteger(index) ? current[index] : void 0;
|
|
4006
4251
|
continue;
|
|
4007
4252
|
}
|
|
4008
|
-
current =
|
|
4253
|
+
current = isRecord5(current) ? current[segment] : void 0;
|
|
4009
4254
|
}
|
|
4010
4255
|
return current;
|
|
4011
4256
|
}
|
|
@@ -4028,7 +4273,7 @@ function initialValues(surface) {
|
|
|
4028
4273
|
}
|
|
4029
4274
|
function cloneJsonValue(value) {
|
|
4030
4275
|
if (Array.isArray(value)) return value.map(cloneJsonValue);
|
|
4031
|
-
if (
|
|
4276
|
+
if (isRecord5(value)) {
|
|
4032
4277
|
return Object.fromEntries(
|
|
4033
4278
|
Object.entries(value).map(([key, item]) => [key, cloneJsonValue(item)])
|
|
4034
4279
|
);
|
|
@@ -4044,7 +4289,7 @@ function assignPath(target, path, value) {
|
|
|
4044
4289
|
return;
|
|
4045
4290
|
}
|
|
4046
4291
|
const existing = current[segment];
|
|
4047
|
-
if (!
|
|
4292
|
+
if (!isRecord5(existing)) current[segment] = {};
|
|
4048
4293
|
current = current[segment];
|
|
4049
4294
|
});
|
|
4050
4295
|
}
|
|
@@ -4340,7 +4585,7 @@ function ToolInputCard({
|
|
|
4340
4585
|
(field) => validateField(field, values[field.path] ?? "")
|
|
4341
4586
|
);
|
|
4342
4587
|
if (nextErrors.some(Boolean)) return;
|
|
4343
|
-
const result =
|
|
4588
|
+
const result = isRecord5(surface.values) ? cloneJsonValue(surface.values) : {};
|
|
4344
4589
|
for (const field of surface.fields) {
|
|
4345
4590
|
const parsed = parsedFieldValue(field, values[field.path] ?? "");
|
|
4346
4591
|
if (parsed !== void 0) assignPath(result, field.path, parsed);
|