@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/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;
|
|
@@ -855,11 +1052,14 @@ var AgentSession = class {
|
|
|
855
1052
|
clientHost;
|
|
856
1053
|
session;
|
|
857
1054
|
activeResponse;
|
|
1055
|
+
childStreams;
|
|
858
1056
|
capability;
|
|
859
1057
|
getActiveSessionId() {
|
|
860
1058
|
return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
|
|
861
1059
|
}
|
|
862
1060
|
reset() {
|
|
1061
|
+
this.childStreams?.abortAll();
|
|
1062
|
+
this.childStreams = void 0;
|
|
863
1063
|
if (this.activeResponse) {
|
|
864
1064
|
void this.activeResponse.cancel().catch(() => {
|
|
865
1065
|
});
|
|
@@ -955,6 +1155,12 @@ var AgentSession = class {
|
|
|
955
1155
|
this.persistSessionCursor(session);
|
|
956
1156
|
}
|
|
957
1157
|
this.activeResponse = response;
|
|
1158
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1159
|
+
client,
|
|
1160
|
+
handlers,
|
|
1161
|
+
signal
|
|
1162
|
+
);
|
|
1163
|
+
this.childStreams = childStreams;
|
|
958
1164
|
let streamIndex = session?.state.streamIndex ?? 0;
|
|
959
1165
|
let rendered = "";
|
|
960
1166
|
const workItems = /* @__PURE__ */ new Map();
|
|
@@ -962,6 +1168,7 @@ var AgentSession = class {
|
|
|
962
1168
|
try {
|
|
963
1169
|
for await (const event of response) {
|
|
964
1170
|
if (signal.aborted) break;
|
|
1171
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
965
1172
|
if (event.type === "input.requested") requestedInput = true;
|
|
966
1173
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
967
1174
|
streamIndex += 1;
|
|
@@ -974,8 +1181,11 @@ var AgentSession = class {
|
|
|
974
1181
|
);
|
|
975
1182
|
}
|
|
976
1183
|
}
|
|
1184
|
+
await childStreams.waitForAll();
|
|
977
1185
|
} finally {
|
|
1186
|
+
childStreams.abortAll();
|
|
978
1187
|
this.activeResponse = void 0;
|
|
1188
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
979
1189
|
if (session) {
|
|
980
1190
|
this.persistSessionCursor(session);
|
|
981
1191
|
}
|
|
@@ -1011,63 +1221,80 @@ var AgentSession = class {
|
|
|
1011
1221
|
}
|
|
1012
1222
|
let rendered = renderTurn(turnEvents);
|
|
1013
1223
|
const workItems = /* @__PURE__ */ new Map();
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
}
|
|
1026
|
-
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
1027
|
-
streamIndex: snapshot.session.streamIndex
|
|
1028
|
-
});
|
|
1029
|
-
this.session = session;
|
|
1030
|
-
this.persistSessionCursor(session);
|
|
1031
|
-
let snapshotBoundary;
|
|
1032
|
-
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
1033
|
-
const event = turnEvents[index];
|
|
1034
|
-
if (event && isTurnBoundary(event)) {
|
|
1035
|
-
snapshotBoundary = event;
|
|
1036
|
-
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);
|
|
1037
1235
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
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
|
|
1043
1281
|
);
|
|
1282
|
+
if (isTurnBoundary(event)) break;
|
|
1044
1283
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
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) {
|
|
1047
1291
|
throw new Error("Empty response from runtime");
|
|
1048
1292
|
}
|
|
1049
1293
|
return rendered.trim();
|
|
1294
|
+
} finally {
|
|
1295
|
+
childStreams.abortAll();
|
|
1296
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
1050
1297
|
}
|
|
1051
|
-
let streamIndex = snapshot.session.streamIndex;
|
|
1052
|
-
for await (const event of session.stream({ signal })) {
|
|
1053
|
-
if (signal.aborted) break;
|
|
1054
|
-
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1055
|
-
streamIndex += 1;
|
|
1056
|
-
savePersistedAgentSession(
|
|
1057
|
-
this.visitorSessionId,
|
|
1058
|
-
session.state.sessionId,
|
|
1059
|
-
streamIndex,
|
|
1060
|
-
this.storeOptions
|
|
1061
|
-
);
|
|
1062
|
-
if (isTurnBoundary(event)) break;
|
|
1063
|
-
}
|
|
1064
|
-
session = client.sessions.attach(session.state.sessionId, { streamIndex });
|
|
1065
|
-
this.session = session;
|
|
1066
|
-
this.persistSessionCursor(session);
|
|
1067
|
-
if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
|
|
1068
|
-
throw new Error("Empty response from runtime");
|
|
1069
|
-
}
|
|
1070
|
-
return rendered.trim();
|
|
1071
1298
|
}
|
|
1072
1299
|
async respondTurn(responses, signal, handlers) {
|
|
1073
1300
|
const client = this.ensureClient();
|
|
@@ -1088,6 +1315,12 @@ var AgentSession = class {
|
|
|
1088
1315
|
() => session.respond(inputResponses, { signal })
|
|
1089
1316
|
);
|
|
1090
1317
|
this.activeResponse = response;
|
|
1318
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1319
|
+
client,
|
|
1320
|
+
handlers,
|
|
1321
|
+
signal
|
|
1322
|
+
);
|
|
1323
|
+
this.childStreams = childStreams;
|
|
1091
1324
|
let streamIndex = session.state.streamIndex;
|
|
1092
1325
|
let rendered = "";
|
|
1093
1326
|
let requestedInput = false;
|
|
@@ -1095,6 +1328,7 @@ var AgentSession = class {
|
|
|
1095
1328
|
try {
|
|
1096
1329
|
for await (const event of response) {
|
|
1097
1330
|
if (signal.aborted) break;
|
|
1331
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1098
1332
|
if (event.type === "input.requested") requestedInput = true;
|
|
1099
1333
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1100
1334
|
streamIndex += 1;
|
|
@@ -1105,8 +1339,11 @@ var AgentSession = class {
|
|
|
1105
1339
|
this.storeOptions
|
|
1106
1340
|
);
|
|
1107
1341
|
}
|
|
1342
|
+
await childStreams.waitForAll();
|
|
1108
1343
|
} finally {
|
|
1344
|
+
childStreams.abortAll();
|
|
1109
1345
|
this.activeResponse = void 0;
|
|
1346
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
1110
1347
|
this.session = client.sessions.attach(session.state.sessionId, {
|
|
1111
1348
|
streamIndex
|
|
1112
1349
|
});
|
|
@@ -1118,6 +1355,7 @@ var AgentSession = class {
|
|
|
1118
1355
|
return rendered.trim();
|
|
1119
1356
|
}
|
|
1120
1357
|
cancelActive() {
|
|
1358
|
+
this.childStreams?.abortAll();
|
|
1121
1359
|
if (this.activeResponse) {
|
|
1122
1360
|
this.activeResponse.cancel().catch(() => {
|
|
1123
1361
|
});
|
|
@@ -1956,7 +2194,7 @@ var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1956
2194
|
"presentationKinds",
|
|
1957
2195
|
"ui"
|
|
1958
2196
|
]);
|
|
1959
|
-
function
|
|
2197
|
+
function isRecord4(value) {
|
|
1960
2198
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1961
2199
|
}
|
|
1962
2200
|
function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -1983,7 +2221,7 @@ function decodeEnvelope(value) {
|
|
|
1983
2221
|
}
|
|
1984
2222
|
function parseAgentToolResultEnvelope(value) {
|
|
1985
2223
|
const decoded = decodeEnvelope(value);
|
|
1986
|
-
if (!
|
|
2224
|
+
if (!isRecord4(decoded)) return null;
|
|
1987
2225
|
const keys = Object.keys(decoded);
|
|
1988
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) {
|
|
1989
2227
|
return null;
|
|
@@ -3532,7 +3770,14 @@ function BookingCard({
|
|
|
3532
3770
|
const [startTime, setStartTime] = (0, import_react7.useState)("");
|
|
3533
3771
|
const [name, setName] = (0, import_react7.useState)("");
|
|
3534
3772
|
const [email, setEmail] = (0, import_react7.useState)("");
|
|
3773
|
+
const activeStepRef = (0, import_react7.useRef)(null);
|
|
3774
|
+
const previousStepRef = (0, import_react7.useRef)(step);
|
|
3535
3775
|
const stepIndex = BOOKING_STEPS.findIndex((item) => item.id === step);
|
|
3776
|
+
(0, import_react7.useEffect)(() => {
|
|
3777
|
+
if (previousStepRef.current === step) return;
|
|
3778
|
+
previousStepRef.current = step;
|
|
3779
|
+
activeStepRef.current?.scrollIntoView({ block: "nearest" });
|
|
3780
|
+
}, [step]);
|
|
3536
3781
|
const slots = (0, import_react7.useMemo)(
|
|
3537
3782
|
() => bookingSlotsForEventType(offer.slots, eventTypeUri),
|
|
3538
3783
|
[eventTypeUri, offer.slots]
|
|
@@ -3626,7 +3871,7 @@ function BookingCard({
|
|
|
3626
3871
|
},
|
|
3627
3872
|
item.id
|
|
3628
3873
|
)) }),
|
|
3629
|
-
step === "date" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
|
|
3874
|
+
step === "date" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
|
|
3630
3875
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: selectedType?.name || "Pick a date" }),
|
|
3631
3876
|
timeZone ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "booking-card__tz", children: [
|
|
3632
3877
|
"Times in ",
|
|
@@ -3716,7 +3961,7 @@ function BookingCard({
|
|
|
3716
3961
|
}
|
|
3717
3962
|
)
|
|
3718
3963
|
] }, "date") : null,
|
|
3719
|
-
step === "time" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
|
|
3964
|
+
step === "time" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
|
|
3720
3965
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
|
|
3721
3966
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3722
3967
|
"button",
|
|
@@ -3747,7 +3992,7 @@ function BookingCard({
|
|
|
3747
3992
|
slot.startTime
|
|
3748
3993
|
)) })
|
|
3749
3994
|
] }, "time") : null,
|
|
3750
|
-
step === "details" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
|
|
3995
|
+
step === "details" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
|
|
3751
3996
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
|
|
3752
3997
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3753
3998
|
"button",
|
|
@@ -3983,7 +4228,7 @@ function ConfirmationCard({
|
|
|
3983
4228
|
// src/react/components/ToolInputCard/ToolInputCard.tsx
|
|
3984
4229
|
var import_react9 = require("react");
|
|
3985
4230
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
3986
|
-
function
|
|
4231
|
+
function isRecord5(value) {
|
|
3987
4232
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3988
4233
|
}
|
|
3989
4234
|
function pathSegments(path) {
|
|
@@ -3997,7 +4242,7 @@ function valueAtPath(root, path) {
|
|
|
3997
4242
|
current = Number.isInteger(index) ? current[index] : void 0;
|
|
3998
4243
|
continue;
|
|
3999
4244
|
}
|
|
4000
|
-
current =
|
|
4245
|
+
current = isRecord5(current) ? current[segment] : void 0;
|
|
4001
4246
|
}
|
|
4002
4247
|
return current;
|
|
4003
4248
|
}
|
|
@@ -4020,7 +4265,7 @@ function initialValues(surface) {
|
|
|
4020
4265
|
}
|
|
4021
4266
|
function cloneJsonValue(value) {
|
|
4022
4267
|
if (Array.isArray(value)) return value.map(cloneJsonValue);
|
|
4023
|
-
if (
|
|
4268
|
+
if (isRecord5(value)) {
|
|
4024
4269
|
return Object.fromEntries(
|
|
4025
4270
|
Object.entries(value).map(([key, item]) => [key, cloneJsonValue(item)])
|
|
4026
4271
|
);
|
|
@@ -4036,7 +4281,7 @@ function assignPath(target, path, value) {
|
|
|
4036
4281
|
return;
|
|
4037
4282
|
}
|
|
4038
4283
|
const existing = current[segment];
|
|
4039
|
-
if (!
|
|
4284
|
+
if (!isRecord5(existing)) current[segment] = {};
|
|
4040
4285
|
current = current[segment];
|
|
4041
4286
|
});
|
|
4042
4287
|
}
|
|
@@ -4332,7 +4577,7 @@ function ToolInputCard({
|
|
|
4332
4577
|
(field) => validateField(field, values[field.path] ?? "")
|
|
4333
4578
|
);
|
|
4334
4579
|
if (nextErrors.some(Boolean)) return;
|
|
4335
|
-
const result =
|
|
4580
|
+
const result = isRecord5(surface.values) ? cloneJsonValue(surface.values) : {};
|
|
4336
4581
|
for (const field of surface.fields) {
|
|
4337
4582
|
const parsed = parsedFieldValue(field, values[field.path] ?? "");
|
|
4338
4583
|
if (parsed !== void 0) assignPath(result, field.path, parsed);
|