@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/index.js
CHANGED
|
@@ -268,6 +268,203 @@ function clearPersistedAgentSession(visitorSessionId, options) {
|
|
|
268
268
|
sessionStorage.removeItem(runtimeLastMessageKey(visitorSessionId, prefix));
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
+
// src/runtime/subagent-child-stream.ts
|
|
272
|
+
var INITIAL_RETRY_DELAY_MS = 100;
|
|
273
|
+
var MAX_RETRY_DELAY_MS = 2e3;
|
|
274
|
+
var MAX_CONSECUTIVE_RETRIES = 6;
|
|
275
|
+
function isRecord2(value) {
|
|
276
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
277
|
+
}
|
|
278
|
+
function parseError(value) {
|
|
279
|
+
if (!isRecord2(value)) return void 0;
|
|
280
|
+
const { code, message } = value;
|
|
281
|
+
if (typeof code !== "string" || typeof message !== "string") {
|
|
282
|
+
return void 0;
|
|
283
|
+
}
|
|
284
|
+
return { code, message };
|
|
285
|
+
}
|
|
286
|
+
function parseChildStreamEvent(value) {
|
|
287
|
+
if (!isRecord2(value) || typeof value.type !== "string") {
|
|
288
|
+
return { type: "other" };
|
|
289
|
+
}
|
|
290
|
+
if (value.type === "session.waiting" || value.type === "session.completed" || value.type === "session.failed") {
|
|
291
|
+
return { type: "session.boundary" };
|
|
292
|
+
}
|
|
293
|
+
if (value.type === "subagent.event" && isRecord2(value.data) && Object.hasOwn(value.data, "event")) {
|
|
294
|
+
return parseChildStreamEvent(value.data.event);
|
|
295
|
+
}
|
|
296
|
+
if (value.type === "subagent.called" && isRecord2(value.data)) {
|
|
297
|
+
const { childStreamPath } = value.data;
|
|
298
|
+
if (typeof childStreamPath === "string") {
|
|
299
|
+
return { childStreamPath, type: "subagent.called" };
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (value.type !== "action.result" || !isRecord2(value.data)) {
|
|
303
|
+
return { type: "other" };
|
|
304
|
+
}
|
|
305
|
+
const { data } = value;
|
|
306
|
+
if (data.status !== "completed" && data.status !== "failed" && data.status !== "rejected") {
|
|
307
|
+
return { type: "other" };
|
|
308
|
+
}
|
|
309
|
+
if (!isRecord2(data.result) || data.result.kind !== "tool-result") {
|
|
310
|
+
return { type: "other" };
|
|
311
|
+
}
|
|
312
|
+
const result = data.result;
|
|
313
|
+
if (typeof result.callId !== "string" || typeof result.toolName !== "string") {
|
|
314
|
+
return { type: "other" };
|
|
315
|
+
}
|
|
316
|
+
const error = parseError(data.error);
|
|
317
|
+
return {
|
|
318
|
+
type: "action.result",
|
|
319
|
+
hasOutput: Object.hasOwn(result, "output"),
|
|
320
|
+
result: {
|
|
321
|
+
callId: result.callId,
|
|
322
|
+
toolName: result.toolName,
|
|
323
|
+
status: data.status,
|
|
324
|
+
...Object.hasOwn(result, "output") ? { output: result.output } : {},
|
|
325
|
+
...error ? { error } : {}
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
async function* readNdjsonStream(body) {
|
|
330
|
+
const reader = body.getReader();
|
|
331
|
+
const decoder = new TextDecoder();
|
|
332
|
+
let buffer = "";
|
|
333
|
+
try {
|
|
334
|
+
while (true) {
|
|
335
|
+
const { done, value } = await reader.read();
|
|
336
|
+
buffer += decoder.decode(value, { stream: !done });
|
|
337
|
+
const lines = buffer.split("\n");
|
|
338
|
+
buffer = lines.pop() ?? "";
|
|
339
|
+
for (const line of lines) {
|
|
340
|
+
const trimmed2 = line.trim();
|
|
341
|
+
if (!trimmed2) continue;
|
|
342
|
+
try {
|
|
343
|
+
const parsed = JSON.parse(trimmed2);
|
|
344
|
+
yield parsed;
|
|
345
|
+
} catch {
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (done) break;
|
|
349
|
+
}
|
|
350
|
+
const trimmed = buffer.trim();
|
|
351
|
+
if (trimmed) {
|
|
352
|
+
try {
|
|
353
|
+
const parsed = JSON.parse(trimmed);
|
|
354
|
+
yield parsed;
|
|
355
|
+
} catch {
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
} finally {
|
|
359
|
+
reader.releaseLock();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function streamPathAt(path, streamIndex) {
|
|
363
|
+
if (streamIndex === 0) return path;
|
|
364
|
+
return `${path}${path.includes("?") ? "&" : "?"}startIndex=${streamIndex}`;
|
|
365
|
+
}
|
|
366
|
+
function abortableDelay(delayMs, signal) {
|
|
367
|
+
if (signal.aborted) return Promise.resolve();
|
|
368
|
+
return new Promise((resolve) => {
|
|
369
|
+
const finish = () => {
|
|
370
|
+
clearTimeout(timeout);
|
|
371
|
+
signal.removeEventListener("abort", finish);
|
|
372
|
+
resolve();
|
|
373
|
+
};
|
|
374
|
+
const timeout = setTimeout(finish, delayMs);
|
|
375
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
var SubagentChildStreamCoordinator = class {
|
|
379
|
+
constructor(client, handlers, parentSignal) {
|
|
380
|
+
this.client = client;
|
|
381
|
+
this.handlers = handlers;
|
|
382
|
+
this.parentSignal = parentSignal;
|
|
383
|
+
}
|
|
384
|
+
client;
|
|
385
|
+
handlers;
|
|
386
|
+
parentSignal;
|
|
387
|
+
controllers = /* @__PURE__ */ new Map();
|
|
388
|
+
tasks = /* @__PURE__ */ new Map();
|
|
389
|
+
begin(event) {
|
|
390
|
+
this.beginPath(event.data.childStreamPath);
|
|
391
|
+
}
|
|
392
|
+
async waitForAll() {
|
|
393
|
+
let observedTaskCount = -1;
|
|
394
|
+
while (observedTaskCount !== this.tasks.size) {
|
|
395
|
+
observedTaskCount = this.tasks.size;
|
|
396
|
+
await Promise.all(this.tasks.values());
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
abortAll() {
|
|
400
|
+
for (const controller of this.controllers.values()) controller.abort();
|
|
401
|
+
this.controllers.clear();
|
|
402
|
+
}
|
|
403
|
+
beginPath(childStreamPath) {
|
|
404
|
+
if (this.tasks.has(childStreamPath)) return;
|
|
405
|
+
const controller = new AbortController();
|
|
406
|
+
const abort = () => controller.abort();
|
|
407
|
+
if (this.parentSignal.aborted) {
|
|
408
|
+
controller.abort();
|
|
409
|
+
} else {
|
|
410
|
+
this.parentSignal.addEventListener("abort", abort, { once: true });
|
|
411
|
+
}
|
|
412
|
+
this.controllers.set(childStreamPath, controller);
|
|
413
|
+
const task = this.consume(childStreamPath, controller.signal).finally(
|
|
414
|
+
() => {
|
|
415
|
+
this.parentSignal.removeEventListener("abort", abort);
|
|
416
|
+
if (this.controllers.get(childStreamPath) === controller) {
|
|
417
|
+
this.controllers.delete(childStreamPath);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
);
|
|
421
|
+
this.tasks.set(childStreamPath, task);
|
|
422
|
+
}
|
|
423
|
+
async consume(path, signal) {
|
|
424
|
+
let streamIndex = 0;
|
|
425
|
+
let consecutiveRetries = 0;
|
|
426
|
+
let retryDelayMs = INITIAL_RETRY_DELAY_MS;
|
|
427
|
+
while (!signal.aborted && consecutiveRetries < MAX_CONSECUTIVE_RETRIES) {
|
|
428
|
+
let receivedEvent = false;
|
|
429
|
+
try {
|
|
430
|
+
const response = await this.client.fetch(
|
|
431
|
+
streamPathAt(path, streamIndex),
|
|
432
|
+
{
|
|
433
|
+
cache: "no-store",
|
|
434
|
+
signal
|
|
435
|
+
}
|
|
436
|
+
);
|
|
437
|
+
if (!response.ok || response.body === null) {
|
|
438
|
+
await response.body?.cancel().catch(() => {
|
|
439
|
+
});
|
|
440
|
+
throw new Error(`Child stream returned ${response.status}.`);
|
|
441
|
+
}
|
|
442
|
+
for await (const rawEvent of readNdjsonStream(response.body)) {
|
|
443
|
+
if (signal.aborted) return;
|
|
444
|
+
receivedEvent = true;
|
|
445
|
+
streamIndex += 1;
|
|
446
|
+
const event = parseChildStreamEvent(rawEvent);
|
|
447
|
+
if (event.type === "session.boundary") return;
|
|
448
|
+
if (event.type === "subagent.called") {
|
|
449
|
+
this.beginPath(event.childStreamPath);
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
if (event.type !== "action.result") continue;
|
|
453
|
+
this.handlers.onToolResult?.(event.result);
|
|
454
|
+
if (event.hasOutput) {
|
|
455
|
+
this.handlers.onActionResult?.(event.result.output);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
} catch {
|
|
459
|
+
if (signal.aborted) return;
|
|
460
|
+
}
|
|
461
|
+
consecutiveRetries = receivedEvent ? 0 : consecutiveRetries + 1;
|
|
462
|
+
retryDelayMs = receivedEvent ? INITIAL_RETRY_DELAY_MS : Math.min(retryDelayMs * 2, MAX_RETRY_DELAY_MS);
|
|
463
|
+
await abortableDelay(retryDelayMs, signal);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
|
|
271
468
|
// src/runtime/tool-ui.ts
|
|
272
469
|
var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
|
|
273
470
|
var AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION = "webless.structured-tool-input.v1";
|
|
@@ -281,7 +478,7 @@ function formatAgentStructuredToolInput(surface, values) {
|
|
|
281
478
|
};
|
|
282
479
|
return `${AGENT_STRUCTURED_TOOL_INPUT_HEADER} ${JSON.stringify(payload)}`;
|
|
283
480
|
}
|
|
284
|
-
function
|
|
481
|
+
function isRecord3(value) {
|
|
285
482
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
286
483
|
}
|
|
287
484
|
function isJsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -330,7 +527,7 @@ function isFieldKind(value) {
|
|
|
330
527
|
].includes(value);
|
|
331
528
|
}
|
|
332
529
|
function parseField(value) {
|
|
333
|
-
if (!
|
|
530
|
+
if (!isRecord3(value)) return null;
|
|
334
531
|
if (!hasOnlyKeys(value, [
|
|
335
532
|
"description",
|
|
336
533
|
"kind",
|
|
@@ -381,7 +578,7 @@ function parseField(value) {
|
|
|
381
578
|
if (!Array.isArray(value.options) || value.options.length > 100)
|
|
382
579
|
return null;
|
|
383
580
|
for (const option of value.options) {
|
|
384
|
-
if (!
|
|
581
|
+
if (!isRecord3(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
|
|
385
582
|
return null;
|
|
386
583
|
}
|
|
387
584
|
}
|
|
@@ -404,7 +601,7 @@ function parseField(value) {
|
|
|
404
601
|
};
|
|
405
602
|
}
|
|
406
603
|
function parseStep(value) {
|
|
407
|
-
if (!
|
|
604
|
+
if (!isRecord3(value)) return null;
|
|
408
605
|
if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
|
|
409
606
|
return null;
|
|
410
607
|
}
|
|
@@ -424,7 +621,7 @@ function parseStep(value) {
|
|
|
424
621
|
};
|
|
425
622
|
}
|
|
426
623
|
function parseAction(value) {
|
|
427
|
-
if (!
|
|
624
|
+
if (!isRecord3(value)) return null;
|
|
428
625
|
if (!hasOnlyKeys(value, ["id", "label"])) return null;
|
|
429
626
|
const label = boundedString(value.label, 80);
|
|
430
627
|
if (value.id !== "submit" && value.id !== "back" && value.id !== "next" && value.id !== "reset" || !label) {
|
|
@@ -436,7 +633,7 @@ function parseAction(value) {
|
|
|
436
633
|
};
|
|
437
634
|
}
|
|
438
635
|
function parseAgentToolUiSurface(value) {
|
|
439
|
-
if (!
|
|
636
|
+
if (!isRecord3(value) || value.schemaVersion !== AGENT_TOOL_UI_SCHEMA_VERSION)
|
|
440
637
|
return null;
|
|
441
638
|
if (!hasOnlyKeys(value, [
|
|
442
639
|
"actions",
|
|
@@ -474,7 +671,7 @@ function parseAgentToolUiSurface(value) {
|
|
|
474
671
|
if (value.operationId !== void 0 && !operationId) return null;
|
|
475
672
|
if (value.requestId !== void 0 && !requestId) return null;
|
|
476
673
|
if (value.submitLabel !== void 0 && !submitLabel) return null;
|
|
477
|
-
const values = value.values !== void 0 &&
|
|
674
|
+
const values = value.values !== void 0 && isRecord3(value.values) ? value.values : void 0;
|
|
478
675
|
if (value.values !== void 0) {
|
|
479
676
|
if (!values || !Object.values(values).every((item) => isJsonValue(item)))
|
|
480
677
|
return null;
|
|
@@ -511,8 +708,7 @@ function applyMessageEvent(event, rendered, handlers, workItems) {
|
|
|
511
708
|
if (event.type === "message.completed") {
|
|
512
709
|
handlers.onComplete?.();
|
|
513
710
|
}
|
|
514
|
-
|
|
515
|
-
if (event.type === "input.requested") emitInputRequests(event, handlers);
|
|
711
|
+
emitVisitorInteractionEvent(event, handlers);
|
|
516
712
|
if (event.type !== "message.appended") return rendered;
|
|
517
713
|
const { messageDelta, messageSoFar } = event.data;
|
|
518
714
|
let delta = messageDelta;
|
|
@@ -562,6 +758,13 @@ function emitInputRequests(event, handlers) {
|
|
|
562
758
|
})
|
|
563
759
|
);
|
|
564
760
|
}
|
|
761
|
+
function emitVisitorInteractionEvent(event, handlers) {
|
|
762
|
+
if (event.type === "action.result") emitActionResult(event, handlers);
|
|
763
|
+
if (event.type === "input.requested") emitInputRequests(event, handlers);
|
|
764
|
+
if (event.type === "subagent.event") {
|
|
765
|
+
emitVisitorInteractionEvent(event.data.event, handlers);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
565
768
|
function isResumeTurnMessage(received, candidate) {
|
|
566
769
|
if (received === candidate) return true;
|
|
567
770
|
return Boolean(candidate) && received.endsWith(`
|
|
@@ -734,11 +937,14 @@ var AgentSession = class {
|
|
|
734
937
|
clientHost;
|
|
735
938
|
session;
|
|
736
939
|
activeResponse;
|
|
940
|
+
childStreams;
|
|
737
941
|
capability;
|
|
738
942
|
getActiveSessionId() {
|
|
739
943
|
return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
|
|
740
944
|
}
|
|
741
945
|
reset() {
|
|
946
|
+
this.childStreams?.abortAll();
|
|
947
|
+
this.childStreams = void 0;
|
|
742
948
|
if (this.activeResponse) {
|
|
743
949
|
void this.activeResponse.cancel().catch(() => {
|
|
744
950
|
});
|
|
@@ -834,6 +1040,12 @@ var AgentSession = class {
|
|
|
834
1040
|
this.persistSessionCursor(session);
|
|
835
1041
|
}
|
|
836
1042
|
this.activeResponse = response;
|
|
1043
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1044
|
+
client,
|
|
1045
|
+
handlers,
|
|
1046
|
+
signal
|
|
1047
|
+
);
|
|
1048
|
+
this.childStreams = childStreams;
|
|
837
1049
|
let streamIndex = session?.state.streamIndex ?? 0;
|
|
838
1050
|
let rendered = "";
|
|
839
1051
|
const workItems = /* @__PURE__ */ new Map();
|
|
@@ -841,6 +1053,7 @@ var AgentSession = class {
|
|
|
841
1053
|
try {
|
|
842
1054
|
for await (const event of response) {
|
|
843
1055
|
if (signal.aborted) break;
|
|
1056
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
844
1057
|
if (event.type === "input.requested") requestedInput = true;
|
|
845
1058
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
846
1059
|
streamIndex += 1;
|
|
@@ -853,8 +1066,11 @@ var AgentSession = class {
|
|
|
853
1066
|
);
|
|
854
1067
|
}
|
|
855
1068
|
}
|
|
1069
|
+
await childStreams.waitForAll();
|
|
856
1070
|
} finally {
|
|
1071
|
+
childStreams.abortAll();
|
|
857
1072
|
this.activeResponse = void 0;
|
|
1073
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
858
1074
|
if (session) {
|
|
859
1075
|
this.persistSessionCursor(session);
|
|
860
1076
|
}
|
|
@@ -890,64 +1106,80 @@ var AgentSession = class {
|
|
|
890
1106
|
}
|
|
891
1107
|
let rendered = renderTurn(turnEvents);
|
|
892
1108
|
const workItems = /* @__PURE__ */ new Map();
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
rendered = initialText + rendered;
|
|
905
|
-
}
|
|
906
|
-
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
907
|
-
streamIndex: snapshot.session.streamIndex
|
|
908
|
-
});
|
|
909
|
-
this.session = session;
|
|
910
|
-
this.persistSessionCursor(session);
|
|
911
|
-
let snapshotBoundary;
|
|
912
|
-
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
913
|
-
const event = turnEvents[index];
|
|
914
|
-
if (event && isTurnBoundary(event)) {
|
|
915
|
-
snapshotBoundary = event;
|
|
916
|
-
break;
|
|
1109
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1110
|
+
client,
|
|
1111
|
+
handlers,
|
|
1112
|
+
signal
|
|
1113
|
+
);
|
|
1114
|
+
this.childStreams = childStreams;
|
|
1115
|
+
try {
|
|
1116
|
+
for (const event of turnEvents) {
|
|
1117
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1118
|
+
applyWorkEvent(event, handlers, workItems);
|
|
1119
|
+
emitVisitorInteractionEvent(event, handlers);
|
|
917
1120
|
}
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
1121
|
+
if (rendered.startsWith(initialText)) {
|
|
1122
|
+
const missedText = rendered.slice(initialText.length);
|
|
1123
|
+
if (missedText) handlers.onDelta(missedText);
|
|
1124
|
+
} else if (initialText.startsWith(rendered)) {
|
|
1125
|
+
rendered = initialText;
|
|
1126
|
+
} else if (!initialText.startsWith(rendered)) {
|
|
1127
|
+
rendered = initialText + rendered;
|
|
1128
|
+
}
|
|
1129
|
+
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
1130
|
+
streamIndex: snapshot.session.streamIndex
|
|
1131
|
+
});
|
|
1132
|
+
this.session = session;
|
|
1133
|
+
this.persistSessionCursor(session);
|
|
1134
|
+
let snapshotBoundary;
|
|
1135
|
+
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
1136
|
+
const event = turnEvents[index];
|
|
1137
|
+
if (event && isTurnBoundary(event)) {
|
|
1138
|
+
snapshotBoundary = event;
|
|
1139
|
+
break;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
if (snapshotBoundary) {
|
|
1143
|
+
if (snapshotBoundary.type === "session.failed") {
|
|
1144
|
+
throw new Error(
|
|
1145
|
+
snapshotBoundary.data.message || snapshotBoundary.data.code
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
handlers.onComplete?.();
|
|
1149
|
+
await childStreams.waitForAll();
|
|
1150
|
+
if (!rendered.trim() && !hasInputRequest) {
|
|
1151
|
+
throw new Error("Empty response from runtime");
|
|
1152
|
+
}
|
|
1153
|
+
return rendered.trim();
|
|
1154
|
+
}
|
|
1155
|
+
let streamIndex = snapshot.session.streamIndex;
|
|
1156
|
+
for await (const event of session.stream({ signal })) {
|
|
1157
|
+
if (signal.aborted) break;
|
|
1158
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
1159
|
+
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
1160
|
+
streamIndex += 1;
|
|
1161
|
+
savePersistedAgentSession(
|
|
1162
|
+
this.visitorSessionId,
|
|
1163
|
+
session.state.sessionId,
|
|
1164
|
+
streamIndex,
|
|
1165
|
+
this.storeOptions
|
|
923
1166
|
);
|
|
1167
|
+
if (isTurnBoundary(event)) break;
|
|
924
1168
|
}
|
|
925
|
-
|
|
926
|
-
|
|
1169
|
+
await childStreams.waitForAll();
|
|
1170
|
+
session = client.sessions.attach(session.state.sessionId, {
|
|
1171
|
+
streamIndex
|
|
1172
|
+
});
|
|
1173
|
+
this.session = session;
|
|
1174
|
+
this.persistSessionCursor(session);
|
|
1175
|
+
if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
|
|
927
1176
|
throw new Error("Empty response from runtime");
|
|
928
1177
|
}
|
|
929
1178
|
return rendered.trim();
|
|
1179
|
+
} finally {
|
|
1180
|
+
childStreams.abortAll();
|
|
1181
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
930
1182
|
}
|
|
931
|
-
let streamIndex = snapshot.session.streamIndex;
|
|
932
|
-
for await (const event of session.stream({ signal })) {
|
|
933
|
-
if (signal.aborted) break;
|
|
934
|
-
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
935
|
-
streamIndex += 1;
|
|
936
|
-
savePersistedAgentSession(
|
|
937
|
-
this.visitorSessionId,
|
|
938
|
-
session.state.sessionId,
|
|
939
|
-
streamIndex,
|
|
940
|
-
this.storeOptions
|
|
941
|
-
);
|
|
942
|
-
if (isTurnBoundary(event)) break;
|
|
943
|
-
}
|
|
944
|
-
session = client.sessions.attach(session.state.sessionId, { streamIndex });
|
|
945
|
-
this.session = session;
|
|
946
|
-
this.persistSessionCursor(session);
|
|
947
|
-
if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
|
|
948
|
-
throw new Error("Empty response from runtime");
|
|
949
|
-
}
|
|
950
|
-
return rendered.trim();
|
|
951
1183
|
}
|
|
952
1184
|
async respondTurn(responses, signal, handlers) {
|
|
953
1185
|
const client = this.ensureClient();
|
|
@@ -968,6 +1200,12 @@ var AgentSession = class {
|
|
|
968
1200
|
() => session.respond(inputResponses, { signal })
|
|
969
1201
|
);
|
|
970
1202
|
this.activeResponse = response;
|
|
1203
|
+
const childStreams = new SubagentChildStreamCoordinator(
|
|
1204
|
+
client,
|
|
1205
|
+
handlers,
|
|
1206
|
+
signal
|
|
1207
|
+
);
|
|
1208
|
+
this.childStreams = childStreams;
|
|
971
1209
|
let streamIndex = session.state.streamIndex;
|
|
972
1210
|
let rendered = "";
|
|
973
1211
|
let requestedInput = false;
|
|
@@ -975,6 +1213,7 @@ var AgentSession = class {
|
|
|
975
1213
|
try {
|
|
976
1214
|
for await (const event of response) {
|
|
977
1215
|
if (signal.aborted) break;
|
|
1216
|
+
if (event.type === "subagent.called") childStreams.begin(event);
|
|
978
1217
|
if (event.type === "input.requested") requestedInput = true;
|
|
979
1218
|
rendered = applyMessageEvent(event, rendered, handlers, workItems);
|
|
980
1219
|
streamIndex += 1;
|
|
@@ -985,8 +1224,11 @@ var AgentSession = class {
|
|
|
985
1224
|
this.storeOptions
|
|
986
1225
|
);
|
|
987
1226
|
}
|
|
1227
|
+
await childStreams.waitForAll();
|
|
988
1228
|
} finally {
|
|
1229
|
+
childStreams.abortAll();
|
|
989
1230
|
this.activeResponse = void 0;
|
|
1231
|
+
if (this.childStreams === childStreams) this.childStreams = void 0;
|
|
990
1232
|
this.session = client.sessions.attach(session.state.sessionId, {
|
|
991
1233
|
streamIndex
|
|
992
1234
|
});
|
|
@@ -998,6 +1240,7 @@ var AgentSession = class {
|
|
|
998
1240
|
return rendered.trim();
|
|
999
1241
|
}
|
|
1000
1242
|
cancelActive() {
|
|
1243
|
+
this.childStreams?.abortAll();
|
|
1001
1244
|
if (this.activeResponse) {
|
|
1002
1245
|
this.activeResponse.cancel().catch(() => {
|
|
1003
1246
|
});
|
|
@@ -1113,7 +1356,7 @@ var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1113
1356
|
"presentationKinds",
|
|
1114
1357
|
"ui"
|
|
1115
1358
|
]);
|
|
1116
|
-
function
|
|
1359
|
+
function isRecord4(value) {
|
|
1117
1360
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1118
1361
|
}
|
|
1119
1362
|
function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -1140,7 +1383,7 @@ function decodeEnvelope(value) {
|
|
|
1140
1383
|
}
|
|
1141
1384
|
function parseAgentToolResultEnvelope(value) {
|
|
1142
1385
|
const decoded = decodeEnvelope(value);
|
|
1143
|
-
if (!
|
|
1386
|
+
if (!isRecord4(decoded)) return null;
|
|
1144
1387
|
const keys = Object.keys(decoded);
|
|
1145
1388
|
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) {
|
|
1146
1389
|
return null;
|