@astralbeam/sdk 0.15.2 → 0.17.0
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/README.md +16 -8
- package/dist/api-BaIPbj-Q.js +709 -0
- package/dist/api.d.ts +2 -2
- package/dist/api.js +2 -2
- package/dist/client.d.ts +21 -7
- package/dist/client.js +1 -1
- package/dist/{core-BGDo_tQ4.js → core-DeMY6_wQ.js} +2276 -203
- package/dist/core.d.ts +2 -2
- package/dist/core.js +1 -1
- package/dist/index-CfGnT6Od.d.ts +938 -0
- package/dist/{index-DUznpmNz.d.ts → index-NT05_Yw_.d.ts} +245 -69
- package/dist/listings-BH_hPkxx.js +1 -0
- package/dist/react.d.ts +14 -6
- package/dist/react.js +22 -7
- package/dist/rolldown-runtime-QTnfLwEv.js +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +6 -2
- package/dist/styles.generated-D8sDOLu3.js +98 -0
- package/dist/widget-BdiuWvPf.js +24 -0
- package/package.json +6 -6
- package/dist/api-DUe8JSVU.d.ts +0 -372
- package/dist/api-r11gRy91.js +0 -323
- package/dist/index-BVVgDSdq.d.ts +0 -1
- package/dist/listings-6eaCXB6G.js +0 -21
- package/dist/styles.generated-Bub4csY_.js +0 -60
- package/dist/widget-Bjm0sUjE.js +0 -26
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ct as isAstralBeamApiError, O as getCurrentUser, S as getChatFile, St as astralBeamChatFetch, X as getRunChatUrl, Y as getResolveChatToolResultUrl, b as getChatAttachment, ct as listChatThreads, g as createChatThread, ot as listChatMessages, vt as updateChatThread, wt as resolveApiUrl, x as getChatConfig, xt as uploadChatFile, y as deleteChatThread } from "./api-BaIPbj-Q.js";
|
|
2
2
|
import { d as JWTInvalid, h as strictDecoder, r as isObject, s as decode } from "./type_checks-C-WTHaWs.js";
|
|
3
3
|
//#region \0rolldown/runtime.js
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
4
5
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
6
|
+
var __exportAll = (all, no_symbols) => {
|
|
7
|
+
let target = {};
|
|
8
|
+
for (var name in all) __defProp(target, name, {
|
|
9
|
+
get: all[name],
|
|
10
|
+
enumerable: true
|
|
11
|
+
});
|
|
12
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
13
|
+
return target;
|
|
14
|
+
};
|
|
5
15
|
//#endregion
|
|
6
16
|
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/util/decode_jwt.js
|
|
7
17
|
function decodeJwt(jwt) {
|
|
@@ -26,7 +36,7 @@ function decodeJwt(jwt) {
|
|
|
26
36
|
return result;
|
|
27
37
|
}
|
|
28
38
|
//#endregion
|
|
29
|
-
//#region node_modules/.deno/@tanstack+ai-client@0.
|
|
39
|
+
//#region node_modules/.deno/@tanstack+ai-client@0.39.2/node_modules/@tanstack/ai-client/dist/esm/response-stream.js
|
|
30
40
|
var UnsupportedResponseStreamError = class extends Error {
|
|
31
41
|
missingFeature;
|
|
32
42
|
constructor(missingFeature) {
|
|
@@ -48,14 +58,14 @@ function createResponseStreamTextDecoder() {
|
|
|
48
58
|
return new globalThis.TextDecoder();
|
|
49
59
|
}
|
|
50
60
|
//#endregion
|
|
51
|
-
//#region node_modules/.deno/@tanstack+ai-client@0.
|
|
61
|
+
//#region node_modules/.deno/@tanstack+ai-client@0.39.2/node_modules/@tanstack/ai-client/dist/esm/sse-utils.js
|
|
52
62
|
function parseSseDataLine(line) {
|
|
53
63
|
if (!line.startsWith("data:")) return line;
|
|
54
64
|
const data = line.slice(5);
|
|
55
65
|
return data.startsWith(" ") ? data.slice(1) : data;
|
|
56
66
|
}
|
|
57
67
|
//#endregion
|
|
58
|
-
//#region node_modules/.deno/@tanstack+ai-client@0.
|
|
68
|
+
//#region node_modules/.deno/@tanstack+ai-client@0.39.2/node_modules/@tanstack/ai-client/dist/esm/message-date-normalizer.js
|
|
59
69
|
function validDate(value) {
|
|
60
70
|
if (value instanceof Date) return Number.isNaN(value.getTime()) ? void 0 : value;
|
|
61
71
|
if (typeof value !== "string") return void 0;
|
|
@@ -87,7 +97,7 @@ function normalizeMessagesDates(messages) {
|
|
|
87
97
|
return messages.map(normalizeMessageDates);
|
|
88
98
|
}
|
|
89
99
|
//#endregion
|
|
90
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
100
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/utilities/ag-ui-usage.js
|
|
91
101
|
function definedDetails(value) {
|
|
92
102
|
return Object.keys(value).length > 0 ? value : void 0;
|
|
93
103
|
}
|
|
@@ -132,7 +142,7 @@ function fromSpecTokenUsage(usage, leftover) {
|
|
|
132
142
|
};
|
|
133
143
|
}
|
|
134
144
|
//#endregion
|
|
135
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
145
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/utilities/merge-metadata.js
|
|
136
146
|
function isPlainRecord$1(value) {
|
|
137
147
|
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
138
148
|
}
|
|
@@ -211,7 +221,19 @@ let EventType = /* @__PURE__ */ function(EventType) {
|
|
|
211
221
|
return EventType;
|
|
212
222
|
}({});
|
|
213
223
|
//#endregion
|
|
214
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
224
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/utilities/reasoning-encrypted-value.js
|
|
225
|
+
/**
|
|
226
|
+
* Id prefix for the reasoning message of a redacted thinking block (Anthropic
|
|
227
|
+
* `redacted_thinking`). AG-UI's `encryptedValue` does not say what kind of
|
|
228
|
+
* bytes it holds (ag-ui-protocol/ag-ui#2884), so the id that `entityId` points
|
|
229
|
+
* to says it. AG-UI clients keep message ids, but they drop event metadata.
|
|
230
|
+
*/
|
|
231
|
+
var REDACTED_THINKING_ID_PREFIX = "redacted_thinking-";
|
|
232
|
+
function isRedactedThinkingId(id) {
|
|
233
|
+
return typeof id === "string" && id.startsWith("redacted_thinking-");
|
|
234
|
+
}
|
|
235
|
+
//#endregion
|
|
236
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/interrupt-serialization.js
|
|
215
237
|
var SHA256_K = new Uint32Array([
|
|
216
238
|
1116352408,
|
|
217
239
|
1899447441,
|
|
@@ -386,7 +408,7 @@ function cloneAndDeepFreezeJson(value) {
|
|
|
386
408
|
return clone;
|
|
387
409
|
}
|
|
388
410
|
//#endregion
|
|
389
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
411
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/interrupts.js
|
|
390
412
|
function canonicalizeInterruptResolutions(resolutions) {
|
|
391
413
|
const frozen = cloneAndDeepFreezeJson([...resolutions].sort((left, right) => left.interruptId.localeCompare(right.interruptId)));
|
|
392
414
|
const canonicalResolutions = canonicalInterruptJson(frozen);
|
|
@@ -397,7 +419,7 @@ function canonicalizeInterruptResolutions(resolutions) {
|
|
|
397
419
|
});
|
|
398
420
|
}
|
|
399
421
|
//#endregion
|
|
400
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
422
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/activities/chat/tools/schema-converter.js
|
|
401
423
|
/**
|
|
402
424
|
* Build a JSONSchema object from any plain key/value source. The `JSONSchema`
|
|
403
425
|
* interface's `[key: string]: any` index signature makes every property
|
|
@@ -550,16 +572,17 @@ function makeStructuredOutputCompatible(schema, originalRequired = []) {
|
|
|
550
572
|
*
|
|
551
573
|
* - Standard JSON Schemas are rebuilt structurally (dropping `$schema`, which
|
|
552
574
|
* LLM providers ignore) and given the explicit `type`/`properties`/`required`
|
|
553
|
-
* defaults object shapes need downstream.
|
|
575
|
+
* defaults object shapes need downstream. `io` picks the `input` (default)
|
|
576
|
+
* or `output` view.
|
|
554
577
|
* - Plain `JSONSchema` inputs are rebuilt into the typed view; non-object inputs
|
|
555
578
|
* are surfaced untouched (they can't be widened).
|
|
556
579
|
* - Standard Schema validators lacking a `~standard.jsonSchema` converter throw
|
|
557
580
|
* with actionable guidance, rather than shipping `{ '~standard': … }` to the
|
|
558
581
|
* provider and producing an opaque downstream error.
|
|
559
582
|
*/
|
|
560
|
-
function toTypedJsonSchema(schema) {
|
|
583
|
+
function toTypedJsonSchema(schema, io = "input") {
|
|
561
584
|
if (isStandardJSONSchema(schema)) {
|
|
562
|
-
const result = toJsonSchema$2(schema["~standard"].jsonSchema
|
|
585
|
+
const result = toJsonSchema$2(schema["~standard"].jsonSchema[io]({ target: "draft-07" }));
|
|
563
586
|
if ("properties" in result && !result.type) result.type = "object";
|
|
564
587
|
if (result.type === "object" && !("properties" in result)) result.properties = {};
|
|
565
588
|
if (result.type === "object" && !("required" in result)) result.required = [];
|
|
@@ -631,9 +654,9 @@ function toTypedJsonSchema(schema) {
|
|
|
631
654
|
*/
|
|
632
655
|
function convertSchemaToJsonSchema(schema, options = {}) {
|
|
633
656
|
if (!schema) return void 0;
|
|
634
|
-
const { forStructuredOutput = false } = options;
|
|
657
|
+
const { forStructuredOutput = false, io } = options;
|
|
635
658
|
if (!forStructuredOutput && !isStandardJSONSchema(schema) && !isStandardSchema(schema)) return schema;
|
|
636
|
-
const base = toTypedJsonSchema(schema);
|
|
659
|
+
const base = toTypedJsonSchema(schema, io);
|
|
637
660
|
if (!base || typeof base !== "object") return base;
|
|
638
661
|
if (!forStructuredOutput) return base;
|
|
639
662
|
return makeStructuredOutputCompatible(base, base.required || []).schema;
|
|
@@ -664,7 +687,7 @@ async function validateWithStandardSchema(schema, data) {
|
|
|
664
687
|
};
|
|
665
688
|
}
|
|
666
689
|
//#endregion
|
|
667
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
690
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/activities/chat/tools/approval-schema.js
|
|
668
691
|
var jsonSchemaKeywords = /* @__PURE__ */ new Set([
|
|
669
692
|
"$schema",
|
|
670
693
|
"$id",
|
|
@@ -776,7 +799,7 @@ function hashSchemaInput(schema) {
|
|
|
776
799
|
return digestInterruptJson(canonicalInterruptJson(schemaToWire(schema).jsonSchema ?? { standardValidator: "unserialized" }));
|
|
777
800
|
}
|
|
778
801
|
//#endregion
|
|
779
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
802
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/interrupt-resume.js
|
|
780
803
|
/**
|
|
781
804
|
* The `Interrupt.metadata` key under which this package's resume binding
|
|
782
805
|
* travels.
|
|
@@ -897,7 +920,7 @@ function readInterruptBinding(descriptor) {
|
|
|
897
920
|
};
|
|
898
921
|
}
|
|
899
922
|
//#endregion
|
|
900
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
923
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/interrupt-definition.js
|
|
901
924
|
var INTERRUPT_PAYLOAD_METADATA_KEY = "tanstack:interruptPayload";
|
|
902
925
|
function schemaJson(schema, name) {
|
|
903
926
|
if (!isStandardJSONSchema(schema)) throw new TypeError(`${name} must be a Standard Schema with a JSON Schema converter.`);
|
|
@@ -922,7 +945,7 @@ function hashInterruptDefinitionSchema(schema) {
|
|
|
922
945
|
return digestInterruptJson(schemaJson(schema, "Interrupt schema").canonicalJson);
|
|
923
946
|
}
|
|
924
947
|
//#endregion
|
|
925
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
948
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/generic-interrupt-continuation.js
|
|
926
949
|
/**
|
|
927
950
|
* `ResumeEntry.metadata` key for a first-party generic request.
|
|
928
951
|
*
|
|
@@ -961,7 +984,7 @@ function genericInterruptContinuationFromDescriptor(interrupt) {
|
|
|
961
984
|
};
|
|
962
985
|
}
|
|
963
986
|
//#endregion
|
|
964
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
987
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/utilities/provider-executed.js
|
|
965
988
|
/**
|
|
966
989
|
* Narrow a tool call's opaque `metadata` to the provider-executed convention.
|
|
967
990
|
* Returns the typed metadata when the call is provider-executed, else `null`.
|
|
@@ -991,7 +1014,7 @@ function isAssistantSegmentOf(id, parentId) {
|
|
|
991
1014
|
return id?.startsWith(`${parentId}-segment-`) === true;
|
|
992
1015
|
}
|
|
993
1016
|
//#endregion
|
|
994
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
1017
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/utilities/tool-result.js
|
|
995
1018
|
var CONTENT_PART_TYPES = /* @__PURE__ */ new Set([
|
|
996
1019
|
"text",
|
|
997
1020
|
"image",
|
|
@@ -1052,7 +1075,7 @@ function normalizeToolResult(result) {
|
|
|
1052
1075
|
return JSON.stringify(result);
|
|
1053
1076
|
}
|
|
1054
1077
|
//#endregion
|
|
1055
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
1078
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/utilities/subagent-wire.js
|
|
1056
1079
|
function isRecord$2(value) {
|
|
1057
1080
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1058
1081
|
}
|
|
@@ -1156,7 +1179,7 @@ function splitSubagentWire(messages) {
|
|
|
1156
1179
|
};
|
|
1157
1180
|
}
|
|
1158
1181
|
//#endregion
|
|
1159
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
1182
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/activities/chat/messages.js
|
|
1160
1183
|
function isRecord$1(value) {
|
|
1161
1184
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1162
1185
|
}
|
|
@@ -1184,6 +1207,10 @@ function encryptedValueFrom(value) {
|
|
|
1184
1207
|
}
|
|
1185
1208
|
return nonEmptyString(tanstackMetadata(value)?.signature);
|
|
1186
1209
|
}
|
|
1210
|
+
/** `{ redacted: true }` when a reasoning message's id marks a redacted block. */
|
|
1211
|
+
function redactedFrom(value) {
|
|
1212
|
+
return "id" in value && isRedactedThinkingId(value.id) ? { redacted: true } : {};
|
|
1213
|
+
}
|
|
1187
1214
|
/**
|
|
1188
1215
|
* Collapse an array of ContentParts into the most compact ModelMessage content:
|
|
1189
1216
|
* - Empty array → null
|
|
@@ -1345,6 +1372,7 @@ function assistantMetadata(uiMessage) {
|
|
|
1345
1372
|
*/
|
|
1346
1373
|
function uiMessageToModelMessages(uiMessage) {
|
|
1347
1374
|
if (uiMessage.role === "system") return [];
|
|
1375
|
+
if (uiMessage.role === "activity") return [];
|
|
1348
1376
|
if (uiMessage.role !== "assistant") return [buildUserOrToolMessage(uiMessage)];
|
|
1349
1377
|
return buildAssistantMessages(uiMessage);
|
|
1350
1378
|
}
|
|
@@ -1456,7 +1484,8 @@ function buildAssistantMessages(uiMessage) {
|
|
|
1456
1484
|
if (current.toolCalls.some(isProviderExecutedToolCall)) flushSegment();
|
|
1457
1485
|
pendingThinking.push({
|
|
1458
1486
|
content: part.content,
|
|
1459
|
-
...part.signature && { signature: part.signature }
|
|
1487
|
+
...part.signature && { signature: part.signature },
|
|
1488
|
+
...part.redacted && { redacted: true }
|
|
1460
1489
|
});
|
|
1461
1490
|
}
|
|
1462
1491
|
break;
|
|
@@ -1473,6 +1502,7 @@ function buildAssistantMessages(uiMessage) {
|
|
|
1473
1502
|
}
|
|
1474
1503
|
break;
|
|
1475
1504
|
case "ui-resource": break;
|
|
1505
|
+
case "activity": break;
|
|
1476
1506
|
case "subagent": {
|
|
1477
1507
|
const block = part.subagent.parentToolCallId === void 0 ? subagentHistoryText(part) : "";
|
|
1478
1508
|
if (block !== "") {
|
|
@@ -1538,7 +1568,8 @@ function modelMessageToUIMessage(modelMessage, id) {
|
|
|
1538
1568
|
parts.push({
|
|
1539
1569
|
type: "thinking",
|
|
1540
1570
|
content: thinking.content,
|
|
1541
|
-
...thinking.signature && { signature: thinking.signature }
|
|
1571
|
+
...thinking.signature && { signature: thinking.signature },
|
|
1572
|
+
...thinking.redacted && { redacted: true }
|
|
1542
1573
|
});
|
|
1543
1574
|
}
|
|
1544
1575
|
const structuredOutput = modelMessage.structuredOutput ?? snapshotStructuredOutput(tanstackMetadata(modelMessage)?.structuredOutput);
|
|
@@ -1683,10 +1714,20 @@ function aguiSnapshotMessageToUIMessage(message) {
|
|
|
1683
1714
|
parts: content || signature !== void 0 ? [{
|
|
1684
1715
|
type: "thinking",
|
|
1685
1716
|
content,
|
|
1686
|
-
...signature !== void 0 ? { signature } : {}
|
|
1717
|
+
...signature !== void 0 ? { signature } : {},
|
|
1718
|
+
...redactedFrom(message)
|
|
1687
1719
|
}] : []
|
|
1688
1720
|
});
|
|
1689
1721
|
}
|
|
1722
|
+
case "activity": return applySnapshotMetadata(message, {
|
|
1723
|
+
id,
|
|
1724
|
+
role: "activity",
|
|
1725
|
+
parts: [{
|
|
1726
|
+
type: "activity",
|
|
1727
|
+
activityType: message.activityType,
|
|
1728
|
+
content: structuredClone(message.content)
|
|
1729
|
+
}]
|
|
1730
|
+
});
|
|
1690
1731
|
default: return applySnapshotMetadata(message, {
|
|
1691
1732
|
id,
|
|
1692
1733
|
role: "assistant",
|
|
@@ -1732,15 +1773,23 @@ function applySnapshotMetadata(source, ui) {
|
|
|
1732
1773
|
}
|
|
1733
1774
|
function snapshotStructuredOutput(value) {
|
|
1734
1775
|
if (value == null || value.status !== "streaming" && value.status !== "complete" && value.status !== "error" || typeof value.raw !== "string") return;
|
|
1735
|
-
|
|
1776
|
+
const base = {
|
|
1736
1777
|
type: "structured-output",
|
|
1737
|
-
status: value.status,
|
|
1738
1778
|
raw: value.raw,
|
|
1739
1779
|
...value.partial !== void 0 ? { partial: value.partial } : {},
|
|
1740
|
-
...value.data !== void 0 ? { data: value.data } : {},
|
|
1741
1780
|
...value.reasoning ? { reasoning: value.reasoning } : {},
|
|
1742
1781
|
...value.errorMessage !== void 0 ? { errorMessage: value.errorMessage } : {}
|
|
1743
1782
|
};
|
|
1783
|
+
if (value.status !== "complete") return {
|
|
1784
|
+
...base,
|
|
1785
|
+
status: value.status
|
|
1786
|
+
};
|
|
1787
|
+
if (value.data === void 0) return void 0;
|
|
1788
|
+
return {
|
|
1789
|
+
...base,
|
|
1790
|
+
status: "complete",
|
|
1791
|
+
data: value.data
|
|
1792
|
+
};
|
|
1744
1793
|
}
|
|
1745
1794
|
/**
|
|
1746
1795
|
* Convert AG-UI user message content into `UIMessage` parts.
|
|
@@ -1798,7 +1847,7 @@ function generateMessageId() {
|
|
|
1798
1847
|
return `msg-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
|
1799
1848
|
}
|
|
1800
1849
|
//#endregion
|
|
1801
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
1850
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/utilities/ag-ui-wire.js
|
|
1802
1851
|
function isRecord(value) {
|
|
1803
1852
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1804
1853
|
}
|
|
@@ -1829,15 +1878,35 @@ function rebuiltToolMetadata(metadata, createdAt, id, content, anchorOwnsUiResou
|
|
|
1829
1878
|
* on assistant messages are additionally emitted as fan-out
|
|
1830
1879
|
* `{role:'tool',...}` and `{role:'reasoning',...}` entries for strict AG-UI
|
|
1831
1880
|
* server consumers. Set `includeSnapshotStructuredOutput` to retain complete
|
|
1832
|
-
* structured-output metadata for UI snapshots.
|
|
1881
|
+
* structured-output metadata for UI snapshots. Set `includeActivity` to emit
|
|
1882
|
+
* AG-UI `ActivityMessage` rows (MESSAGES_SNAPSHOT only — default omit so
|
|
1883
|
+
* RunAgentInput never carries activity).
|
|
1833
1884
|
*/
|
|
1834
1885
|
function uiMessagesToWire(messages, options) {
|
|
1835
1886
|
const wire = [];
|
|
1836
1887
|
const usedWireIds = new Set(messages.flatMap((message) => "id" in message && message.id && message.role !== "tool" ? [message.id] : []));
|
|
1837
1888
|
const includeSnapshotStructuredOutput = options?.includeSnapshotStructuredOutput ?? false;
|
|
1889
|
+
const includeActivity = options?.includeActivity ?? false;
|
|
1838
1890
|
const assistantIds = /* @__PURE__ */ new Set();
|
|
1839
1891
|
for (const msg of messages) if (msg.role === "assistant" && msg.id !== void 0) assistantIds.add(msg.id);
|
|
1840
1892
|
for (const msg of messages) {
|
|
1893
|
+
if (msg.role === "activity") {
|
|
1894
|
+
if (includeActivity && "parts" in msg) {
|
|
1895
|
+
const part = msg.parts.find((p) => p.type === "activity");
|
|
1896
|
+
if (part) {
|
|
1897
|
+
const activity = {
|
|
1898
|
+
id: msg.id,
|
|
1899
|
+
role: "activity",
|
|
1900
|
+
activityType: part.activityType,
|
|
1901
|
+
content: structuredClone(part.content),
|
|
1902
|
+
...msg.metadata != null && { metadata: msg.metadata },
|
|
1903
|
+
...part.subagentRunId !== void 0 && { subagentRunId: part.subagentRunId }
|
|
1904
|
+
};
|
|
1905
|
+
wire.push(activity);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
continue;
|
|
1909
|
+
}
|
|
1841
1910
|
if (!("parts" in msg) && msg.role === "tool" && msg.toolCallId) {
|
|
1842
1911
|
const id = uniqueToolWireId(toolWireId(msg.id, msg.toolCallId, assistantIds), usedWireIds);
|
|
1843
1912
|
const metadata = rebuiltToolMetadata(msg.metadata, msg.createdAt, msg.id, msg.content);
|
|
@@ -2081,7 +2150,8 @@ function collectToolCalls(parts) {
|
|
|
2081
2150
|
return calls.length > 0 ? calls : void 0;
|
|
2082
2151
|
}
|
|
2083
2152
|
function deriveReasoningId(messageId, part) {
|
|
2084
|
-
|
|
2153
|
+
const id = `${messageId}-reasoning-${part.id ?? hashContent(part.content)}`;
|
|
2154
|
+
return part.type === "thinking" && part.redacted ? `${REDACTED_THINKING_ID_PREFIX}${id}` : id;
|
|
2085
2155
|
}
|
|
2086
2156
|
function deriveToolMessageId(toolCallId) {
|
|
2087
2157
|
return `tool-${toolCallId}`;
|
|
@@ -2111,7 +2181,7 @@ function hashContent(s) {
|
|
|
2111
2181
|
return Math.abs(h).toString(36);
|
|
2112
2182
|
}
|
|
2113
2183
|
//#endregion
|
|
2114
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
2184
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/utilities/restore-inbound-chunk.js
|
|
2115
2185
|
/**
|
|
2116
2186
|
* Rebuild TanStack `TokenUsage` (`promptTokens`) from spec `usage[]` plus
|
|
2117
2187
|
* leftover fields in `metadata.tanstack.usage`. Restore in-process aliases
|
|
@@ -2148,7 +2218,7 @@ function restoreInboundChunk(chunk) {
|
|
|
2148
2218
|
return next;
|
|
2149
2219
|
}
|
|
2150
2220
|
//#endregion
|
|
2151
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
2221
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/activities/chat/tools/tool-definition.js
|
|
2152
2222
|
/**
|
|
2153
2223
|
* Create an isomorphic tool definition that can be used directly or instantiated for server/client
|
|
2154
2224
|
*
|
|
@@ -2246,7 +2316,7 @@ function toolDefinition(config) {
|
|
|
2246
2316
|
};
|
|
2247
2317
|
}
|
|
2248
2318
|
//#endregion
|
|
2249
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
2319
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/utilities/chunk-ids.js
|
|
2250
2320
|
function stringField(value) {
|
|
2251
2321
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
2252
2322
|
}
|
|
@@ -2349,7 +2419,7 @@ var require_options = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
2349
2419
|
exports.default = exports.Allow;
|
|
2350
2420
|
}));
|
|
2351
2421
|
//#endregion
|
|
2352
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
2422
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/activities/chat/stream/json-parser.js
|
|
2353
2423
|
var import_dist = (/* @__PURE__ */ __commonJSMin(((exports) => {
|
|
2354
2424
|
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
2355
2425
|
if (k2 === void 0) k2 = k;
|
|
@@ -2571,7 +2641,7 @@ function parsePartialJSON(jsonString) {
|
|
|
2571
2641
|
return defaultJSONParser.parse(jsonString);
|
|
2572
2642
|
}
|
|
2573
2643
|
//#endregion
|
|
2574
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
2644
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/activities/chat/stream/strategies.js
|
|
2575
2645
|
/**
|
|
2576
2646
|
* Immediate Strategy - emit on every chunk (default behavior)
|
|
2577
2647
|
*/
|
|
@@ -2581,7 +2651,7 @@ var ImmediateStrategy = class {
|
|
|
2581
2651
|
}
|
|
2582
2652
|
};
|
|
2583
2653
|
//#endregion
|
|
2584
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
2654
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/utilities/errors.js
|
|
2585
2655
|
/**
|
|
2586
2656
|
* Convert an AG-UI RUN_ERROR event to the Error shape exposed to consumers.
|
|
2587
2657
|
* Preserves the provider code and sanitized raw event when available, while
|
|
@@ -2595,7 +2665,730 @@ function runErrorEventToError(chunk) {
|
|
|
2595
2665
|
return error;
|
|
2596
2666
|
}
|
|
2597
2667
|
//#endregion
|
|
2598
|
-
//#region node_modules/.deno
|
|
2668
|
+
//#region node_modules/.deno/fast-json-patch@3.1.1/node_modules/fast-json-patch/module/helpers.mjs
|
|
2669
|
+
/*!
|
|
2670
|
+
* https://github.com/Starcounter-Jack/JSON-Patch
|
|
2671
|
+
* (c) 2017-2022 Joachim Wester
|
|
2672
|
+
* MIT licensed
|
|
2673
|
+
*/
|
|
2674
|
+
var __extends = (function() {
|
|
2675
|
+
var extendStatics = function(d, b) {
|
|
2676
|
+
extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d, b) {
|
|
2677
|
+
d.__proto__ = b;
|
|
2678
|
+
} || function(d, b) {
|
|
2679
|
+
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
|
2680
|
+
};
|
|
2681
|
+
return extendStatics(d, b);
|
|
2682
|
+
};
|
|
2683
|
+
return function(d, b) {
|
|
2684
|
+
extendStatics(d, b);
|
|
2685
|
+
function __() {
|
|
2686
|
+
this.constructor = d;
|
|
2687
|
+
}
|
|
2688
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
2689
|
+
};
|
|
2690
|
+
})();
|
|
2691
|
+
var _hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
2692
|
+
function hasOwnProperty(obj, key) {
|
|
2693
|
+
return _hasOwnProperty.call(obj, key);
|
|
2694
|
+
}
|
|
2695
|
+
function _objectKeys(obj) {
|
|
2696
|
+
if (Array.isArray(obj)) {
|
|
2697
|
+
var keys_1 = new Array(obj.length);
|
|
2698
|
+
for (var k = 0; k < keys_1.length; k++) keys_1[k] = "" + k;
|
|
2699
|
+
return keys_1;
|
|
2700
|
+
}
|
|
2701
|
+
if (Object.keys) return Object.keys(obj);
|
|
2702
|
+
var keys = [];
|
|
2703
|
+
for (var i in obj) if (hasOwnProperty(obj, i)) keys.push(i);
|
|
2704
|
+
return keys;
|
|
2705
|
+
}
|
|
2706
|
+
/**
|
|
2707
|
+
* Deeply clone the object.
|
|
2708
|
+
* https://jsperf.com/deep-copy-vs-json-stringify-json-parse/25 (recursiveDeepCopy)
|
|
2709
|
+
* @param {any} obj value to clone
|
|
2710
|
+
* @return {any} cloned obj
|
|
2711
|
+
*/
|
|
2712
|
+
function _deepClone(obj) {
|
|
2713
|
+
switch (typeof obj) {
|
|
2714
|
+
case "object": return JSON.parse(JSON.stringify(obj));
|
|
2715
|
+
case "undefined": return null;
|
|
2716
|
+
default: return obj;
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
function isInteger(str) {
|
|
2720
|
+
var i = 0;
|
|
2721
|
+
var len = str.length;
|
|
2722
|
+
var charCode;
|
|
2723
|
+
while (i < len) {
|
|
2724
|
+
charCode = str.charCodeAt(i);
|
|
2725
|
+
if (charCode >= 48 && charCode <= 57) {
|
|
2726
|
+
i++;
|
|
2727
|
+
continue;
|
|
2728
|
+
}
|
|
2729
|
+
return false;
|
|
2730
|
+
}
|
|
2731
|
+
return true;
|
|
2732
|
+
}
|
|
2733
|
+
/**
|
|
2734
|
+
* Escapes a json pointer path
|
|
2735
|
+
* @param path The raw pointer
|
|
2736
|
+
* @return the Escaped path
|
|
2737
|
+
*/
|
|
2738
|
+
function escapePathComponent(path) {
|
|
2739
|
+
if (path.indexOf("/") === -1 && path.indexOf("~") === -1) return path;
|
|
2740
|
+
return path.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
2741
|
+
}
|
|
2742
|
+
/**
|
|
2743
|
+
* Unescapes a json pointer path
|
|
2744
|
+
* @param path The escaped pointer
|
|
2745
|
+
* @return The unescaped path
|
|
2746
|
+
*/
|
|
2747
|
+
function unescapePathComponent(path) {
|
|
2748
|
+
return path.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
2749
|
+
}
|
|
2750
|
+
/**
|
|
2751
|
+
* Recursively checks whether an object has any undefined values inside.
|
|
2752
|
+
*/
|
|
2753
|
+
function hasUndefined(obj) {
|
|
2754
|
+
if (obj === void 0) return true;
|
|
2755
|
+
if (obj) {
|
|
2756
|
+
if (Array.isArray(obj)) {
|
|
2757
|
+
for (var i_1 = 0, len = obj.length; i_1 < len; i_1++) if (hasUndefined(obj[i_1])) return true;
|
|
2758
|
+
} else if (typeof obj === "object") {
|
|
2759
|
+
var objKeys = _objectKeys(obj);
|
|
2760
|
+
var objKeysLength = objKeys.length;
|
|
2761
|
+
for (var i = 0; i < objKeysLength; i++) if (hasUndefined(obj[objKeys[i]])) return true;
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
return false;
|
|
2765
|
+
}
|
|
2766
|
+
function patchErrorMessageFormatter(message, args) {
|
|
2767
|
+
var messageParts = [message];
|
|
2768
|
+
for (var key in args) {
|
|
2769
|
+
var value = typeof args[key] === "object" ? JSON.stringify(args[key], null, 2) : args[key];
|
|
2770
|
+
if (typeof value !== "undefined") messageParts.push(key + ": " + value);
|
|
2771
|
+
}
|
|
2772
|
+
return messageParts.join("\n");
|
|
2773
|
+
}
|
|
2774
|
+
var PatchError = function(_super) {
|
|
2775
|
+
__extends(PatchError, _super);
|
|
2776
|
+
function PatchError(message, name, index, operation, tree) {
|
|
2777
|
+
var _newTarget = this.constructor;
|
|
2778
|
+
var _this = _super.call(this, patchErrorMessageFormatter(message, {
|
|
2779
|
+
name,
|
|
2780
|
+
index,
|
|
2781
|
+
operation,
|
|
2782
|
+
tree
|
|
2783
|
+
})) || this;
|
|
2784
|
+
_this.name = name;
|
|
2785
|
+
_this.index = index;
|
|
2786
|
+
_this.operation = operation;
|
|
2787
|
+
_this.tree = tree;
|
|
2788
|
+
Object.setPrototypeOf(_this, _newTarget.prototype);
|
|
2789
|
+
_this.message = patchErrorMessageFormatter(message, {
|
|
2790
|
+
name,
|
|
2791
|
+
index,
|
|
2792
|
+
operation,
|
|
2793
|
+
tree
|
|
2794
|
+
});
|
|
2795
|
+
return _this;
|
|
2796
|
+
}
|
|
2797
|
+
return PatchError;
|
|
2798
|
+
}(Error);
|
|
2799
|
+
//#endregion
|
|
2800
|
+
//#region node_modules/.deno/fast-json-patch@3.1.1/node_modules/fast-json-patch/module/core.mjs
|
|
2801
|
+
var core_exports = /* @__PURE__ */ __exportAll({
|
|
2802
|
+
JsonPatchError: () => JsonPatchError,
|
|
2803
|
+
_areEquals: () => _areEquals,
|
|
2804
|
+
applyOperation: () => applyOperation,
|
|
2805
|
+
applyPatch: () => applyPatch,
|
|
2806
|
+
applyReducer: () => applyReducer,
|
|
2807
|
+
deepClone: () => deepClone,
|
|
2808
|
+
getValueByPointer: () => getValueByPointer,
|
|
2809
|
+
validate: () => validate,
|
|
2810
|
+
validator: () => validator
|
|
2811
|
+
});
|
|
2812
|
+
var JsonPatchError = PatchError;
|
|
2813
|
+
var deepClone = _deepClone;
|
|
2814
|
+
var objOps = {
|
|
2815
|
+
add: function(obj, key, document) {
|
|
2816
|
+
obj[key] = this.value;
|
|
2817
|
+
return { newDocument: document };
|
|
2818
|
+
},
|
|
2819
|
+
remove: function(obj, key, document) {
|
|
2820
|
+
var removed = obj[key];
|
|
2821
|
+
delete obj[key];
|
|
2822
|
+
return {
|
|
2823
|
+
newDocument: document,
|
|
2824
|
+
removed
|
|
2825
|
+
};
|
|
2826
|
+
},
|
|
2827
|
+
replace: function(obj, key, document) {
|
|
2828
|
+
var removed = obj[key];
|
|
2829
|
+
obj[key] = this.value;
|
|
2830
|
+
return {
|
|
2831
|
+
newDocument: document,
|
|
2832
|
+
removed
|
|
2833
|
+
};
|
|
2834
|
+
},
|
|
2835
|
+
move: function(obj, key, document) {
|
|
2836
|
+
var removed = getValueByPointer(document, this.path);
|
|
2837
|
+
if (removed) removed = _deepClone(removed);
|
|
2838
|
+
var originalValue = applyOperation(document, {
|
|
2839
|
+
op: "remove",
|
|
2840
|
+
path: this.from
|
|
2841
|
+
}).removed;
|
|
2842
|
+
applyOperation(document, {
|
|
2843
|
+
op: "add",
|
|
2844
|
+
path: this.path,
|
|
2845
|
+
value: originalValue
|
|
2846
|
+
});
|
|
2847
|
+
return {
|
|
2848
|
+
newDocument: document,
|
|
2849
|
+
removed
|
|
2850
|
+
};
|
|
2851
|
+
},
|
|
2852
|
+
copy: function(obj, key, document) {
|
|
2853
|
+
var valueToCopy = getValueByPointer(document, this.from);
|
|
2854
|
+
applyOperation(document, {
|
|
2855
|
+
op: "add",
|
|
2856
|
+
path: this.path,
|
|
2857
|
+
value: _deepClone(valueToCopy)
|
|
2858
|
+
});
|
|
2859
|
+
return { newDocument: document };
|
|
2860
|
+
},
|
|
2861
|
+
test: function(obj, key, document) {
|
|
2862
|
+
return {
|
|
2863
|
+
newDocument: document,
|
|
2864
|
+
test: _areEquals(obj[key], this.value)
|
|
2865
|
+
};
|
|
2866
|
+
},
|
|
2867
|
+
_get: function(obj, key, document) {
|
|
2868
|
+
this.value = obj[key];
|
|
2869
|
+
return { newDocument: document };
|
|
2870
|
+
}
|
|
2871
|
+
};
|
|
2872
|
+
var arrOps = {
|
|
2873
|
+
add: function(arr, i, document) {
|
|
2874
|
+
if (isInteger(i)) arr.splice(i, 0, this.value);
|
|
2875
|
+
else arr[i] = this.value;
|
|
2876
|
+
return {
|
|
2877
|
+
newDocument: document,
|
|
2878
|
+
index: i
|
|
2879
|
+
};
|
|
2880
|
+
},
|
|
2881
|
+
remove: function(arr, i, document) {
|
|
2882
|
+
return {
|
|
2883
|
+
newDocument: document,
|
|
2884
|
+
removed: arr.splice(i, 1)[0]
|
|
2885
|
+
};
|
|
2886
|
+
},
|
|
2887
|
+
replace: function(arr, i, document) {
|
|
2888
|
+
var removed = arr[i];
|
|
2889
|
+
arr[i] = this.value;
|
|
2890
|
+
return {
|
|
2891
|
+
newDocument: document,
|
|
2892
|
+
removed
|
|
2893
|
+
};
|
|
2894
|
+
},
|
|
2895
|
+
move: objOps.move,
|
|
2896
|
+
copy: objOps.copy,
|
|
2897
|
+
test: objOps.test,
|
|
2898
|
+
_get: objOps._get
|
|
2899
|
+
};
|
|
2900
|
+
/**
|
|
2901
|
+
* Retrieves a value from a JSON document by a JSON pointer.
|
|
2902
|
+
* Returns the value.
|
|
2903
|
+
*
|
|
2904
|
+
* @param document The document to get the value from
|
|
2905
|
+
* @param pointer an escaped JSON pointer
|
|
2906
|
+
* @return The retrieved value
|
|
2907
|
+
*/
|
|
2908
|
+
function getValueByPointer(document, pointer) {
|
|
2909
|
+
if (pointer == "") return document;
|
|
2910
|
+
var getOriginalDestination = {
|
|
2911
|
+
op: "_get",
|
|
2912
|
+
path: pointer
|
|
2913
|
+
};
|
|
2914
|
+
applyOperation(document, getOriginalDestination);
|
|
2915
|
+
return getOriginalDestination.value;
|
|
2916
|
+
}
|
|
2917
|
+
/**
|
|
2918
|
+
* Apply a single JSON Patch Operation on a JSON document.
|
|
2919
|
+
* Returns the {newDocument, result} of the operation.
|
|
2920
|
+
* It modifies the `document` and `operation` objects - it gets the values by reference.
|
|
2921
|
+
* If you would like to avoid touching your values, clone them:
|
|
2922
|
+
* `jsonpatch.applyOperation(document, jsonpatch._deepClone(operation))`.
|
|
2923
|
+
*
|
|
2924
|
+
* @param document The document to patch
|
|
2925
|
+
* @param operation The operation to apply
|
|
2926
|
+
* @param validateOperation `false` is without validation, `true` to use default jsonpatch's validation, or you can pass a `validateOperation` callback to be used for validation.
|
|
2927
|
+
* @param mutateDocument Whether to mutate the original document or clone it before applying
|
|
2928
|
+
* @param banPrototypeModifications Whether to ban modifications to `__proto__`, defaults to `true`.
|
|
2929
|
+
* @return `{newDocument, result}` after the operation
|
|
2930
|
+
*/
|
|
2931
|
+
function applyOperation(document, operation, validateOperation, mutateDocument, banPrototypeModifications, index) {
|
|
2932
|
+
if (validateOperation === void 0) validateOperation = false;
|
|
2933
|
+
if (mutateDocument === void 0) mutateDocument = true;
|
|
2934
|
+
if (banPrototypeModifications === void 0) banPrototypeModifications = true;
|
|
2935
|
+
if (index === void 0) index = 0;
|
|
2936
|
+
if (validateOperation) if (typeof validateOperation == "function") validateOperation(operation, 0, document, operation.path);
|
|
2937
|
+
else validator(operation, 0);
|
|
2938
|
+
if (operation.path === "") {
|
|
2939
|
+
var returnValue = { newDocument: document };
|
|
2940
|
+
if (operation.op === "add") {
|
|
2941
|
+
returnValue.newDocument = operation.value;
|
|
2942
|
+
return returnValue;
|
|
2943
|
+
} else if (operation.op === "replace") {
|
|
2944
|
+
returnValue.newDocument = operation.value;
|
|
2945
|
+
returnValue.removed = document;
|
|
2946
|
+
return returnValue;
|
|
2947
|
+
} else if (operation.op === "move" || operation.op === "copy") {
|
|
2948
|
+
returnValue.newDocument = getValueByPointer(document, operation.from);
|
|
2949
|
+
if (operation.op === "move") returnValue.removed = document;
|
|
2950
|
+
return returnValue;
|
|
2951
|
+
} else if (operation.op === "test") {
|
|
2952
|
+
returnValue.test = _areEquals(document, operation.value);
|
|
2953
|
+
if (returnValue.test === false) throw new JsonPatchError("Test operation failed", "TEST_OPERATION_FAILED", index, operation, document);
|
|
2954
|
+
returnValue.newDocument = document;
|
|
2955
|
+
return returnValue;
|
|
2956
|
+
} else if (operation.op === "remove") {
|
|
2957
|
+
returnValue.removed = document;
|
|
2958
|
+
returnValue.newDocument = null;
|
|
2959
|
+
return returnValue;
|
|
2960
|
+
} else if (operation.op === "_get") {
|
|
2961
|
+
operation.value = document;
|
|
2962
|
+
return returnValue;
|
|
2963
|
+
} else if (validateOperation) throw new JsonPatchError("Operation `op` property is not one of operations defined in RFC-6902", "OPERATION_OP_INVALID", index, operation, document);
|
|
2964
|
+
else return returnValue;
|
|
2965
|
+
} else {
|
|
2966
|
+
if (!mutateDocument) document = _deepClone(document);
|
|
2967
|
+
var keys = (operation.path || "").split("/");
|
|
2968
|
+
var obj = document;
|
|
2969
|
+
var t = 1;
|
|
2970
|
+
var len = keys.length;
|
|
2971
|
+
var existingPathFragment = void 0;
|
|
2972
|
+
var key = void 0;
|
|
2973
|
+
var validateFunction = void 0;
|
|
2974
|
+
if (typeof validateOperation == "function") validateFunction = validateOperation;
|
|
2975
|
+
else validateFunction = validator;
|
|
2976
|
+
while (true) {
|
|
2977
|
+
key = keys[t];
|
|
2978
|
+
if (key && key.indexOf("~") != -1) key = unescapePathComponent(key);
|
|
2979
|
+
if (banPrototypeModifications && (key == "__proto__" || key == "prototype" && t > 0 && keys[t - 1] == "constructor")) throw new TypeError("JSON-Patch: modifying `__proto__` or `constructor/prototype` prop is banned for security reasons, if this was on purpose, please set `banPrototypeModifications` flag false and pass it to this function. More info in fast-json-patch README");
|
|
2980
|
+
if (validateOperation) {
|
|
2981
|
+
if (existingPathFragment === void 0) {
|
|
2982
|
+
if (obj[key] === void 0) existingPathFragment = keys.slice(0, t).join("/");
|
|
2983
|
+
else if (t == len - 1) existingPathFragment = operation.path;
|
|
2984
|
+
if (existingPathFragment !== void 0) validateFunction(operation, 0, document, existingPathFragment);
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
t++;
|
|
2988
|
+
if (Array.isArray(obj)) {
|
|
2989
|
+
if (key === "-") key = obj.length;
|
|
2990
|
+
else if (validateOperation && !isInteger(key)) throw new JsonPatchError("Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index", "OPERATION_PATH_ILLEGAL_ARRAY_INDEX", index, operation, document);
|
|
2991
|
+
else if (isInteger(key)) key = ~~key;
|
|
2992
|
+
if (t >= len) {
|
|
2993
|
+
if (validateOperation && operation.op === "add" && key > obj.length) throw new JsonPatchError("The specified index MUST NOT be greater than the number of elements in the array", "OPERATION_VALUE_OUT_OF_BOUNDS", index, operation, document);
|
|
2994
|
+
var returnValue = arrOps[operation.op].call(operation, obj, key, document);
|
|
2995
|
+
if (returnValue.test === false) throw new JsonPatchError("Test operation failed", "TEST_OPERATION_FAILED", index, operation, document);
|
|
2996
|
+
return returnValue;
|
|
2997
|
+
}
|
|
2998
|
+
} else if (t >= len) {
|
|
2999
|
+
var returnValue = objOps[operation.op].call(operation, obj, key, document);
|
|
3000
|
+
if (returnValue.test === false) throw new JsonPatchError("Test operation failed", "TEST_OPERATION_FAILED", index, operation, document);
|
|
3001
|
+
return returnValue;
|
|
3002
|
+
}
|
|
3003
|
+
obj = obj[key];
|
|
3004
|
+
if (validateOperation && t < len && (!obj || typeof obj !== "object")) throw new JsonPatchError("Cannot perform operation at the desired path", "OPERATION_PATH_UNRESOLVABLE", index, operation, document);
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
/**
|
|
3009
|
+
* Apply a full JSON Patch array on a JSON document.
|
|
3010
|
+
* Returns the {newDocument, result} of the patch.
|
|
3011
|
+
* It modifies the `document` object and `patch` - it gets the values by reference.
|
|
3012
|
+
* If you would like to avoid touching your values, clone them:
|
|
3013
|
+
* `jsonpatch.applyPatch(document, jsonpatch._deepClone(patch))`.
|
|
3014
|
+
*
|
|
3015
|
+
* @param document The document to patch
|
|
3016
|
+
* @param patch The patch to apply
|
|
3017
|
+
* @param validateOperation `false` is without validation, `true` to use default jsonpatch's validation, or you can pass a `validateOperation` callback to be used for validation.
|
|
3018
|
+
* @param mutateDocument Whether to mutate the original document or clone it before applying
|
|
3019
|
+
* @param banPrototypeModifications Whether to ban modifications to `__proto__`, defaults to `true`.
|
|
3020
|
+
* @return An array of `{newDocument, result}` after the patch
|
|
3021
|
+
*/
|
|
3022
|
+
function applyPatch(document, patch, validateOperation, mutateDocument, banPrototypeModifications) {
|
|
3023
|
+
if (mutateDocument === void 0) mutateDocument = true;
|
|
3024
|
+
if (banPrototypeModifications === void 0) banPrototypeModifications = true;
|
|
3025
|
+
if (validateOperation) {
|
|
3026
|
+
if (!Array.isArray(patch)) throw new JsonPatchError("Patch sequence must be an array", "SEQUENCE_NOT_AN_ARRAY");
|
|
3027
|
+
}
|
|
3028
|
+
if (!mutateDocument) document = _deepClone(document);
|
|
3029
|
+
var results = new Array(patch.length);
|
|
3030
|
+
for (var i = 0, length_1 = patch.length; i < length_1; i++) {
|
|
3031
|
+
results[i] = applyOperation(document, patch[i], validateOperation, true, banPrototypeModifications, i);
|
|
3032
|
+
document = results[i].newDocument;
|
|
3033
|
+
}
|
|
3034
|
+
results.newDocument = document;
|
|
3035
|
+
return results;
|
|
3036
|
+
}
|
|
3037
|
+
/**
|
|
3038
|
+
* Apply a single JSON Patch Operation on a JSON document.
|
|
3039
|
+
* Returns the updated document.
|
|
3040
|
+
* Suitable as a reducer.
|
|
3041
|
+
*
|
|
3042
|
+
* @param document The document to patch
|
|
3043
|
+
* @param operation The operation to apply
|
|
3044
|
+
* @return The updated document
|
|
3045
|
+
*/
|
|
3046
|
+
function applyReducer(document, operation, index) {
|
|
3047
|
+
var operationResult = applyOperation(document, operation);
|
|
3048
|
+
if (operationResult.test === false) throw new JsonPatchError("Test operation failed", "TEST_OPERATION_FAILED", index, operation, document);
|
|
3049
|
+
return operationResult.newDocument;
|
|
3050
|
+
}
|
|
3051
|
+
/**
|
|
3052
|
+
* Validates a single operation. Called from `jsonpatch.validate`. Throws `JsonPatchError` in case of an error.
|
|
3053
|
+
* @param {object} operation - operation object (patch)
|
|
3054
|
+
* @param {number} index - index of operation in the sequence
|
|
3055
|
+
* @param {object} [document] - object where the operation is supposed to be applied
|
|
3056
|
+
* @param {string} [existingPathFragment] - comes along with `document`
|
|
3057
|
+
*/
|
|
3058
|
+
function validator(operation, index, document, existingPathFragment) {
|
|
3059
|
+
if (typeof operation !== "object" || operation === null || Array.isArray(operation)) throw new JsonPatchError("Operation is not an object", "OPERATION_NOT_AN_OBJECT", index, operation, document);
|
|
3060
|
+
else if (!objOps[operation.op]) throw new JsonPatchError("Operation `op` property is not one of operations defined in RFC-6902", "OPERATION_OP_INVALID", index, operation, document);
|
|
3061
|
+
else if (typeof operation.path !== "string") throw new JsonPatchError("Operation `path` property is not a string", "OPERATION_PATH_INVALID", index, operation, document);
|
|
3062
|
+
else if (operation.path.indexOf("/") !== 0 && operation.path.length > 0) throw new JsonPatchError("Operation `path` property must start with \"/\"", "OPERATION_PATH_INVALID", index, operation, document);
|
|
3063
|
+
else if ((operation.op === "move" || operation.op === "copy") && typeof operation.from !== "string") throw new JsonPatchError("Operation `from` property is not present (applicable in `move` and `copy` operations)", "OPERATION_FROM_REQUIRED", index, operation, document);
|
|
3064
|
+
else if ((operation.op === "add" || operation.op === "replace" || operation.op === "test") && operation.value === void 0) throw new JsonPatchError("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)", "OPERATION_VALUE_REQUIRED", index, operation, document);
|
|
3065
|
+
else if ((operation.op === "add" || operation.op === "replace" || operation.op === "test") && hasUndefined(operation.value)) throw new JsonPatchError("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)", "OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED", index, operation, document);
|
|
3066
|
+
else if (document) {
|
|
3067
|
+
if (operation.op == "add") {
|
|
3068
|
+
var pathLen = operation.path.split("/").length;
|
|
3069
|
+
var existingPathLen = existingPathFragment.split("/").length;
|
|
3070
|
+
if (pathLen !== existingPathLen + 1 && pathLen !== existingPathLen) throw new JsonPatchError("Cannot perform an `add` operation at the desired path", "OPERATION_PATH_CANNOT_ADD", index, operation, document);
|
|
3071
|
+
} else if (operation.op === "replace" || operation.op === "remove" || operation.op === "_get") {
|
|
3072
|
+
if (operation.path !== existingPathFragment) throw new JsonPatchError("Cannot perform the operation at a path that does not exist", "OPERATION_PATH_UNRESOLVABLE", index, operation, document);
|
|
3073
|
+
} else if (operation.op === "move" || operation.op === "copy") {
|
|
3074
|
+
var error = validate([{
|
|
3075
|
+
op: "_get",
|
|
3076
|
+
path: operation.from,
|
|
3077
|
+
value: void 0
|
|
3078
|
+
}], document);
|
|
3079
|
+
if (error && error.name === "OPERATION_PATH_UNRESOLVABLE") throw new JsonPatchError("Cannot perform the operation from a path that does not exist", "OPERATION_FROM_UNRESOLVABLE", index, operation, document);
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
/**
|
|
3084
|
+
* Validates a sequence of operations. If `document` parameter is provided, the sequence is additionally validated against the object document.
|
|
3085
|
+
* If error is encountered, returns a JsonPatchError object
|
|
3086
|
+
* @param sequence
|
|
3087
|
+
* @param document
|
|
3088
|
+
* @returns {JsonPatchError|undefined}
|
|
3089
|
+
*/
|
|
3090
|
+
function validate(sequence, document, externalValidator) {
|
|
3091
|
+
try {
|
|
3092
|
+
if (!Array.isArray(sequence)) throw new JsonPatchError("Patch sequence must be an array", "SEQUENCE_NOT_AN_ARRAY");
|
|
3093
|
+
if (document) applyPatch(_deepClone(document), _deepClone(sequence), externalValidator || true);
|
|
3094
|
+
else {
|
|
3095
|
+
externalValidator = externalValidator || validator;
|
|
3096
|
+
for (var i = 0; i < sequence.length; i++) externalValidator(sequence[i], i, document, void 0);
|
|
3097
|
+
}
|
|
3098
|
+
} catch (e) {
|
|
3099
|
+
if (e instanceof JsonPatchError) return e;
|
|
3100
|
+
else throw e;
|
|
3101
|
+
}
|
|
3102
|
+
}
|
|
3103
|
+
function _areEquals(a, b) {
|
|
3104
|
+
if (a === b) return true;
|
|
3105
|
+
if (a && b && typeof a == "object" && typeof b == "object") {
|
|
3106
|
+
var arrA = Array.isArray(a), arrB = Array.isArray(b), i, length, key;
|
|
3107
|
+
if (arrA && arrB) {
|
|
3108
|
+
length = a.length;
|
|
3109
|
+
if (length != b.length) return false;
|
|
3110
|
+
for (i = length; i-- !== 0;) if (!_areEquals(a[i], b[i])) return false;
|
|
3111
|
+
return true;
|
|
3112
|
+
}
|
|
3113
|
+
if (arrA != arrB) return false;
|
|
3114
|
+
var keys = Object.keys(a);
|
|
3115
|
+
length = keys.length;
|
|
3116
|
+
if (length !== Object.keys(b).length) return false;
|
|
3117
|
+
for (i = length; i-- !== 0;) if (!b.hasOwnProperty(keys[i])) return false;
|
|
3118
|
+
for (i = length; i-- !== 0;) {
|
|
3119
|
+
key = keys[i];
|
|
3120
|
+
if (!_areEquals(a[key], b[key])) return false;
|
|
3121
|
+
}
|
|
3122
|
+
return true;
|
|
3123
|
+
}
|
|
3124
|
+
return a !== a && b !== b;
|
|
3125
|
+
}
|
|
3126
|
+
//#endregion
|
|
3127
|
+
//#region node_modules/.deno/fast-json-patch@3.1.1/node_modules/fast-json-patch/module/duplex.mjs
|
|
3128
|
+
/*!
|
|
3129
|
+
* https://github.com/Starcounter-Jack/JSON-Patch
|
|
3130
|
+
* (c) 2017-2021 Joachim Wester
|
|
3131
|
+
* MIT license
|
|
3132
|
+
*/
|
|
3133
|
+
var duplex_exports = /* @__PURE__ */ __exportAll({
|
|
3134
|
+
compare: () => compare,
|
|
3135
|
+
generate: () => generate,
|
|
3136
|
+
observe: () => observe,
|
|
3137
|
+
unobserve: () => unobserve
|
|
3138
|
+
});
|
|
3139
|
+
var beforeDict = /* @__PURE__ */ new WeakMap();
|
|
3140
|
+
var Mirror = function() {
|
|
3141
|
+
function Mirror(obj) {
|
|
3142
|
+
this.observers = /* @__PURE__ */ new Map();
|
|
3143
|
+
this.obj = obj;
|
|
3144
|
+
}
|
|
3145
|
+
return Mirror;
|
|
3146
|
+
}();
|
|
3147
|
+
var ObserverInfo = function() {
|
|
3148
|
+
function ObserverInfo(callback, observer) {
|
|
3149
|
+
this.callback = callback;
|
|
3150
|
+
this.observer = observer;
|
|
3151
|
+
}
|
|
3152
|
+
return ObserverInfo;
|
|
3153
|
+
}();
|
|
3154
|
+
function getMirror(obj) {
|
|
3155
|
+
return beforeDict.get(obj);
|
|
3156
|
+
}
|
|
3157
|
+
function getObserverFromMirror(mirror, callback) {
|
|
3158
|
+
return mirror.observers.get(callback);
|
|
3159
|
+
}
|
|
3160
|
+
function removeObserverFromMirror(mirror, observer) {
|
|
3161
|
+
mirror.observers.delete(observer.callback);
|
|
3162
|
+
}
|
|
3163
|
+
/**
|
|
3164
|
+
* Detach an observer from an object
|
|
3165
|
+
*/
|
|
3166
|
+
function unobserve(root, observer) {
|
|
3167
|
+
observer.unobserve();
|
|
3168
|
+
}
|
|
3169
|
+
/**
|
|
3170
|
+
* Observes changes made to an object, which can then be retrieved using generate
|
|
3171
|
+
*/
|
|
3172
|
+
function observe(obj, callback) {
|
|
3173
|
+
var patches = [];
|
|
3174
|
+
var observer;
|
|
3175
|
+
var mirror = getMirror(obj);
|
|
3176
|
+
if (!mirror) {
|
|
3177
|
+
mirror = new Mirror(obj);
|
|
3178
|
+
beforeDict.set(obj, mirror);
|
|
3179
|
+
} else {
|
|
3180
|
+
var observerInfo = getObserverFromMirror(mirror, callback);
|
|
3181
|
+
observer = observerInfo && observerInfo.observer;
|
|
3182
|
+
}
|
|
3183
|
+
if (observer) return observer;
|
|
3184
|
+
observer = {};
|
|
3185
|
+
mirror.value = _deepClone(obj);
|
|
3186
|
+
if (callback) {
|
|
3187
|
+
observer.callback = callback;
|
|
3188
|
+
observer.next = null;
|
|
3189
|
+
var dirtyCheck = function() {
|
|
3190
|
+
generate(observer);
|
|
3191
|
+
};
|
|
3192
|
+
var fastCheck = function() {
|
|
3193
|
+
clearTimeout(observer.next);
|
|
3194
|
+
observer.next = setTimeout(dirtyCheck);
|
|
3195
|
+
};
|
|
3196
|
+
if (typeof window !== "undefined") {
|
|
3197
|
+
window.addEventListener("mouseup", fastCheck);
|
|
3198
|
+
window.addEventListener("keyup", fastCheck);
|
|
3199
|
+
window.addEventListener("mousedown", fastCheck);
|
|
3200
|
+
window.addEventListener("keydown", fastCheck);
|
|
3201
|
+
window.addEventListener("change", fastCheck);
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
observer.patches = patches;
|
|
3205
|
+
observer.object = obj;
|
|
3206
|
+
observer.unobserve = function() {
|
|
3207
|
+
generate(observer);
|
|
3208
|
+
clearTimeout(observer.next);
|
|
3209
|
+
removeObserverFromMirror(mirror, observer);
|
|
3210
|
+
if (typeof window !== "undefined") {
|
|
3211
|
+
window.removeEventListener("mouseup", fastCheck);
|
|
3212
|
+
window.removeEventListener("keyup", fastCheck);
|
|
3213
|
+
window.removeEventListener("mousedown", fastCheck);
|
|
3214
|
+
window.removeEventListener("keydown", fastCheck);
|
|
3215
|
+
window.removeEventListener("change", fastCheck);
|
|
3216
|
+
}
|
|
3217
|
+
};
|
|
3218
|
+
mirror.observers.set(callback, new ObserverInfo(callback, observer));
|
|
3219
|
+
return observer;
|
|
3220
|
+
}
|
|
3221
|
+
/**
|
|
3222
|
+
* Generate an array of patches from an observer
|
|
3223
|
+
*/
|
|
3224
|
+
function generate(observer, invertible) {
|
|
3225
|
+
if (invertible === void 0) invertible = false;
|
|
3226
|
+
var mirror = beforeDict.get(observer.object);
|
|
3227
|
+
_generate(mirror.value, observer.object, observer.patches, "", invertible);
|
|
3228
|
+
if (observer.patches.length) applyPatch(mirror.value, observer.patches);
|
|
3229
|
+
var temp = observer.patches;
|
|
3230
|
+
if (temp.length > 0) {
|
|
3231
|
+
observer.patches = [];
|
|
3232
|
+
if (observer.callback) observer.callback(temp);
|
|
3233
|
+
}
|
|
3234
|
+
return temp;
|
|
3235
|
+
}
|
|
3236
|
+
function _generate(mirror, obj, patches, path, invertible) {
|
|
3237
|
+
if (obj === mirror) return;
|
|
3238
|
+
if (typeof obj.toJSON === "function") obj = obj.toJSON();
|
|
3239
|
+
var newKeys = _objectKeys(obj);
|
|
3240
|
+
var oldKeys = _objectKeys(mirror);
|
|
3241
|
+
var deleted = false;
|
|
3242
|
+
for (var t = oldKeys.length - 1; t >= 0; t--) {
|
|
3243
|
+
var key = oldKeys[t];
|
|
3244
|
+
var oldVal = mirror[key];
|
|
3245
|
+
if (hasOwnProperty(obj, key) && !(obj[key] === void 0 && oldVal !== void 0 && Array.isArray(obj) === false)) {
|
|
3246
|
+
var newVal = obj[key];
|
|
3247
|
+
if (typeof oldVal == "object" && oldVal != null && typeof newVal == "object" && newVal != null && Array.isArray(oldVal) === Array.isArray(newVal)) _generate(oldVal, newVal, patches, path + "/" + escapePathComponent(key), invertible);
|
|
3248
|
+
else if (oldVal !== newVal) {
|
|
3249
|
+
if (invertible) patches.push({
|
|
3250
|
+
op: "test",
|
|
3251
|
+
path: path + "/" + escapePathComponent(key),
|
|
3252
|
+
value: _deepClone(oldVal)
|
|
3253
|
+
});
|
|
3254
|
+
patches.push({
|
|
3255
|
+
op: "replace",
|
|
3256
|
+
path: path + "/" + escapePathComponent(key),
|
|
3257
|
+
value: _deepClone(newVal)
|
|
3258
|
+
});
|
|
3259
|
+
}
|
|
3260
|
+
} else if (Array.isArray(mirror) === Array.isArray(obj)) {
|
|
3261
|
+
if (invertible) patches.push({
|
|
3262
|
+
op: "test",
|
|
3263
|
+
path: path + "/" + escapePathComponent(key),
|
|
3264
|
+
value: _deepClone(oldVal)
|
|
3265
|
+
});
|
|
3266
|
+
patches.push({
|
|
3267
|
+
op: "remove",
|
|
3268
|
+
path: path + "/" + escapePathComponent(key)
|
|
3269
|
+
});
|
|
3270
|
+
deleted = true;
|
|
3271
|
+
} else {
|
|
3272
|
+
if (invertible) patches.push({
|
|
3273
|
+
op: "test",
|
|
3274
|
+
path,
|
|
3275
|
+
value: mirror
|
|
3276
|
+
});
|
|
3277
|
+
patches.push({
|
|
3278
|
+
op: "replace",
|
|
3279
|
+
path,
|
|
3280
|
+
value: obj
|
|
3281
|
+
});
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
if (!deleted && newKeys.length == oldKeys.length) return;
|
|
3285
|
+
for (var t = 0; t < newKeys.length; t++) {
|
|
3286
|
+
var key = newKeys[t];
|
|
3287
|
+
if (!hasOwnProperty(mirror, key) && obj[key] !== void 0) patches.push({
|
|
3288
|
+
op: "add",
|
|
3289
|
+
path: path + "/" + escapePathComponent(key),
|
|
3290
|
+
value: _deepClone(obj[key])
|
|
3291
|
+
});
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
/**
|
|
3295
|
+
* Create an array of patches from the differences in two objects
|
|
3296
|
+
*/
|
|
3297
|
+
function compare(tree1, tree2, invertible) {
|
|
3298
|
+
if (invertible === void 0) invertible = false;
|
|
3299
|
+
var patches = [];
|
|
3300
|
+
_generate(tree1, tree2, patches, "", invertible);
|
|
3301
|
+
return patches;
|
|
3302
|
+
}
|
|
3303
|
+
//#endregion
|
|
3304
|
+
//#region node_modules/.deno/fast-json-patch@3.1.1/node_modules/fast-json-patch/index.mjs
|
|
3305
|
+
/**
|
|
3306
|
+
* Default export for backwards compat
|
|
3307
|
+
*/
|
|
3308
|
+
var fast_json_patch_default = Object.assign({}, core_exports, duplex_exports, {
|
|
3309
|
+
JsonPatchError: PatchError,
|
|
3310
|
+
deepClone: _deepClone,
|
|
3311
|
+
escapePathComponent,
|
|
3312
|
+
unescapePathComponent
|
|
3313
|
+
});
|
|
3314
|
+
//#endregion
|
|
3315
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/activities/chat/activity-records.js
|
|
3316
|
+
function isActivityPart(part) {
|
|
3317
|
+
return part.type === "activity";
|
|
3318
|
+
}
|
|
3319
|
+
function isActivityContent(value) {
|
|
3320
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
3321
|
+
}
|
|
3322
|
+
function applyActivitySnapshotToUIMessages(messages, chunk) {
|
|
3323
|
+
const { messageId, activityType, content } = chunk;
|
|
3324
|
+
const replace = chunk.replace ?? true;
|
|
3325
|
+
const existingIndex = messages.findIndex((m) => m.id === messageId);
|
|
3326
|
+
const existing = existingIndex >= 0 ? messages[existingIndex] : void 0;
|
|
3327
|
+
if (existing && existing.role !== "activity") {
|
|
3328
|
+
console.warn(`ACTIVITY_SNAPSHOT: Message '${messageId}' is not an activity message`);
|
|
3329
|
+
return messages;
|
|
3330
|
+
}
|
|
3331
|
+
if (existing && !replace) return messages;
|
|
3332
|
+
const metadata = mergeMetadata(existing?.role === "activity" ? existing.metadata : void 0, chunk.metadata);
|
|
3333
|
+
const next = {
|
|
3334
|
+
id: messageId,
|
|
3335
|
+
role: "activity",
|
|
3336
|
+
parts: [{
|
|
3337
|
+
type: "activity",
|
|
3338
|
+
activityType,
|
|
3339
|
+
content: structuredClone(content ?? {})
|
|
3340
|
+
}],
|
|
3341
|
+
...metadata != null ? { metadata } : {},
|
|
3342
|
+
...existing?.role === "activity" && existing.createdAt != null ? { createdAt: existing.createdAt } : {},
|
|
3343
|
+
...existing?.role === "activity" && existing.name != null ? { name: existing.name } : {}
|
|
3344
|
+
};
|
|
3345
|
+
if (existingIndex === -1) return [...messages, next];
|
|
3346
|
+
return messages.map((msg, index) => index === existingIndex ? next : msg);
|
|
3347
|
+
}
|
|
3348
|
+
function applyActivityDeltaToUIMessages(messages, chunk) {
|
|
3349
|
+
const { messageId, activityType, patch } = chunk;
|
|
3350
|
+
const existingIndex = messages.findIndex((m) => m.id === messageId);
|
|
3351
|
+
if (existingIndex === -1) {
|
|
3352
|
+
console.warn(`ACTIVITY_DELTA: No activity message '${messageId}'`);
|
|
3353
|
+
return messages;
|
|
3354
|
+
}
|
|
3355
|
+
const existing = messages[existingIndex];
|
|
3356
|
+
if (existing == null || existing.role !== "activity") {
|
|
3357
|
+
console.warn(`ACTIVITY_DELTA: Message '${messageId}' is not an activity message`);
|
|
3358
|
+
return messages;
|
|
3359
|
+
}
|
|
3360
|
+
const activityPart = existing.parts.find(isActivityPart);
|
|
3361
|
+
if (activityPart && activityPart.activityType !== activityType) {
|
|
3362
|
+
console.warn(`ACTIVITY_DELTA: activityType '${activityType}' does not match '${activityPart.activityType}' for '${messageId}'`);
|
|
3363
|
+
return messages;
|
|
3364
|
+
}
|
|
3365
|
+
const baseContent = structuredClone(activityPart?.content ?? {});
|
|
3366
|
+
try {
|
|
3367
|
+
const result = fast_json_patch_default.applyPatch(baseContent, patch ?? [], true, false);
|
|
3368
|
+
if (!isActivityContent(result.newDocument)) {
|
|
3369
|
+
console.warn(`ACTIVITY_DELTA: patched content for '${messageId}' is not an object`);
|
|
3370
|
+
return messages;
|
|
3371
|
+
}
|
|
3372
|
+
const nextPart = {
|
|
3373
|
+
type: "activity",
|
|
3374
|
+
activityType,
|
|
3375
|
+
content: structuredClone(result.newDocument)
|
|
3376
|
+
};
|
|
3377
|
+
const parts = activityPart ? existing.parts.map((part) => part.type === "activity" ? nextPart : part) : [nextPart];
|
|
3378
|
+
const metadata = mergeMetadata(existing.metadata, chunk.metadata);
|
|
3379
|
+
return messages.map((msg, index) => index === existingIndex ? {
|
|
3380
|
+
...msg,
|
|
3381
|
+
parts,
|
|
3382
|
+
...metadata != null ? { metadata } : {}
|
|
3383
|
+
} : msg);
|
|
3384
|
+
} catch (error) {
|
|
3385
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3386
|
+
console.warn(`Failed to apply activity patch for '${messageId}': ${errorMessage}`);
|
|
3387
|
+
return messages;
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
//#endregion
|
|
3391
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/activities/chat/stream/message-updaters.js
|
|
2599
3392
|
/**
|
|
2600
3393
|
* Message Updaters (Internal)
|
|
2601
3394
|
*
|
|
@@ -2880,11 +3673,13 @@ function updateThinkingPart(messages, messageId, stepId, content, signature) {
|
|
|
2880
3673
|
if (candidate?.type === "thinking") adopted = candidate;
|
|
2881
3674
|
}
|
|
2882
3675
|
const nextSignature = signature ?? adopted?.signature;
|
|
3676
|
+
const redacted = isRedactedThinkingId(stepId) || adopted?.redacted === true;
|
|
2883
3677
|
const thinkingPart = {
|
|
2884
3678
|
type: "thinking",
|
|
2885
3679
|
content,
|
|
2886
3680
|
stepId,
|
|
2887
|
-
...nextSignature && { signature: nextSignature }
|
|
3681
|
+
...nextSignature && { signature: nextSignature },
|
|
3682
|
+
...redacted && { redacted: true }
|
|
2888
3683
|
};
|
|
2889
3684
|
if (thinkingPartIndex >= 0) parts[thinkingPartIndex] = thinkingPart;
|
|
2890
3685
|
else parts.push(thinkingPart);
|
|
@@ -2895,7 +3690,7 @@ function updateThinkingPart(messages, messageId, stepId, content, signature) {
|
|
|
2895
3690
|
});
|
|
2896
3691
|
}
|
|
2897
3692
|
//#endregion
|
|
2898
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
3693
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/activities/chat/stream/processor.js
|
|
2899
3694
|
/**
|
|
2900
3695
|
* Unified Stream Processor
|
|
2901
3696
|
*
|
|
@@ -2916,6 +3711,28 @@ function updateThinkingPart(messages, messageId, stepId, content, signature) {
|
|
|
2916
3711
|
* adapter contract, single-shot flows, and expected UIMessage output.
|
|
2917
3712
|
*/
|
|
2918
3713
|
var STRUCTURED_OUTPUT_UPDATE_BATCH_SIZE = 12;
|
|
3714
|
+
/**
|
|
3715
|
+
* Events that leave this processor's open *_CHUNK stream open.
|
|
3716
|
+
* RAW, activity events, and REASONING_ENCRYPTED_VALUE match the AG-UI client.
|
|
3717
|
+
* Subagent lifecycle events stay here too: the child processor owns that
|
|
3718
|
+
* lane, and SUBAGENT_FINISHED or SUBAGENT_ERROR finalizes the child.
|
|
3719
|
+
*/
|
|
3720
|
+
var CHUNK_PASS_THROUGH = /* @__PURE__ */ new Set([
|
|
3721
|
+
"RAW",
|
|
3722
|
+
"ACTIVITY_SNAPSHOT",
|
|
3723
|
+
"ACTIVITY_DELTA",
|
|
3724
|
+
"REASONING_ENCRYPTED_VALUE",
|
|
3725
|
+
"SUBAGENT_STARTED",
|
|
3726
|
+
"SUBAGENT_FINISHED",
|
|
3727
|
+
"SUBAGENT_ERROR"
|
|
3728
|
+
]);
|
|
3729
|
+
/** A run-level event closes every open shorthand lane, including children. */
|
|
3730
|
+
var RUN_LEVEL_CLOSES_LANES = /* @__PURE__ */ new Set([
|
|
3731
|
+
"RUN_STARTED",
|
|
3732
|
+
"RUN_FINISHED",
|
|
3733
|
+
"RUN_ERROR",
|
|
3734
|
+
"MESSAGES_SNAPSHOT"
|
|
3735
|
+
]);
|
|
2919
3736
|
function interruptBatchHasGeneric(interrupts) {
|
|
2920
3737
|
return interrupts.some((interrupt) => {
|
|
2921
3738
|
const metadata = interrupt.metadata;
|
|
@@ -2941,6 +3758,19 @@ function serializeToolInput(input) {
|
|
|
2941
3758
|
}
|
|
2942
3759
|
}
|
|
2943
3760
|
/**
|
|
3761
|
+
* The input of a tool call from its raw arguments: `{}` for an empty string,
|
|
3762
|
+
* `undefined` when the arguments are not complete JSON (for example cut off)
|
|
3763
|
+
* or are `null`.
|
|
3764
|
+
*/
|
|
3765
|
+
function parseToolArguments(args) {
|
|
3766
|
+
if (args.trim() === "") return {};
|
|
3767
|
+
try {
|
|
3768
|
+
return JSON.parse(args) ?? void 0;
|
|
3769
|
+
} catch {
|
|
3770
|
+
return;
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
3773
|
+
/**
|
|
2944
3774
|
* StreamProcessor - State machine for processing AI response streams
|
|
2945
3775
|
*
|
|
2946
3776
|
* Manages the full UIMessage[] conversation and emits events on changes.
|
|
@@ -2967,9 +3797,12 @@ var StreamProcessor = class StreamProcessor {
|
|
|
2967
3797
|
toolCallToMessage = /* @__PURE__ */ new Map();
|
|
2968
3798
|
pendingManualMessageId = null;
|
|
2969
3799
|
pendingThinkingStepId = null;
|
|
3800
|
+
openChunk = null;
|
|
2970
3801
|
structuredMessageIds = /* @__PURE__ */ new Set();
|
|
2971
3802
|
structuredOutputUpdateBatches = /* @__PURE__ */ new Map();
|
|
2972
3803
|
activeRuns = /* @__PURE__ */ new Set();
|
|
3804
|
+
runToolCallIds = [];
|
|
3805
|
+
toolCallsSentToClient = /* @__PURE__ */ new Set();
|
|
2973
3806
|
childProcessors = /* @__PURE__ */ new Map();
|
|
2974
3807
|
childToolCalls = /* @__PURE__ */ new Map();
|
|
2975
3808
|
finishReason = null;
|
|
@@ -3176,6 +4009,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3176
4009
|
this.structuredMessageIds.clear();
|
|
3177
4010
|
this.structuredOutputUpdateBatches.clear();
|
|
3178
4011
|
this.pendingManualMessageId = null;
|
|
4012
|
+
this.openChunk = null;
|
|
3179
4013
|
this.childProcessors.clear();
|
|
3180
4014
|
this.childToolCalls.clear();
|
|
3181
4015
|
this.emitMessagesChange();
|
|
@@ -3196,7 +4030,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3196
4030
|
*
|
|
3197
4031
|
* Central dispatch for all AG-UI events. Each event type maps to a specific
|
|
3198
4032
|
* handler. Events not listed in the switch are intentionally ignored
|
|
3199
|
-
* (
|
|
4033
|
+
* (STATE_SNAPSHOT, STATE_DELTA).
|
|
3200
4034
|
*
|
|
3201
4035
|
* @see docs/chat-architecture.md#adapter-contract — Expected event types and ordering
|
|
3202
4036
|
*/
|
|
@@ -3207,6 +4041,10 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3207
4041
|
index: this.recording.chunks.length
|
|
3208
4042
|
});
|
|
3209
4043
|
if (this.routeToChild(chunk)) return;
|
|
4044
|
+
for (const event of this.expandChunk(chunk)) this.dispatchChunk(event);
|
|
4045
|
+
}
|
|
4046
|
+
/** Send one event, after expandChunk(), to its handler. */
|
|
4047
|
+
dispatchChunk(chunk) {
|
|
3210
4048
|
switch (chunk.type) {
|
|
3211
4049
|
case "SUBAGENT_STARTED":
|
|
3212
4050
|
this.handleSubagentStartedEvent(chunk);
|
|
@@ -3266,7 +4104,178 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3266
4104
|
case "TOOL_CALL_RESULT":
|
|
3267
4105
|
this.handleToolCallResultEvent(chunk);
|
|
3268
4106
|
break;
|
|
3269
|
-
case "STEP_STARTED":
|
|
4107
|
+
case "STEP_STARTED":
|
|
4108
|
+
this.handleStepStartedEvent(chunk);
|
|
4109
|
+
break;
|
|
4110
|
+
case "ACTIVITY_SNAPSHOT":
|
|
4111
|
+
this.handleActivitySnapshotEvent(chunk);
|
|
4112
|
+
break;
|
|
4113
|
+
case "ACTIVITY_DELTA": this.handleActivityDeltaEvent(chunk);
|
|
4114
|
+
}
|
|
4115
|
+
}
|
|
4116
|
+
/**
|
|
4117
|
+
* AG-UI lets a producer send one TEXT_MESSAGE_CHUNK, TOOL_CALL_CHUNK or
|
|
4118
|
+
* REASONING_MESSAGE_CHUNK in place of the START / CONTENT (ARGS) / END
|
|
4119
|
+
* events. A chunk with a new id opens a stream. A chunk with the same id or
|
|
4120
|
+
* no id continues it. Any other event closes it, except the ones in
|
|
4121
|
+
* CHUNK_PASS_THROUGH. Expand the shorthand into the START / CONTENT (ARGS)
|
|
4122
|
+
* / END events, so both forms build the same message.
|
|
4123
|
+
*/
|
|
4124
|
+
expandChunk(chunk) {
|
|
4125
|
+
const open = this.openChunk;
|
|
4126
|
+
const timestamp = chunk.timestamp;
|
|
4127
|
+
switch (chunk.type) {
|
|
4128
|
+
case "TEXT_MESSAGE_CHUNK": {
|
|
4129
|
+
const id = this.chunkStreamId("TEXT_MESSAGE", chunk.messageId, chunk.type);
|
|
4130
|
+
if (id === void 0) return this.closeChunk();
|
|
4131
|
+
const events = [];
|
|
4132
|
+
if (open?.family !== "TEXT_MESSAGE" || open.id !== id) {
|
|
4133
|
+
events.push(...this.closeChunk(), {
|
|
4134
|
+
type: EventType.TEXT_MESSAGE_START,
|
|
4135
|
+
messageId: id,
|
|
4136
|
+
role: chunk.role ?? "assistant",
|
|
4137
|
+
...chunk.name !== void 0 ? { name: chunk.name } : {},
|
|
4138
|
+
timestamp
|
|
4139
|
+
});
|
|
4140
|
+
this.openChunk = {
|
|
4141
|
+
family: "TEXT_MESSAGE",
|
|
4142
|
+
id
|
|
4143
|
+
};
|
|
4144
|
+
}
|
|
4145
|
+
if (chunk.delta !== void 0 || chunk.metadata !== void 0) events.push({
|
|
4146
|
+
type: EventType.TEXT_MESSAGE_CONTENT,
|
|
4147
|
+
messageId: id,
|
|
4148
|
+
delta: chunk.delta ?? "",
|
|
4149
|
+
metadata: chunk.metadata,
|
|
4150
|
+
timestamp
|
|
4151
|
+
});
|
|
4152
|
+
return events;
|
|
4153
|
+
}
|
|
4154
|
+
case "TOOL_CALL_CHUNK": {
|
|
4155
|
+
const id = this.chunkStreamId("TOOL_CALL", chunk.toolCallId, chunk.type);
|
|
4156
|
+
if (id === void 0) return this.closeChunk();
|
|
4157
|
+
const events = [];
|
|
4158
|
+
if (open?.family !== "TOOL_CALL" || open.id !== id) {
|
|
4159
|
+
if (chunk.toolCallName === void 0) {
|
|
4160
|
+
console.warn(`[StreamProcessor] Dropped TOOL_CALL_CHUNK ${id}: the first chunk of a tool call needs a toolCallName`);
|
|
4161
|
+
return this.closeChunk();
|
|
4162
|
+
}
|
|
4163
|
+
events.push(...this.closeChunk(), {
|
|
4164
|
+
type: EventType.TOOL_CALL_START,
|
|
4165
|
+
toolCallId: id,
|
|
4166
|
+
toolCallName: chunk.toolCallName,
|
|
4167
|
+
parentMessageId: chunk.parentMessageId,
|
|
4168
|
+
metadata: chunk.metadata,
|
|
4169
|
+
timestamp
|
|
4170
|
+
});
|
|
4171
|
+
this.openChunk = {
|
|
4172
|
+
family: "TOOL_CALL",
|
|
4173
|
+
id
|
|
4174
|
+
};
|
|
4175
|
+
}
|
|
4176
|
+
if (chunk.delta !== void 0 || chunk.metadata !== void 0) events.push({
|
|
4177
|
+
type: EventType.TOOL_CALL_ARGS,
|
|
4178
|
+
toolCallId: id,
|
|
4179
|
+
delta: chunk.delta ?? "",
|
|
4180
|
+
...chunk.metadata !== void 0 ? { metadata: chunk.metadata } : {},
|
|
4181
|
+
timestamp
|
|
4182
|
+
});
|
|
4183
|
+
return events;
|
|
4184
|
+
}
|
|
4185
|
+
case "REASONING_MESSAGE_CHUNK": {
|
|
4186
|
+
const id = this.chunkStreamId("REASONING_MESSAGE", chunk.messageId, chunk.type);
|
|
4187
|
+
if (id === void 0) return this.closeChunk();
|
|
4188
|
+
const events = [];
|
|
4189
|
+
if (open?.family !== "REASONING_MESSAGE" || open.id !== id) {
|
|
4190
|
+
events.push(...this.closeChunk(), {
|
|
4191
|
+
type: EventType.REASONING_MESSAGE_START,
|
|
4192
|
+
messageId: id,
|
|
4193
|
+
role: "reasoning",
|
|
4194
|
+
timestamp
|
|
4195
|
+
});
|
|
4196
|
+
this.openChunk = {
|
|
4197
|
+
family: "REASONING_MESSAGE",
|
|
4198
|
+
id
|
|
4199
|
+
};
|
|
4200
|
+
}
|
|
4201
|
+
if (chunk.delta !== void 0 || chunk.metadata !== void 0) events.push({
|
|
4202
|
+
type: EventType.REASONING_MESSAGE_CONTENT,
|
|
4203
|
+
messageId: id,
|
|
4204
|
+
delta: chunk.delta ?? "",
|
|
4205
|
+
...chunk.metadata !== void 0 ? { metadata: chunk.metadata } : {},
|
|
4206
|
+
timestamp
|
|
4207
|
+
});
|
|
4208
|
+
return events;
|
|
4209
|
+
}
|
|
4210
|
+
default: {
|
|
4211
|
+
const events = open && !CHUNK_PASS_THROUGH.has(chunk.type) ? this.closeChunk() : [];
|
|
4212
|
+
if (RUN_LEVEL_CLOSES_LANES.has(chunk.type)) this.closeChildChunkLanes();
|
|
4213
|
+
return [...events, chunk];
|
|
4214
|
+
}
|
|
4215
|
+
}
|
|
4216
|
+
}
|
|
4217
|
+
/** Synthesize *_END on every nested shorthand lane and apply those events there. */
|
|
4218
|
+
closeChildChunkLanes() {
|
|
4219
|
+
for (const child of this.childProcessors.values()) {
|
|
4220
|
+
for (const event of child.closeChunk()) child.dispatchChunk(event);
|
|
4221
|
+
child.closeChildChunkLanes();
|
|
4222
|
+
}
|
|
4223
|
+
}
|
|
4224
|
+
/**
|
|
4225
|
+
* The child an untagged chunk with no id continues: the only child whose
|
|
4226
|
+
* subtree has an open chunk stream of its kind, when this processor has
|
|
4227
|
+
* none. The AG-UI client resolves a chunk that tags only its opener the
|
|
4228
|
+
* same way.
|
|
4229
|
+
*/
|
|
4230
|
+
childContinuing(chunk) {
|
|
4231
|
+
let family;
|
|
4232
|
+
if (chunk.type === "TEXT_MESSAGE_CHUNK" && chunk.messageId === void 0) family = "TEXT_MESSAGE";
|
|
4233
|
+
else if (chunk.type === "REASONING_MESSAGE_CHUNK" && chunk.messageId === void 0) family = "REASONING_MESSAGE";
|
|
4234
|
+
else if (chunk.type === "TOOL_CALL_CHUNK" && chunk.toolCallId === void 0) family = "TOOL_CALL";
|
|
4235
|
+
else return;
|
|
4236
|
+
if (this.openChunkCount(family) !== 1) return void 0;
|
|
4237
|
+
for (const [id, child] of this.childProcessors) if (child.openChunkCount(family) === 1) return id;
|
|
4238
|
+
}
|
|
4239
|
+
/**
|
|
4240
|
+
* How many open chunk streams of a kind this processor and all its nested
|
|
4241
|
+
* children hold.
|
|
4242
|
+
*/
|
|
4243
|
+
openChunkCount(family) {
|
|
4244
|
+
let count = this.openChunk?.family === family ? 1 : 0;
|
|
4245
|
+
for (const child of this.childProcessors.values()) count += child.openChunkCount(family);
|
|
4246
|
+
return count;
|
|
4247
|
+
}
|
|
4248
|
+
/**
|
|
4249
|
+
* The id a chunk opens or continues. A chunk with no id continues. If it
|
|
4250
|
+
* continues nothing, the caller drops it and closes the open stream, so a
|
|
4251
|
+
* later chunk with no id cannot continue that stream either.
|
|
4252
|
+
*/
|
|
4253
|
+
chunkStreamId(family, id, type) {
|
|
4254
|
+
if (id !== void 0) return id;
|
|
4255
|
+
if (this.openChunk?.family === family) return this.openChunk.id;
|
|
4256
|
+
console.warn(`[StreamProcessor] Dropped ${type}: it has no id and continues nothing`);
|
|
4257
|
+
}
|
|
4258
|
+
closeChunk() {
|
|
4259
|
+
const open = this.openChunk;
|
|
4260
|
+
if (!open) return [];
|
|
4261
|
+
this.openChunk = null;
|
|
4262
|
+
const timestamp = Date.now();
|
|
4263
|
+
switch (open.family) {
|
|
4264
|
+
case "TEXT_MESSAGE": return [{
|
|
4265
|
+
type: EventType.TEXT_MESSAGE_END,
|
|
4266
|
+
messageId: open.id,
|
|
4267
|
+
timestamp
|
|
4268
|
+
}];
|
|
4269
|
+
case "TOOL_CALL": return [{
|
|
4270
|
+
type: EventType.TOOL_CALL_END,
|
|
4271
|
+
toolCallId: open.id,
|
|
4272
|
+
timestamp
|
|
4273
|
+
}];
|
|
4274
|
+
case "REASONING_MESSAGE": return [{
|
|
4275
|
+
type: EventType.REASONING_MESSAGE_END,
|
|
4276
|
+
messageId: open.id,
|
|
4277
|
+
timestamp
|
|
4278
|
+
}];
|
|
3270
4279
|
}
|
|
3271
4280
|
}
|
|
3272
4281
|
/**
|
|
@@ -3343,7 +4352,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3343
4352
|
* MESSAGES_SNAPSHOT) but whose transient state was cleared. In that case we
|
|
3344
4353
|
* hydrate state from the existing message rather than creating a duplicate.
|
|
3345
4354
|
*/
|
|
3346
|
-
ensureAssistantMessage(preferredId) {
|
|
4355
|
+
ensureAssistantMessage(preferredId, fallbackToActive = true) {
|
|
3347
4356
|
if (preferredId) {
|
|
3348
4357
|
const state = this.getMessageState(preferredId);
|
|
3349
4358
|
if (state) {
|
|
@@ -3354,7 +4363,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3354
4363
|
};
|
|
3355
4364
|
}
|
|
3356
4365
|
}
|
|
3357
|
-
const activeId = this.getActiveAssistantMessageId();
|
|
4366
|
+
const activeId = fallbackToActive ? this.getActiveAssistantMessageId() : null;
|
|
3358
4367
|
if (activeId) {
|
|
3359
4368
|
const state = this.getMessageState(activeId);
|
|
3360
4369
|
if (state) {
|
|
@@ -3367,7 +4376,8 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3367
4376
|
}
|
|
3368
4377
|
if (preferredId) {
|
|
3369
4378
|
const existingMsg = this.messages.find((m) => m.id === preferredId);
|
|
3370
|
-
if (existingMsg)
|
|
4379
|
+
if (existingMsg?.role === "activity") preferredId = void 0;
|
|
4380
|
+
else if (existingMsg) {
|
|
3371
4381
|
const state = this.createMessageState(preferredId, existingMsg.role);
|
|
3372
4382
|
this.activeMessageIds.add(preferredId);
|
|
3373
4383
|
const lastPart = existingMsg.parts.length > 0 ? existingMsg.parts[existingMsg.parts.length - 1] : null;
|
|
@@ -3392,7 +4402,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3392
4402
|
this.messages = [...this.messages, assistantMessage];
|
|
3393
4403
|
const state = this.createMessageState(id, "assistant");
|
|
3394
4404
|
this.activeMessageIds.add(id);
|
|
3395
|
-
this.pendingManualMessageId = id;
|
|
4405
|
+
if (!preferredId) this.pendingManualMessageId = id;
|
|
3396
4406
|
this.events.onStreamStart?.();
|
|
3397
4407
|
this.emitMessagesChange();
|
|
3398
4408
|
return {
|
|
@@ -3562,7 +4572,9 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3562
4572
|
/**
|
|
3563
4573
|
* Send a child's chunk to that child's processor, so the card keeps text,
|
|
3564
4574
|
* reasoning, tool calls, results, and nested children. A tool event without
|
|
3565
|
-
* `subagentRunId` follows its `TOOL_CALL_START`.
|
|
4575
|
+
* `subagentRunId` follows its `TOOL_CALL_START` or `TOOL_CALL_CHUNK`. An
|
|
4576
|
+
* untagged chunk with no id follows a child's open chunk stream (see
|
|
4577
|
+
* childContinuing()).
|
|
3566
4578
|
*/
|
|
3567
4579
|
routeToChild(chunk) {
|
|
3568
4580
|
let id;
|
|
@@ -3572,6 +4584,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3572
4584
|
id = chunk.subagentRunId;
|
|
3573
4585
|
} else if ("subagentRunId" in chunk && chunk.subagentRunId) id = chunk.subagentRunId;
|
|
3574
4586
|
else if ("toolCallId" in chunk && typeof chunk.toolCallId === "string") id = this.childToolCalls.get(chunk.toolCallId);
|
|
4587
|
+
else id = this.childContinuing(chunk);
|
|
3575
4588
|
if (id === void 0) return false;
|
|
3576
4589
|
const owner = this.childOwning(id);
|
|
3577
4590
|
if (owner === void 0) {
|
|
@@ -3580,34 +4593,45 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3580
4593
|
return true;
|
|
3581
4594
|
}
|
|
3582
4595
|
if (this.findSubagentPart(owner)?.part.subagent.status === "error") return true;
|
|
3583
|
-
if (chunk.type === "TOOL_CALL_START") this.childToolCalls.set(chunk.toolCallId, owner);
|
|
4596
|
+
if ((chunk.type === "TOOL_CALL_START" || chunk.type === "TOOL_CALL_CHUNK") && chunk.toolCallId !== void 0) this.childToolCalls.set(chunk.toolCallId, owner);
|
|
3584
4597
|
this.updateChild(owner, (child) => child.processChunk(chunk));
|
|
3585
4598
|
return true;
|
|
3586
4599
|
}
|
|
4600
|
+
renameMessage(fromId, toId) {
|
|
4601
|
+
this.messages = this.messages.map((msg) => msg.id === fromId ? {
|
|
4602
|
+
...msg,
|
|
4603
|
+
id: toId
|
|
4604
|
+
} : msg);
|
|
4605
|
+
const existingState = this.messageStates.get(fromId);
|
|
4606
|
+
if (existingState) {
|
|
4607
|
+
existingState.id = toId;
|
|
4608
|
+
this.messageStates.delete(fromId);
|
|
4609
|
+
this.messageStates.set(toId, existingState);
|
|
4610
|
+
}
|
|
4611
|
+
this.activeMessageIds.delete(fromId);
|
|
4612
|
+
this.activeMessageIds.add(toId);
|
|
4613
|
+
for (const [toolCallId, mappedMessageId] of this.toolCallToMessage) if (mappedMessageId === fromId) this.toolCallToMessage.set(toolCallId, toId);
|
|
4614
|
+
if (this.structuredMessageIds.delete(fromId)) this.structuredMessageIds.add(toId);
|
|
4615
|
+
const batch = this.structuredOutputUpdateBatches.get(fromId);
|
|
4616
|
+
if (batch) {
|
|
4617
|
+
this.structuredOutputUpdateBatches.delete(fromId);
|
|
4618
|
+
this.structuredOutputUpdateBatches.set(toId, batch);
|
|
4619
|
+
}
|
|
4620
|
+
}
|
|
3587
4621
|
/**
|
|
3588
4622
|
* Handle TEXT_MESSAGE_START event
|
|
3589
4623
|
*/
|
|
3590
4624
|
handleTextMessageStartEvent(chunk) {
|
|
3591
4625
|
const { messageId, role } = chunk;
|
|
4626
|
+
if (this.messages.some((m) => m.id === messageId && m.role === "activity")) {
|
|
4627
|
+
console.warn(`TEXT_MESSAGE_START: Dropped text for '${messageId}', the id of an activity message`);
|
|
4628
|
+
return;
|
|
4629
|
+
}
|
|
3592
4630
|
const uiRole = role === "user" || role === "system" ? role : "assistant";
|
|
3593
4631
|
if (this.pendingManualMessageId) {
|
|
3594
4632
|
const pendingId = this.pendingManualMessageId;
|
|
3595
4633
|
this.pendingManualMessageId = null;
|
|
3596
|
-
if (pendingId !== messageId)
|
|
3597
|
-
this.messages = this.messages.map((msg) => msg.id === pendingId ? {
|
|
3598
|
-
...msg,
|
|
3599
|
-
id: messageId
|
|
3600
|
-
} : msg);
|
|
3601
|
-
const existingState = this.messageStates.get(pendingId);
|
|
3602
|
-
if (existingState) {
|
|
3603
|
-
existingState.id = messageId;
|
|
3604
|
-
this.messageStates.delete(pendingId);
|
|
3605
|
-
this.messageStates.set(messageId, existingState);
|
|
3606
|
-
}
|
|
3607
|
-
this.activeMessageIds.delete(pendingId);
|
|
3608
|
-
this.activeMessageIds.add(messageId);
|
|
3609
|
-
for (const [toolCallId, mappedMessageId] of this.toolCallToMessage) if (mappedMessageId === pendingId) this.toolCallToMessage.set(toolCallId, messageId);
|
|
3610
|
-
}
|
|
4634
|
+
if (pendingId !== messageId) this.renameMessage(pendingId, messageId);
|
|
3611
4635
|
let pendingState = this.messageStates.get(messageId);
|
|
3612
4636
|
if (!pendingState) {
|
|
3613
4637
|
pendingState = this.createMessageState(messageId, uiRole);
|
|
@@ -3618,6 +4642,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3618
4642
|
pendingState.lastEmittedText = "";
|
|
3619
4643
|
pendingState.hasToolCallsSinceTextStart = false;
|
|
3620
4644
|
}
|
|
4645
|
+
this.applySenderName(messageId, chunk.name);
|
|
3621
4646
|
this.mergeMessageMetadata(messageId, chunk.metadata);
|
|
3622
4647
|
this.emitMessagesChange();
|
|
3623
4648
|
return;
|
|
@@ -3632,6 +4657,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3632
4657
|
existingState.lastEmittedText = "";
|
|
3633
4658
|
existingState.hasToolCallsSinceTextStart = false;
|
|
3634
4659
|
}
|
|
4660
|
+
this.applySenderName(messageId, chunk.name);
|
|
3635
4661
|
this.mergeMessageMetadata(messageId, chunk.metadata);
|
|
3636
4662
|
return;
|
|
3637
4663
|
}
|
|
@@ -3644,10 +4670,18 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3644
4670
|
this.messages = [...this.messages, newMessage];
|
|
3645
4671
|
this.createMessageState(messageId, uiRole);
|
|
3646
4672
|
this.activeMessageIds.add(messageId);
|
|
4673
|
+
this.applySenderName(messageId, chunk.name);
|
|
3647
4674
|
this.mergeMessageMetadata(messageId, chunk.metadata);
|
|
3648
4675
|
this.events.onStreamStart?.();
|
|
3649
4676
|
this.emitMessagesChange();
|
|
3650
4677
|
}
|
|
4678
|
+
applySenderName(messageId, name) {
|
|
4679
|
+
if (name === void 0) return;
|
|
4680
|
+
this.messages = this.messages.map((msg) => msg.id === messageId ? {
|
|
4681
|
+
...msg,
|
|
4682
|
+
name
|
|
4683
|
+
} : msg);
|
|
4684
|
+
}
|
|
3651
4685
|
/**
|
|
3652
4686
|
* Handle TEXT_MESSAGE_END event
|
|
3653
4687
|
*/
|
|
@@ -3677,10 +4711,31 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3677
4711
|
metadata: prev.metadata
|
|
3678
4712
|
};
|
|
3679
4713
|
});
|
|
3680
|
-
this.messages = this.attachSnapshotSubagents(reconciled, top, groups, prevMessages);
|
|
4714
|
+
this.messages = this.mergeOmittedActivity(prevMessages, this.attachSnapshotSubagents(reconciled, top, groups, prevMessages));
|
|
3681
4715
|
this.emitMessagesChange();
|
|
3682
4716
|
}
|
|
3683
4717
|
/**
|
|
4718
|
+
* Snapshot is authoritative for user/assistant/system. Activity omitted
|
|
4719
|
+
* from the snapshot (TanStack chat() still builds snapshots from
|
|
4720
|
+
* ModelMessage[]) stays in the transcript so persist/reconnect cannot
|
|
4721
|
+
* wipe it. Snapshot activity rows win when the id is present.
|
|
4722
|
+
*
|
|
4723
|
+
* Keep every snapshot row, including two assistants that share an id
|
|
4724
|
+
* (agent-loop retry reuses `currentMessageId`). A Map keyed by id would
|
|
4725
|
+
* drop the earlier error tool-call (#1192).
|
|
4726
|
+
*/
|
|
4727
|
+
mergeOmittedActivity(prevMessages, snapshot) {
|
|
4728
|
+
const snapshotIds = new Set(snapshot.map((msg) => msg.id));
|
|
4729
|
+
const omitted = prevMessages.filter((msg) => msg.role === "activity" && !snapshotIds.has(msg.id));
|
|
4730
|
+
if (omitted.length === 0) return snapshot;
|
|
4731
|
+
const out = [...snapshot];
|
|
4732
|
+
for (const activity of omitted) {
|
|
4733
|
+
const prevIndex = prevMessages.findIndex((msg) => msg.id === activity.id);
|
|
4734
|
+
out.splice(Math.min(Math.max(prevIndex, 0), out.length), 0, activity);
|
|
4735
|
+
}
|
|
4736
|
+
return out;
|
|
4737
|
+
}
|
|
4738
|
+
/**
|
|
3684
4739
|
* Put subagent cards back on a snapshot. Child wire messages (tagged with
|
|
3685
4740
|
* `subagentRunId`) become a card on the nearest assistant message before
|
|
3686
4741
|
* them, or a new assistant message when there is none. A card that the
|
|
@@ -3900,6 +4955,10 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3900
4955
|
* @see docs/chat-architecture.md#uimessage-part-ordering-invariants — Replace vs. push logic
|
|
3901
4956
|
*/
|
|
3902
4957
|
handleTextMessageContentEvent(chunk) {
|
|
4958
|
+
if (this.messages.some((m) => m.id === chunk.messageId && m.role === "activity")) {
|
|
4959
|
+
console.warn(`TEXT_MESSAGE_CONTENT: Dropped text for '${chunk.messageId}', the id of an activity message`);
|
|
4960
|
+
return;
|
|
4961
|
+
}
|
|
3903
4962
|
const { messageId, state } = this.ensureAssistantMessage(chunk.messageId);
|
|
3904
4963
|
this.mergeMessageMetadata(messageId, chunk.metadata);
|
|
3905
4964
|
if (this.structuredMessageIds.has(messageId)) {
|
|
@@ -3943,8 +5002,25 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3943
5002
|
* @see docs/chat-architecture.md#adapter-contract — Ordering requirements
|
|
3944
5003
|
*/
|
|
3945
5004
|
handleToolCallStartEvent(chunk) {
|
|
5005
|
+
const pendingId = this.pendingManualMessageId;
|
|
5006
|
+
const parentId = chunk.parentMessageId;
|
|
5007
|
+
if (pendingId && parentId && parentId !== pendingId) {
|
|
5008
|
+
const parent = this.messages.find((m) => m.id === parentId);
|
|
5009
|
+
const placeholder = this.messages.find((m) => m.id === pendingId);
|
|
5010
|
+
if (!parent) {
|
|
5011
|
+
this.pendingManualMessageId = null;
|
|
5012
|
+
this.renameMessage(pendingId, parentId);
|
|
5013
|
+
} else if (parent.role === "assistant" && placeholder) {
|
|
5014
|
+
this.pendingManualMessageId = null;
|
|
5015
|
+
this.messages = this.messages.filter((m) => m.id !== pendingId).map((m) => m.id === parentId ? {
|
|
5016
|
+
...m,
|
|
5017
|
+
parts: [...m.parts, ...placeholder.parts]
|
|
5018
|
+
} : m);
|
|
5019
|
+
this.renameMessage(pendingId, parentId);
|
|
5020
|
+
}
|
|
5021
|
+
}
|
|
3946
5022
|
const targetMessageId = chunk.parentMessageId ?? this.getActiveAssistantMessageId();
|
|
3947
|
-
const { messageId, state } = this.ensureAssistantMessage(targetMessageId ?? void 0);
|
|
5023
|
+
const { messageId, state } = this.ensureAssistantMessage(targetMessageId ?? void 0, chunk.parentMessageId === void 0);
|
|
3948
5024
|
state.hasToolCallsSinceTextStart = true;
|
|
3949
5025
|
const toolCallId = chunk.toolCallId;
|
|
3950
5026
|
if (!state.toolCalls.get(toolCallId)) {
|
|
@@ -3962,6 +5038,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3962
5038
|
};
|
|
3963
5039
|
state.toolCalls.set(toolCallId, newToolCall);
|
|
3964
5040
|
state.toolCallOrder.push(toolCallId);
|
|
5041
|
+
this.runToolCallIds.push(toolCallId);
|
|
3965
5042
|
this.toolCallToMessage.set(toolCallId, messageId);
|
|
3966
5043
|
this.messages = updateToolCallPart(this.messages, messageId, {
|
|
3967
5044
|
id: chunk.toolCallId,
|
|
@@ -3995,6 +5072,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
3995
5072
|
const existingToolCall = state.toolCalls.get(toolCallId);
|
|
3996
5073
|
if (!existingToolCall) return;
|
|
3997
5074
|
const wasAwaitingInput = existingToolCall.state === "awaiting-input";
|
|
5075
|
+
if (chunk.metadata !== void 0) existingToolCall.metadata = mergeMetadata(existingToolCall.metadata, chunk.metadata);
|
|
3998
5076
|
existingToolCall.arguments += chunk.delta || "";
|
|
3999
5077
|
if (wasAwaitingInput && chunk.delta) existingToolCall.state = "input-streaming";
|
|
4000
5078
|
existingToolCall.parsedArguments = this.jsonParser.parse(existingToolCall.arguments);
|
|
@@ -4002,7 +5080,8 @@ var StreamProcessor = class StreamProcessor {
|
|
|
4002
5080
|
id: existingToolCall.id,
|
|
4003
5081
|
name: existingToolCall.name,
|
|
4004
5082
|
arguments: existingToolCall.arguments,
|
|
4005
|
-
state: existingToolCall.state
|
|
5083
|
+
state: existingToolCall.state,
|
|
5084
|
+
...existingToolCall.metadata !== void 0 && { metadata: existingToolCall.metadata }
|
|
4006
5085
|
});
|
|
4007
5086
|
this.emitMessagesChange();
|
|
4008
5087
|
this.events.onToolCallStateChange?.(messageId, existingToolCall.id, existingToolCall.state, existingToolCall.arguments);
|
|
@@ -4079,6 +5158,10 @@ var StreamProcessor = class StreamProcessor {
|
|
|
4079
5158
|
* runs are still active before finalizing.
|
|
4080
5159
|
*/
|
|
4081
5160
|
handleRunStartedEvent(chunk) {
|
|
5161
|
+
if (this.activeRuns.size === 0) {
|
|
5162
|
+
this.runToolCallIds = [];
|
|
5163
|
+
this.toolCallsSentToClient.clear();
|
|
5164
|
+
}
|
|
4082
5165
|
this.activeRuns.add(chunk.runId);
|
|
4083
5166
|
}
|
|
4084
5167
|
/**
|
|
@@ -4099,11 +5182,39 @@ var StreamProcessor = class StreamProcessor {
|
|
|
4099
5182
|
if (this.activeRuns.size === 0) {
|
|
4100
5183
|
this.completeAllToolCalls();
|
|
4101
5184
|
if (this.finishReason === "tool_calls" && chunk.outcome?.type !== "interrupt") return;
|
|
5185
|
+
if (!chunk.outcome || chunk.outcome.type === "success") this.handlePendingToolCalls(chunk.outcome?.pendingToolCallIds);
|
|
4102
5186
|
this.isDone = true;
|
|
4103
5187
|
this.finalizeStream();
|
|
4104
5188
|
}
|
|
4105
5189
|
}
|
|
4106
5190
|
/**
|
|
5191
|
+
* AG-UI ends a run that calls a frontend tool with a success outcome and
|
|
5192
|
+
* leaves the call unanswered. The pending calls are the ones named in
|
|
5193
|
+
* `pendingToolCallIds` that this run started, or else every call this run
|
|
5194
|
+
* started that has no result. Fire onToolCall once for each, so the client
|
|
5195
|
+
* runs it and continues.
|
|
5196
|
+
*/
|
|
5197
|
+
handlePendingToolCalls(pendingToolCallIds) {
|
|
5198
|
+
const ids = pendingToolCallIds?.length ? pendingToolCallIds.filter((id) => this.runToolCallIds.includes(id)) : this.runToolCallIds;
|
|
5199
|
+
const parts = this.messages.flatMap((msg) => msg.parts ?? []);
|
|
5200
|
+
for (const toolCallId of ids) {
|
|
5201
|
+
if (this.toolCallsSentToClient.has(toolCallId)) continue;
|
|
5202
|
+
const part = parts.find((p) => p.type === "tool-call" && p.id === toolCallId);
|
|
5203
|
+
if (!part || isProviderExecutedToolCall(part) || part.output !== void 0 || parts.some((p) => p.type === "tool-result" && p.toolCallId === toolCallId) || this.isToolCallPartTerminal(toolCallId) || this.isToolCallPartAwaitingUserAction(toolCallId)) continue;
|
|
5204
|
+
const input = part.input ?? parseToolArguments(part.arguments);
|
|
5205
|
+
if (input === void 0) {
|
|
5206
|
+
console.warn(`[StreamProcessor] Did not run tool call ${toolCallId}: the arguments of ${part.name} are not complete JSON`);
|
|
5207
|
+
continue;
|
|
5208
|
+
}
|
|
5209
|
+
this.toolCallsSentToClient.add(toolCallId);
|
|
5210
|
+
this.events.onToolCall?.({
|
|
5211
|
+
toolCallId,
|
|
5212
|
+
toolName: part.name,
|
|
5213
|
+
input
|
|
5214
|
+
});
|
|
5215
|
+
}
|
|
5216
|
+
}
|
|
5217
|
+
/**
|
|
4107
5218
|
* Apply interrupt state to tool-call parts, then fire the client events.
|
|
4108
5219
|
* A child's interrupt updates the child's card. `emit` is false there, so
|
|
4109
5220
|
* the events fire once, from the top processor.
|
|
@@ -4145,6 +5256,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
4145
5256
|
}
|
|
4146
5257
|
if (kind === "client_tool" || interrupt.reason === "client_tool_input") {
|
|
4147
5258
|
if (hasGeneric || !emit) continue;
|
|
5259
|
+
this.toolCallsSentToClient.add(toolCallId);
|
|
4148
5260
|
this.events.onToolCall?.({
|
|
4149
5261
|
toolCallId,
|
|
4150
5262
|
toolName,
|
|
@@ -4205,10 +5317,28 @@ var StreamProcessor = class StreamProcessor {
|
|
|
4205
5317
|
this.pendingThinkingStepId = stepId;
|
|
4206
5318
|
}
|
|
4207
5319
|
/**
|
|
4208
|
-
* Handle
|
|
4209
|
-
*
|
|
4210
|
-
*
|
|
4211
|
-
|
|
5320
|
+
* Handle ACTIVITY_SNAPSHOT. Creates or replaces a frontend-only activity
|
|
5321
|
+
* message. Does not create MessageStreamState (that path feeds
|
|
5322
|
+
* ProcessorResult.content).
|
|
5323
|
+
*/
|
|
5324
|
+
handleActivitySnapshotEvent(chunk) {
|
|
5325
|
+
this.messages = applyActivitySnapshotToUIMessages(this.messages, chunk);
|
|
5326
|
+
this.emitMessagesChange();
|
|
5327
|
+
}
|
|
5328
|
+
/**
|
|
5329
|
+
* Handle ACTIVITY_DELTA. Applies RFC 6902 patches to an existing activity
|
|
5330
|
+
* `content`. Missing or non-activity ids are no-ops. Patch failure leaves
|
|
5331
|
+
* the previous content in place.
|
|
5332
|
+
*/
|
|
5333
|
+
handleActivityDeltaEvent(chunk) {
|
|
5334
|
+
this.messages = applyActivityDeltaToUIMessages(this.messages, chunk);
|
|
5335
|
+
this.emitMessagesChange();
|
|
5336
|
+
}
|
|
5337
|
+
/**
|
|
5338
|
+
* Handle STEP_FINISHED event.
|
|
5339
|
+
*
|
|
5340
|
+
* Thinking *content* comes from REASONING_MESSAGE_CONTENT, not STEP_FINISHED.
|
|
5341
|
+
* But some adapters (e.g. BytePlus thinking-summary) carry the provider
|
|
4212
5342
|
* signature blob ONLY on the STEP_FINISHED event, so still extract that here
|
|
4213
5343
|
* and attach it to the thinking step the reasoning events already built.
|
|
4214
5344
|
*/
|
|
@@ -4233,6 +5363,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
4233
5363
|
*/
|
|
4234
5364
|
handleReasoningMessageContentEvent(chunk) {
|
|
4235
5365
|
const { messageId, state } = this.ensureAssistantMessage(this.getActiveAssistantMessageId() ?? void 0);
|
|
5366
|
+
this.mergeMessageMetadata(messageId, chunk.metadata);
|
|
4236
5367
|
state.hasSeenReasoningEvents = true;
|
|
4237
5368
|
const delta = chunk.delta || "";
|
|
4238
5369
|
this.consumePendingThinkingStep(state);
|
|
@@ -4345,6 +5476,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
4345
5476
|
}
|
|
4346
5477
|
if (chunk.name === "tool-input-available" && chunk.value) {
|
|
4347
5478
|
const { toolCallId, toolName, input } = chunk.value;
|
|
5479
|
+
this.toolCallsSentToClient.add(toolCallId);
|
|
4348
5480
|
this.events.onToolCall?.({
|
|
4349
5481
|
toolCallId,
|
|
4350
5482
|
toolName,
|
|
@@ -4523,6 +5655,8 @@ var StreamProcessor = class StreamProcessor {
|
|
|
4523
5655
|
*/
|
|
4524
5656
|
finalizeStream() {
|
|
4525
5657
|
this.isDone = true;
|
|
5658
|
+
for (const event of this.closeChunk()) this.dispatchChunk(event);
|
|
5659
|
+
this.closeChildChunkLanes();
|
|
4526
5660
|
let lastAssistantMessage;
|
|
4527
5661
|
for (const messageId of this.activeMessageIds) {
|
|
4528
5662
|
const state = this.getMessageState(messageId);
|
|
@@ -4640,6 +5774,7 @@ var StreamProcessor = class StreamProcessor {
|
|
|
4640
5774
|
this.structuredOutputUpdateBatches.clear();
|
|
4641
5775
|
this.pendingManualMessageId = null;
|
|
4642
5776
|
this.pendingThinkingStepId = null;
|
|
5777
|
+
this.openChunk = null;
|
|
4643
5778
|
this.finishReason = null;
|
|
4644
5779
|
this.hasError = false;
|
|
4645
5780
|
this.isDone = false;
|
|
@@ -4679,14 +5814,14 @@ function createReplayStream(recording) {
|
|
|
4679
5814
|
} };
|
|
4680
5815
|
}
|
|
4681
5816
|
//#endregion
|
|
4682
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
5817
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/byok/providers.js
|
|
4683
5818
|
/** `[a-z][a-z0-9-]{0,63}` — lowercase, no underscores, max 64 chars. */
|
|
4684
5819
|
var BYOK_PROVIDER_ID_PATTERN = /^[a-z][a-z0-9-]{0,63}$/;
|
|
4685
5820
|
function isProviderId(value) {
|
|
4686
5821
|
return typeof value === "string" && BYOK_PROVIDER_ID_PATTERN.test(value);
|
|
4687
5822
|
}
|
|
4688
5823
|
//#endregion
|
|
4689
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
5824
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/byok/missing.js
|
|
4690
5825
|
function isByokMissingBody(value) {
|
|
4691
5826
|
if (typeof value !== "object" || value === null) return false;
|
|
4692
5827
|
if (!("error" in value)) return false;
|
|
@@ -4699,7 +5834,7 @@ function isByokMissingBody(value) {
|
|
|
4699
5834
|
return true;
|
|
4700
5835
|
}
|
|
4701
5836
|
//#endregion
|
|
4702
|
-
//#region node_modules/.deno/@tanstack+ai@0.
|
|
5837
|
+
//#region node_modules/.deno/@tanstack+ai@0.68.0/node_modules/@tanstack/ai/dist/esm/byok/errors.js
|
|
4703
5838
|
var ByokMissingError = class extends Error {
|
|
4704
5839
|
provider;
|
|
4705
5840
|
constructor(provider) {
|
|
@@ -4725,7 +5860,7 @@ var ByokUnresolvedProviderError = class extends Error {
|
|
|
4725
5860
|
}
|
|
4726
5861
|
};
|
|
4727
5862
|
//#endregion
|
|
4728
|
-
//#region node_modules/.deno/@tanstack+ai-client@0.
|
|
5863
|
+
//#region node_modules/.deno/@tanstack+ai-client@0.39.2/node_modules/@tanstack/ai-client/dist/esm/connection-adapters.js
|
|
4729
5864
|
/**
|
|
4730
5865
|
* Associates connect-wrapped chunks with the run they were produced under.
|
|
4731
5866
|
* Content events (TEXT_MESSAGE_CONTENT, TOOL_CALL_*, …) carry no `runId` of
|
|
@@ -4918,6 +6053,9 @@ async function* readStreamLines(reader, abortSignal) {
|
|
|
4918
6053
|
buffer += decoder.decode();
|
|
4919
6054
|
if (buffer.trim() && !abortSignal?.aborted) throw new StreamTruncatedError();
|
|
4920
6055
|
} finally {
|
|
6056
|
+
try {
|
|
6057
|
+
reader.cancel().catch(() => {});
|
|
6058
|
+
} catch {}
|
|
4921
6059
|
reader.releaseLock();
|
|
4922
6060
|
}
|
|
4923
6061
|
}
|
|
@@ -5420,7 +6558,7 @@ async function* abortableIterable(iterable, signal) {
|
|
|
5420
6558
|
}
|
|
5421
6559
|
}
|
|
5422
6560
|
//#endregion
|
|
5423
|
-
//#region node_modules/.deno/@tanstack+ai-client@0.
|
|
6561
|
+
//#region node_modules/.deno/@tanstack+ai-client@0.39.2/node_modules/@tanstack/ai-client/dist/esm/interrupt-manager.js
|
|
5424
6562
|
function isClientOwnedInterrupt(item) {
|
|
5425
6563
|
return item.resumable;
|
|
5426
6564
|
}
|
|
@@ -6362,7 +7500,7 @@ var InterruptManager = class {
|
|
|
6362
7500
|
}
|
|
6363
7501
|
};
|
|
6364
7502
|
//#endregion
|
|
6365
|
-
//#region node_modules/.deno/@tanstack+ai-client@0.
|
|
7503
|
+
//#region node_modules/.deno/@tanstack+ai-client@0.39.2/node_modules/@tanstack/ai-client/dist/esm/byok/client.js
|
|
6366
7504
|
var registeredProviderIds = /* @__PURE__ */ new WeakMap();
|
|
6367
7505
|
/**
|
|
6368
7506
|
* Provider to stamp when the caller did not pass a slug.
|
|
@@ -6375,7 +7513,7 @@ function byokFallbackProviderId(byok) {
|
|
|
6375
7513
|
if (registered.length === 1) return registered[0];
|
|
6376
7514
|
}
|
|
6377
7515
|
//#endregion
|
|
6378
|
-
//#region node_modules/.deno/@tanstack+ai-client@0.
|
|
7516
|
+
//#region node_modules/.deno/@tanstack+ai-client@0.39.2/node_modules/@tanstack/ai-client/dist/esm/byok/resolve.js
|
|
6379
7517
|
function resolveByokProviderId(byokProvider, ...candidates) {
|
|
6380
7518
|
const fromFn = byokProvider?.();
|
|
6381
7519
|
if (isProviderId(fromFn)) return fromFn;
|
|
@@ -6391,7 +7529,7 @@ async function prepareResolvedByokHeaders(byok, provider) {
|
|
|
6391
7529
|
return byok.headers(provider);
|
|
6392
7530
|
}
|
|
6393
7531
|
//#endregion
|
|
6394
|
-
//#region node_modules/.deno/@tanstack+ai-client@0.
|
|
7532
|
+
//#region node_modules/.deno/@tanstack+ai-client@0.39.2/node_modules/@tanstack/ai-client/dist/esm/events.js
|
|
6395
7533
|
/**
|
|
6396
7534
|
* Abstract base class for ChatClient event emission
|
|
6397
7535
|
*/
|
|
@@ -6565,7 +7703,7 @@ var ChatClientEventEmitter = class {
|
|
|
6565
7703
|
}
|
|
6566
7704
|
};
|
|
6567
7705
|
//#endregion
|
|
6568
|
-
//#region node_modules/.deno/@tanstack+ai-client@0.
|
|
7706
|
+
//#region node_modules/.deno/@tanstack+ai-client@0.39.2/node_modules/@tanstack/ai-client/dist/esm/devtools-noop.js
|
|
6569
7707
|
var NoOpChatClientEventEmitter = class extends ChatClientEventEmitter {
|
|
6570
7708
|
emitEvent() {}
|
|
6571
7709
|
};
|
|
@@ -6610,7 +7748,7 @@ var NoOpChatDevtoolsBridge = class {
|
|
|
6610
7748
|
};
|
|
6611
7749
|
var createNoOpChatDevtoolsBridge = (options) => new NoOpChatDevtoolsBridge(options);
|
|
6612
7750
|
//#endregion
|
|
6613
|
-
//#region node_modules/.deno/@tanstack+ai-client@0.
|
|
7751
|
+
//#region node_modules/.deno/@tanstack+ai-client@0.39.2/node_modules/@tanstack/ai-client/dist/esm/client-persistor.js
|
|
6614
7752
|
/** Normalize a raw `getItem` result (legacy bare array or combined record). */
|
|
6615
7753
|
function normalizePersistedState(raw) {
|
|
6616
7754
|
if (Array.isArray(raw)) return { messages: raw };
|
|
@@ -6709,12 +7847,13 @@ var ChatPersistor = class {
|
|
|
6709
7847
|
}
|
|
6710
7848
|
/**
|
|
6711
7849
|
* Apply state from an async `getItem` once it resolves, unless the message
|
|
6712
|
-
* list has already changed since hydration began.
|
|
7850
|
+
* list has already changed since hydration began. Returns a promise that
|
|
7851
|
+
* settles (never rejects) when it is done, or `undefined` for sync state.
|
|
6713
7852
|
*/
|
|
6714
7853
|
hydrateAsync(persistedState) {
|
|
6715
7854
|
if (!(persistedState instanceof Promise)) return;
|
|
6716
7855
|
const hydrationGeneration = this.messagesGeneration;
|
|
6717
|
-
persistedState.then((state) => {
|
|
7856
|
+
return persistedState.then((state) => {
|
|
6718
7857
|
if (!state || this.messagesGeneration !== hydrationGeneration) return;
|
|
6719
7858
|
this.lastResume = state.resume ?? null;
|
|
6720
7859
|
this.lastMessages = state.messages;
|
|
@@ -6870,11 +8009,11 @@ var ChatPersistor = class {
|
|
|
6870
8009
|
isRunlessChunkFromIgnoredRun(chunk) {
|
|
6871
8010
|
if (getChunkRunId$1(chunk) || !this.currentRunlessRunId) return false;
|
|
6872
8011
|
if (!this.ignoredActiveRunIds.has(this.currentRunlessRunId) && !this.clearedRunIds.has(this.currentRunlessRunId)) return false;
|
|
6873
|
-
return chunk.type === "TEXT_MESSAGE_START" || chunk.type === "TEXT_MESSAGE_CONTENT" || chunk.type === "TOOL_CALL_START" || chunk.type === "TOOL_CALL_ARGS" || chunk.type === "TOOL_CALL_END" || chunk.type === "TOOL_CALL_RESULT" || chunk.type === "MESSAGES_SNAPSHOT" || chunk.type === "RUN_ERROR";
|
|
8012
|
+
return chunk.type === "TEXT_MESSAGE_START" || chunk.type === "TEXT_MESSAGE_CONTENT" || chunk.type === "TEXT_MESSAGE_CHUNK" || chunk.type === "TOOL_CALL_START" || chunk.type === "TOOL_CALL_ARGS" || chunk.type === "TOOL_CALL_END" || chunk.type === "TOOL_CALL_RESULT" || chunk.type === "TOOL_CALL_CHUNK" || chunk.type === "MESSAGES_SNAPSHOT" || chunk.type === "RUN_ERROR";
|
|
6874
8013
|
}
|
|
6875
8014
|
};
|
|
6876
8015
|
//#endregion
|
|
6877
|
-
//#region node_modules/.deno/@tanstack+ai-client@0.
|
|
8016
|
+
//#region node_modules/.deno/@tanstack+ai-client@0.39.2/node_modules/@tanstack/ai-client/dist/esm/cleared-stream-tracker.js
|
|
6878
8017
|
function getChunkToolCallId(chunk) {
|
|
6879
8018
|
return "toolCallId" in chunk && typeof chunk.toolCallId === "string" ? chunk.toolCallId : void 0;
|
|
6880
8019
|
}
|
|
@@ -6963,11 +8102,11 @@ var ClearedStreamTracker = class {
|
|
|
6963
8102
|
isRunlessChunkFromIgnoredRun(chunk) {
|
|
6964
8103
|
if (getChunkRunId$1(chunk) || !this.currentRunlessRunId) return false;
|
|
6965
8104
|
if (!this.ignoredActiveRunIds.has(this.currentRunlessRunId) && !this.clearedRunIds.has(this.currentRunlessRunId)) return false;
|
|
6966
|
-
return chunk.type === "TEXT_MESSAGE_START" || chunk.type === "TEXT_MESSAGE_CONTENT" || chunk.type === "TOOL_CALL_START" || chunk.type === "TOOL_CALL_ARGS" || chunk.type === "TOOL_CALL_END" || chunk.type === "TOOL_CALL_RESULT" || chunk.type === "MESSAGES_SNAPSHOT" || chunk.type === "RUN_ERROR";
|
|
8105
|
+
return chunk.type === "TEXT_MESSAGE_START" || chunk.type === "TEXT_MESSAGE_CONTENT" || chunk.type === "TEXT_MESSAGE_CHUNK" || chunk.type === "TOOL_CALL_START" || chunk.type === "TOOL_CALL_ARGS" || chunk.type === "TOOL_CALL_END" || chunk.type === "TOOL_CALL_RESULT" || chunk.type === "TOOL_CALL_CHUNK" || chunk.type === "MESSAGES_SNAPSHOT" || chunk.type === "RUN_ERROR";
|
|
6967
8106
|
}
|
|
6968
8107
|
};
|
|
6969
8108
|
//#endregion
|
|
6970
|
-
//#region node_modules/.deno/@tanstack+ai-client@0.
|
|
8109
|
+
//#region node_modules/.deno/@tanstack+ai-client@0.39.2/node_modules/@tanstack/ai-client/dist/esm/chat-client.js
|
|
6971
8110
|
var STREAM_PROCESSING_BUDGET_MS = 8;
|
|
6972
8111
|
function yieldToHost() {
|
|
6973
8112
|
const { scheduler } = globalThis;
|
|
@@ -7103,8 +8242,11 @@ var REJOIN_CONNECT_DEADLINE_MS = 2e3;
|
|
|
7103
8242
|
var REJOIN_REBUILD_TRIGGERS = /* @__PURE__ */ new Set([
|
|
7104
8243
|
"TEXT_MESSAGE_START",
|
|
7105
8244
|
"TEXT_MESSAGE_CONTENT",
|
|
8245
|
+
"TEXT_MESSAGE_CHUNK",
|
|
7106
8246
|
"REASONING_MESSAGE_CONTENT",
|
|
8247
|
+
"REASONING_MESSAGE_CHUNK",
|
|
7107
8248
|
"TOOL_CALL_START",
|
|
8249
|
+
"TOOL_CALL_CHUNK",
|
|
7108
8250
|
"MESSAGES_SNAPSHOT",
|
|
7109
8251
|
"SUBAGENT_STARTED"
|
|
7110
8252
|
]);
|
|
@@ -7208,6 +8350,7 @@ var ChatClient = class {
|
|
|
7208
8350
|
currentMessageId = null;
|
|
7209
8351
|
postStreamActions = [];
|
|
7210
8352
|
pendingToolExecutions = /* @__PURE__ */ new Map();
|
|
8353
|
+
handingOverPendingToolCalls = false;
|
|
7211
8354
|
activeClientTools = null;
|
|
7212
8355
|
activeContext = void 0;
|
|
7213
8356
|
continuationPending = false;
|
|
@@ -7233,6 +8376,12 @@ var ChatClient = class {
|
|
|
7233
8376
|
hydrationError;
|
|
7234
8377
|
/** Whether a view is currently watching. See `attach` / `detach`. */
|
|
7235
8378
|
tailing = false;
|
|
8379
|
+
/** `historyGeneration` of the mount hydration GET still in flight, if any. */
|
|
8380
|
+
hydrationInFlight;
|
|
8381
|
+
/** An async storage adapter is still reading the persisted transcript. */
|
|
8382
|
+
storeHydrating = false;
|
|
8383
|
+
/** See {@link getIsHydrating}. */
|
|
8384
|
+
isHydrating = false;
|
|
7236
8385
|
/** Constructor inputs `attach()` needs on every re-attach, not just the first. */
|
|
7237
8386
|
rejoinRunId;
|
|
7238
8387
|
cachesMessages;
|
|
@@ -7287,6 +8436,7 @@ var ChatClient = class {
|
|
|
7287
8436
|
onSubscriptionChange: options.onSubscriptionChange || (() => {}),
|
|
7288
8437
|
onConnectionStatusChange: options.onConnectionStatusChange || (() => {}),
|
|
7289
8438
|
onSessionGeneratingChange: options.onSessionGeneratingChange || (() => {}),
|
|
8439
|
+
onHydratingChange: options.onHydratingChange || (() => {}),
|
|
7290
8440
|
onQueueChange: options.onQueueChange || (() => {}),
|
|
7291
8441
|
onResumeStateChange: options.onResumeStateChange || (() => {}),
|
|
7292
8442
|
onRunIdChange: options.onRunIdChange || (() => {}),
|
|
@@ -7368,6 +8518,10 @@ var ChatClient = class {
|
|
|
7368
8518
|
onToolCall: (args) => {
|
|
7369
8519
|
const clientTool = (this.activeClientTools ?? this.clientToolsRef.current).get(args.toolName);
|
|
7370
8520
|
const executeFunc = clientTool?.execute;
|
|
8521
|
+
if (this.handingOverPendingToolCalls && clientTool?.needsApproval === true) {
|
|
8522
|
+
console.warn(`[ChatClient] Did not run tool call ${args.toolCallId}: ${args.toolName} needs approval, and the server did not ask for it`);
|
|
8523
|
+
return;
|
|
8524
|
+
}
|
|
7371
8525
|
if (executeFunc) {
|
|
7372
8526
|
const continuationGeneration = this.continuationGeneration;
|
|
7373
8527
|
const runEventContext = this.devtoolsBridge.getCurrentRunEventContext();
|
|
@@ -7414,9 +8568,17 @@ var ChatClient = class {
|
|
|
7414
8568
|
}
|
|
7415
8569
|
});
|
|
7416
8570
|
this.syncSubagentHandles();
|
|
7417
|
-
this.persistor?.hydrateAsync(persistedState);
|
|
8571
|
+
const storeHydration = this.persistor?.hydrateAsync(persistedState);
|
|
8572
|
+
if (storeHydration) {
|
|
8573
|
+
this.storeHydrating = true;
|
|
8574
|
+
storeHydration.finally(() => {
|
|
8575
|
+
this.storeHydrating = false;
|
|
8576
|
+
this.syncIsHydrating();
|
|
8577
|
+
});
|
|
8578
|
+
}
|
|
7418
8579
|
this.rejoinRunId = rejoinRunId;
|
|
7419
8580
|
this.cachesMessages = cachesMessages;
|
|
8581
|
+
this.isHydrating = this.storeHydrating || !cachesMessages && !!this.connection.hydrate;
|
|
7420
8582
|
}
|
|
7421
8583
|
/**
|
|
7422
8584
|
* START TAILING: re-attach to an in-flight run so its chunks arrive here.
|
|
@@ -7519,21 +8681,30 @@ var ChatClient = class {
|
|
|
7519
8681
|
*/
|
|
7520
8682
|
hydrateFromServer() {
|
|
7521
8683
|
const hydrate = this.connection.hydrate;
|
|
7522
|
-
if (!hydrate)
|
|
7523
|
-
|
|
7524
|
-
|
|
8684
|
+
if (!hydrate || this.isLoading || this.abortController || this.disposed) {
|
|
8685
|
+
this.syncIsHydrating();
|
|
8686
|
+
return;
|
|
8687
|
+
}
|
|
8688
|
+
if (this.hydrationInFlight === this.historyGeneration) return;
|
|
7525
8689
|
const pageSize = this.historyPageSize;
|
|
7526
8690
|
const hydrateOptions = pageSize === void 0 ? void 0 : { limit: pageSize };
|
|
7527
8691
|
(async () => {
|
|
7528
8692
|
let result;
|
|
7529
8693
|
const generation = this.historyGeneration;
|
|
8694
|
+
this.hydrationInFlight = generation;
|
|
8695
|
+
this.syncIsHydrating();
|
|
8696
|
+
const isCurrent = () => this.hydrationInFlight === generation && generation === this.historyGeneration;
|
|
8697
|
+
let current;
|
|
7530
8698
|
try {
|
|
7531
8699
|
result = await hydrate(this.threadId, hydrateOptions);
|
|
7532
8700
|
} catch (cause) {
|
|
7533
|
-
if (
|
|
8701
|
+
if (isCurrent()) this.failHydration(cause);
|
|
7534
8702
|
return;
|
|
8703
|
+
} finally {
|
|
8704
|
+
current = isCurrent();
|
|
8705
|
+
if (this.hydrationInFlight === generation) this.hydrationInFlight = void 0;
|
|
7535
8706
|
}
|
|
7536
|
-
if (
|
|
8707
|
+
if (!current) return;
|
|
7537
8708
|
if (this.disposed || !this.tailing) return;
|
|
7538
8709
|
if (this.isLoading || this.abortController) return;
|
|
7539
8710
|
if (this.hydrationError && this.error === this.hydrationError) {
|
|
@@ -7555,7 +8726,7 @@ var ChatClient = class {
|
|
|
7555
8726
|
pendingInterrupts: result.interrupts.pending
|
|
7556
8727
|
});
|
|
7557
8728
|
else if (result.activeRun?.runId) this.maybeRejoinInFlight(result.activeRun.runId);
|
|
7558
|
-
})();
|
|
8729
|
+
})().finally(() => this.syncIsHydrating());
|
|
7559
8730
|
}
|
|
7560
8731
|
/**
|
|
7561
8732
|
* Surface a mount-hydration failure (`persistence: true`) on the observable
|
|
@@ -7824,6 +8995,17 @@ var ChatClient = class {
|
|
|
7824
8995
|
this.isLoading = isLoading;
|
|
7825
8996
|
this.callbacksRef.current.onLoadingChange(isLoading);
|
|
7826
8997
|
this.events.loadingChanged(isLoading);
|
|
8998
|
+
if (isLoading) this.supersedeHydration();
|
|
8999
|
+
}
|
|
9000
|
+
/**
|
|
9001
|
+
* A send or a clear now owns the transcript. A load that is still pending can
|
|
9002
|
+
* no longer paint it (the generation guards drop its result), so it no longer
|
|
9003
|
+
* counts as hydrating.
|
|
9004
|
+
*/
|
|
9005
|
+
supersedeHydration() {
|
|
9006
|
+
this.hydrationInFlight = void 0;
|
|
9007
|
+
this.storeHydrating = false;
|
|
9008
|
+
this.syncIsHydrating();
|
|
7827
9009
|
}
|
|
7828
9010
|
setStatus(status) {
|
|
7829
9011
|
this.status = status;
|
|
@@ -7840,6 +9022,12 @@ var ChatClient = class {
|
|
|
7840
9022
|
this.callbacksRef.current.onConnectionStatusChange(status);
|
|
7841
9023
|
this.devtoolsBridge.emitSnapshot();
|
|
7842
9024
|
}
|
|
9025
|
+
syncIsHydrating() {
|
|
9026
|
+
const isHydrating = this.hydrationInFlight !== void 0 || this.storeHydrating;
|
|
9027
|
+
if (this.isHydrating === isHydrating) return;
|
|
9028
|
+
this.isHydrating = isHydrating;
|
|
9029
|
+
this.callbacksRef.current.onHydratingChange(isHydrating);
|
|
9030
|
+
}
|
|
7843
9031
|
setSessionGenerating(isGenerating) {
|
|
7844
9032
|
if (this.sessionGenerating === isGenerating) return;
|
|
7845
9033
|
this.sessionGenerating = isGenerating;
|
|
@@ -8105,7 +9293,12 @@ var ChatClient = class {
|
|
|
8105
9293
|
this.resolveJoinedRun(chunk);
|
|
8106
9294
|
return;
|
|
8107
9295
|
}
|
|
8108
|
-
this.
|
|
9296
|
+
this.handingOverPendingToolCalls = chunk.type === "RUN_FINISHED" && chunk.outcome?.type !== "interrupt";
|
|
9297
|
+
try {
|
|
9298
|
+
this.processor.processChunk(chunk);
|
|
9299
|
+
} finally {
|
|
9300
|
+
this.handingOverPendingToolCalls = false;
|
|
9301
|
+
}
|
|
8109
9302
|
this.syncSubagentHandles();
|
|
8110
9303
|
this.updateRunLifecycle(chunk);
|
|
8111
9304
|
this.observeInterruptState(chunk);
|
|
@@ -8328,6 +9521,14 @@ var ChatClient = class {
|
|
|
8328
9521
|
if (this.hasPendingInterrupts()) throw new Error("ChatClient: cannot append normal input while pending interrupts exist. Use resumeInterrupts() instead.");
|
|
8329
9522
|
const normalizedMessage = normalizeToUIMessage(message, generateMessageId);
|
|
8330
9523
|
if (normalizedMessage.role === "system") return;
|
|
9524
|
+
if (normalizedMessage.role === "activity") {
|
|
9525
|
+
const uiMessage = normalizedMessage;
|
|
9526
|
+
this.events.messageAppended(uiMessage);
|
|
9527
|
+
const messages = this.processor.getMessages();
|
|
9528
|
+
this.processor.setMessages([...messages, uiMessage]);
|
|
9529
|
+
this.devtoolsBridge.emitSnapshot();
|
|
9530
|
+
return;
|
|
9531
|
+
}
|
|
8331
9532
|
const uiMessage = normalizedMessage;
|
|
8332
9533
|
this.events.messageAppended(uiMessage);
|
|
8333
9534
|
const messages = this.processor.getMessages();
|
|
@@ -8544,6 +9745,7 @@ var ChatClient = class {
|
|
|
8544
9745
|
this.persistor?.beginClear();
|
|
8545
9746
|
this.processor.clearMessages();
|
|
8546
9747
|
this.resetHistoryPaging();
|
|
9748
|
+
this.supersedeHydration();
|
|
8547
9749
|
this.discardPendingSends();
|
|
8548
9750
|
this.persistor?.remove();
|
|
8549
9751
|
this.stoppedSubagentIds.clear();
|
|
@@ -8802,16 +10004,17 @@ var ChatClient = class {
|
|
|
8802
10004
|
this.rememberServerMessageIds(this.processor.getMessages());
|
|
8803
10005
|
}
|
|
8804
10006
|
messagesForSend(messages) {
|
|
8805
|
-
|
|
10007
|
+
const forModel = messages.filter((message) => message.role !== "activity");
|
|
10008
|
+
if (this.historyPageSize === void 0) return forModel;
|
|
8806
10009
|
const unknownMessages = [];
|
|
8807
|
-
for (const message of
|
|
10010
|
+
for (const message of forModel) {
|
|
8808
10011
|
if (this.knownServerMessageIds.has(message.id)) continue;
|
|
8809
10012
|
unknownMessages.push(message);
|
|
8810
10013
|
}
|
|
8811
10014
|
if (unknownMessages.length > 0) return unknownMessages;
|
|
8812
|
-
const lastUserIndex =
|
|
10015
|
+
const lastUserIndex = forModel.findLastIndex((message) => message.role === "user");
|
|
8813
10016
|
if (lastUserIndex === -1) return [];
|
|
8814
|
-
return
|
|
10017
|
+
return forModel.slice(lastUserIndex);
|
|
8815
10018
|
}
|
|
8816
10019
|
/**
|
|
8817
10020
|
* True when an interrupt (or another direct send) claimed the client during
|
|
@@ -8933,6 +10136,15 @@ var ChatClient = class {
|
|
|
8933
10136
|
return this.sessionGenerating;
|
|
8934
10137
|
}
|
|
8935
10138
|
/**
|
|
10139
|
+
* Whether the client is rebuilding the chat from persistence: the server
|
|
10140
|
+
* hydrate (`persistence: true`) or an async storage adapter. Turns false once
|
|
10141
|
+
* the transcript is applied and any in-flight run is re-joined (from then on
|
|
10142
|
+
* `isLoading` covers the stream), or when the load fails.
|
|
10143
|
+
*/
|
|
10144
|
+
getIsHydrating() {
|
|
10145
|
+
return this.isHydrating;
|
|
10146
|
+
}
|
|
10147
|
+
/**
|
|
8936
10148
|
* Get current error
|
|
8937
10149
|
*/
|
|
8938
10150
|
getError() {
|
|
@@ -8983,6 +10195,7 @@ var ChatClient = class {
|
|
|
8983
10195
|
if (options.onSubscriptionChange !== void 0) this.callbacksRef.current.onSubscriptionChange = options.onSubscriptionChange;
|
|
8984
10196
|
if (options.onConnectionStatusChange !== void 0) this.callbacksRef.current.onConnectionStatusChange = options.onConnectionStatusChange;
|
|
8985
10197
|
if (options.onSessionGeneratingChange !== void 0) this.callbacksRef.current.onSessionGeneratingChange = options.onSessionGeneratingChange;
|
|
10198
|
+
if (options.onHydratingChange !== void 0) this.callbacksRef.current.onHydratingChange = options.onHydratingChange;
|
|
8986
10199
|
if (options.onQueueChange !== void 0) this.callbacksRef.current.onQueueChange = options.onQueueChange;
|
|
8987
10200
|
if (options.onResumeStateChange !== void 0) this.callbacksRef.current.onResumeStateChange = options.onResumeStateChange;
|
|
8988
10201
|
if (options.onRunIdChange !== void 0) this.callbacksRef.current.onRunIdChange = options.onRunIdChange;
|
|
@@ -9043,16 +10256,11 @@ function toJsonSchema(parameters) {
|
|
|
9043
10256
|
properties: {}
|
|
9044
10257
|
};
|
|
9045
10258
|
if (!("~standard" in parameters)) return parameters;
|
|
9046
|
-
|
|
9047
|
-
return convertSchemaToJsonSchema(parameters);
|
|
9048
|
-
} catch {
|
|
9049
|
-
return { type: "object" };
|
|
9050
|
-
}
|
|
10259
|
+
return "jsonSchema" in parameters["~standard"] ? convertSchemaToJsonSchema(parameters) : { type: "object" };
|
|
9051
10260
|
}
|
|
9052
10261
|
async function validateParameters(parameters, input) {
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
return result.issues ? null : result.value ?? {};
|
|
10262
|
+
const result = await validateWithStandardSchema(parameters, input);
|
|
10263
|
+
return result.success ? result.data ?? {} : null;
|
|
9056
10264
|
}
|
|
9057
10265
|
//#endregion
|
|
9058
10266
|
//#region src/core/agent-tools.ts
|
|
@@ -9314,6 +10522,7 @@ async function loadChatAuthToken(options) {
|
|
|
9314
10522
|
} catch (cause) {
|
|
9315
10523
|
signal.throwIfAborted();
|
|
9316
10524
|
const error = cause instanceof Error ? cause : /* @__PURE__ */ new Error("Authentication failed");
|
|
10525
|
+
if (isAstralBeamApiError(error) && error.status === 401) error.message = "AstralBeam rejected the chat token after renewal. Check that apiUrl matches the deployment that issued your API key. If the key was revoked or expired, create a replacement in API Keys and update your server's secret.";
|
|
9317
10526
|
session.cached = void 0;
|
|
9318
10527
|
publishAuthentication(options, {
|
|
9319
10528
|
status: "error",
|
|
@@ -9445,6 +10654,11 @@ function hasPendingToolRun(messages, toolNames) {
|
|
|
9445
10654
|
return messages.some((message) => message.parts.some((part) => part.type === "tool-call" && !isSettledToolCall(part) && part.name !== "ask_questionnaire" && toolNames.has(part.name)));
|
|
9446
10655
|
}
|
|
9447
10656
|
//#endregion
|
|
10657
|
+
//#region src/core/web.ts
|
|
10658
|
+
function webPartMetadata(part) {
|
|
10659
|
+
return part.metadata ?? {};
|
|
10660
|
+
}
|
|
10661
|
+
//#endregion
|
|
9448
10662
|
//#region src/core/sandbox.ts
|
|
9449
10663
|
const SANDBOX_TOOLS = [
|
|
9450
10664
|
SANDBOX_WRITE_FILE_TOOL,
|
|
@@ -9495,19 +10709,19 @@ function sandboxPathLabel(part) {
|
|
|
9495
10709
|
if (relative !== void 0 && relative !== ".") return relative;
|
|
9496
10710
|
return text(part.output, "path") ?? text(part.input, "path");
|
|
9497
10711
|
}
|
|
9498
|
-
/** A `sandbox_publish_artifact` call whose output carries
|
|
10712
|
+
/** A `sandbox_publish_artifact` call whose output carries a durable file reference. */
|
|
9499
10713
|
function readSandboxArtifact(part) {
|
|
9500
10714
|
if (part.name !== "sandbox_publish_artifact") return void 0;
|
|
9501
10715
|
const path = text(part.output, "path") ?? text(part.input, "path");
|
|
9502
|
-
const
|
|
10716
|
+
const fileId = text(part.output, "fileId");
|
|
9503
10717
|
return {
|
|
9504
10718
|
toolCallId: part.id,
|
|
9505
10719
|
path: path ?? "",
|
|
9506
10720
|
label: sandboxPathLabel(part) ?? path ?? "",
|
|
9507
10721
|
mimeType: text(part.output, "mimeType"),
|
|
9508
10722
|
size: count(part.output, "size"),
|
|
9509
|
-
|
|
9510
|
-
published:
|
|
10723
|
+
fileId,
|
|
10724
|
+
published: fileId !== void 0 && sandboxRefusal(part) === void 0
|
|
9511
10725
|
};
|
|
9512
10726
|
}
|
|
9513
10727
|
/** A `sandbox_run_command` call. `stdout` holds combined output on providers with no stderr. */
|
|
@@ -9558,9 +10772,126 @@ function describeSandboxCommandRun(run) {
|
|
|
9558
10772
|
return parts.join(" · ");
|
|
9559
10773
|
}
|
|
9560
10774
|
//#endregion
|
|
10775
|
+
//#region src/core/threads.ts
|
|
10776
|
+
function newUuid() {
|
|
10777
|
+
const bytes = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
|
|
10778
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
10779
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
10780
|
+
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
10781
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
10782
|
+
}
|
|
10783
|
+
function threadFromRecord(record, hasMessages = true) {
|
|
10784
|
+
return {
|
|
10785
|
+
id: record.id,
|
|
10786
|
+
title: record.title,
|
|
10787
|
+
agentId: record.agent_id,
|
|
10788
|
+
version: record.version,
|
|
10789
|
+
role: record.role,
|
|
10790
|
+
writerActive: record.writer_active,
|
|
10791
|
+
hasMessages,
|
|
10792
|
+
updatedAt: record.updated_at
|
|
10793
|
+
};
|
|
10794
|
+
}
|
|
10795
|
+
function savedToolCallId(messageId, partId, targetId) {
|
|
10796
|
+
return `saved:${messageId}:${partId}${targetId ? `:${targetId}` : ""}`;
|
|
10797
|
+
}
|
|
10798
|
+
async function loadThreadMessages(id, options, pageAfter, liveToolMessageIds = /* @__PURE__ */ new Map()) {
|
|
10799
|
+
const page = await listChatMessages(id, {
|
|
10800
|
+
page_size: 100,
|
|
10801
|
+
...pageAfter ? { page_after: pageAfter } : {}
|
|
10802
|
+
}, options);
|
|
10803
|
+
const pendingInteractions = page.pending_interactions.map((pending) => ({
|
|
10804
|
+
sourceMessageId: pending.source_message_id,
|
|
10805
|
+
sourcePartId: pending.source_part_id,
|
|
10806
|
+
responseTargetId: pending.response_target_id,
|
|
10807
|
+
toolCallId: liveToolMessageIds.get(pending.tool_call_id) === pending.source_message_id ? pending.tool_call_id : savedToolCallId(pending.source_message_id, pending.source_part_id, pending.response_target_id),
|
|
10808
|
+
targetTenantUserId: pending.target_tenant_user_id,
|
|
10809
|
+
targetClientId: pending.target_client_id,
|
|
10810
|
+
executionLocation: pending.execution_location
|
|
10811
|
+
}));
|
|
10812
|
+
return {
|
|
10813
|
+
...page,
|
|
10814
|
+
pendingInteractions
|
|
10815
|
+
};
|
|
10816
|
+
}
|
|
10817
|
+
function projectThreadMessages(records, pendingInteractions = [], liveToolMessageIds = /* @__PURE__ */ new Map()) {
|
|
10818
|
+
const messages = [];
|
|
10819
|
+
const calls = /* @__PURE__ */ new Map();
|
|
10820
|
+
for (const message of records) {
|
|
10821
|
+
if (message.role === "tool") {
|
|
10822
|
+
for (const part of message.parts) {
|
|
10823
|
+
const call = calls.get(savedToolCallId(message.source_assistant_message_id, message.source_tool_part_id, message.response_target_id));
|
|
10824
|
+
if (!call) continue;
|
|
10825
|
+
call.output = part.output ?? null;
|
|
10826
|
+
if (call.name === "sandbox_publish_artifact") {
|
|
10827
|
+
call.artifactMessageId = message.id;
|
|
10828
|
+
call.artifactPartId = String(part.id);
|
|
10829
|
+
}
|
|
10830
|
+
Object.assign(call, { resultOutcome: part.outcome });
|
|
10831
|
+
call.state = part.outcome === "succeeded" ? "complete" : "error";
|
|
10832
|
+
}
|
|
10833
|
+
continue;
|
|
10834
|
+
}
|
|
10835
|
+
const parts = message.parts.flatMap((part) => {
|
|
10836
|
+
const source = part.source;
|
|
10837
|
+
if (typeof part.type === "string" && [
|
|
10838
|
+
"image",
|
|
10839
|
+
"document",
|
|
10840
|
+
"audio",
|
|
10841
|
+
"video"
|
|
10842
|
+
].includes(part.type) && source && typeof source === "object" && !Array.isArray(source) && "type" in source && source.type === "attachment") return [{
|
|
10843
|
+
...part,
|
|
10844
|
+
source: {
|
|
10845
|
+
...source,
|
|
10846
|
+
type: "url",
|
|
10847
|
+
value: ""
|
|
10848
|
+
},
|
|
10849
|
+
savedAttachmentId: part.id
|
|
10850
|
+
}];
|
|
10851
|
+
if (part.type !== "tool-call") return [part];
|
|
10852
|
+
if (part.executionLocation === "provider") return [part];
|
|
10853
|
+
const toolCallId = String(part.toolCallId);
|
|
10854
|
+
const targets = Array.isArray(part.targets) ? part.targets.flatMap((target) => target && typeof target === "object" && !Array.isArray(target) && "id" in target && typeof target.id === "string" ? [target.id] : []) : pendingInteractions.filter((pending) => pending.sourceMessageId === message.id && pending.sourcePartId === part.id).map((pending) => pending.responseTargetId);
|
|
10855
|
+
return (targets.length ? targets : [void 0]).map((responseTargetId) => {
|
|
10856
|
+
const savedId = savedToolCallId(message.id, String(part.id), responseTargetId);
|
|
10857
|
+
const call = {
|
|
10858
|
+
...part,
|
|
10859
|
+
id: liveToolMessageIds.get(toolCallId) === message.id ? toolCallId : savedId,
|
|
10860
|
+
upstreamToolCallId: toolCallId,
|
|
10861
|
+
applicationPartId: part.id,
|
|
10862
|
+
sourceMessageId: message.id,
|
|
10863
|
+
responseTargetId
|
|
10864
|
+
};
|
|
10865
|
+
calls.set(savedId, call);
|
|
10866
|
+
return call;
|
|
10867
|
+
});
|
|
10868
|
+
});
|
|
10869
|
+
messages.push({
|
|
10870
|
+
id: message.id,
|
|
10871
|
+
role: message.role,
|
|
10872
|
+
parts,
|
|
10873
|
+
createdAt: new Date(message.created_at),
|
|
10874
|
+
metadata: { astralbeam: {
|
|
10875
|
+
state: message.state,
|
|
10876
|
+
authorTenantUserId: message.author_tenant_user_id
|
|
10877
|
+
} }
|
|
10878
|
+
});
|
|
10879
|
+
}
|
|
10880
|
+
return messages;
|
|
10881
|
+
}
|
|
10882
|
+
/** Cache selection within this tab. Stored IDs are reauthorized before loading history. */
|
|
10883
|
+
function selectedThread(key, id) {
|
|
10884
|
+
try {
|
|
10885
|
+
if (id === void 0) return globalThis.sessionStorage?.getItem(key) ?? void 0;
|
|
10886
|
+
if (id === null) globalThis.sessionStorage?.removeItem(key);
|
|
10887
|
+
else globalThis.sessionStorage?.setItem(key, id);
|
|
10888
|
+
} catch {}
|
|
10889
|
+
}
|
|
10890
|
+
//#endregion
|
|
9561
10891
|
//#region src/core/session.ts
|
|
9562
10892
|
const CORE_OPTION_KEYS = Object.keys({
|
|
9563
10893
|
agentId: true,
|
|
10894
|
+
threadId: true,
|
|
9564
10895
|
apiUrl: true,
|
|
9565
10896
|
fetchAstralBeamToken: true,
|
|
9566
10897
|
tools: true,
|
|
@@ -9589,10 +10920,19 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
9589
10920
|
capabilities: { attachments: true },
|
|
9590
10921
|
agentTools: [],
|
|
9591
10922
|
sandboxStatus: void 0,
|
|
10923
|
+
usageLimitReached: void 0,
|
|
9592
10924
|
sandbox: {
|
|
9593
10925
|
files: [],
|
|
9594
10926
|
commands: []
|
|
9595
|
-
}
|
|
10927
|
+
},
|
|
10928
|
+
thread: void 0,
|
|
10929
|
+
threadLoading: false,
|
|
10930
|
+
threadLoadFailed: false,
|
|
10931
|
+
messagesCursor: void 0,
|
|
10932
|
+
olderMessagesLoading: false,
|
|
10933
|
+
unsentMessage: void 0,
|
|
10934
|
+
activeToolCallIds: [],
|
|
10935
|
+
pendingInteractions: []
|
|
9596
10936
|
};
|
|
9597
10937
|
const update = (next) => {
|
|
9598
10938
|
state = {
|
|
@@ -9610,24 +10950,99 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
9610
10950
|
let unsubscribeAuthentication;
|
|
9611
10951
|
let identity;
|
|
9612
10952
|
let started = false;
|
|
10953
|
+
let selectionGeneration = 0;
|
|
10954
|
+
let navigationGeneration = 0;
|
|
10955
|
+
let historyGeneration = 0;
|
|
10956
|
+
let hydration = Promise.resolve();
|
|
10957
|
+
let requestController = new AbortController();
|
|
10958
|
+
let threadKey;
|
|
10959
|
+
let startWithNewThread = false;
|
|
10960
|
+
let threadRecords = [];
|
|
10961
|
+
const clientId = newUuid();
|
|
10962
|
+
let pendingSend;
|
|
10963
|
+
let sending = false;
|
|
10964
|
+
const pendingSends = /* @__PURE__ */ new Map();
|
|
10965
|
+
const acceptPendingSend = () => {
|
|
10966
|
+
if (!pendingSend || pendingSend.accepted) return;
|
|
10967
|
+
pendingSend.accepted = true;
|
|
10968
|
+
if (state.thread) update({ thread: {
|
|
10969
|
+
...state.thread,
|
|
10970
|
+
hasMessages: true
|
|
10971
|
+
} });
|
|
10972
|
+
pendingSend.callbacks?.onAccepted?.();
|
|
10973
|
+
};
|
|
10974
|
+
const replaceAcceptedMessage = (record) => {
|
|
10975
|
+
const messages = [...client.getMessages()];
|
|
10976
|
+
const index = messages.findLastIndex((message) => message.role === "user");
|
|
10977
|
+
if (index !== -1) {
|
|
10978
|
+
messages[index] = projectThreadMessages([record])[0];
|
|
10979
|
+
client.setMessagesManually(messages);
|
|
10980
|
+
}
|
|
10981
|
+
};
|
|
10982
|
+
const liveToolCalls = /* @__PURE__ */ new Set();
|
|
10983
|
+
const liveToolMessageIds = /* @__PURE__ */ new Map();
|
|
10984
|
+
const historicalToolIds = /* @__PURE__ */ new Map();
|
|
10985
|
+
let toolResults = /* @__PURE__ */ new Map();
|
|
10986
|
+
const threadToolResults = /* @__PURE__ */ new Map();
|
|
10987
|
+
const toolResultKey = (id) => {
|
|
10988
|
+
const messageId = liveToolMessageIds.get(id);
|
|
10989
|
+
return messageId ? `live:${messageId}:${id}` : id;
|
|
10990
|
+
};
|
|
10991
|
+
const retainToolResults = (history) => {
|
|
10992
|
+
const retained = /* @__PURE__ */ new Map();
|
|
10993
|
+
for (const pending of history.pending_interactions) {
|
|
10994
|
+
const nativeKey = `live:${pending.source_message_id}:${pending.tool_call_id}`;
|
|
10995
|
+
const savedKey = savedToolCallId(pending.source_message_id, pending.source_part_id, pending.response_target_id);
|
|
10996
|
+
const result = toolResults.get(nativeKey) ?? toolResults.get(savedKey);
|
|
10997
|
+
if (!result) continue;
|
|
10998
|
+
retained.set(savedKey, result);
|
|
10999
|
+
if (liveToolMessageIds.get(pending.tool_call_id) === pending.source_message_id) retained.set(nativeKey, result);
|
|
11000
|
+
}
|
|
11001
|
+
toolResults.clear();
|
|
11002
|
+
for (const [id, result] of retained) toolResults.set(id, result);
|
|
11003
|
+
};
|
|
11004
|
+
const reportError = (error) => {
|
|
11005
|
+
if (error instanceof Error && error.name === "AbortError") return;
|
|
11006
|
+
const failure = error instanceof Error ? error : new Error(String(error));
|
|
11007
|
+
update({
|
|
11008
|
+
error: failure,
|
|
11009
|
+
status: "error"
|
|
11010
|
+
});
|
|
11011
|
+
if (state.auth.status !== "error" || state.auth.error !== failure) live.streamCallbacks?.onError?.(failure);
|
|
11012
|
+
};
|
|
11013
|
+
const requestOptions = async (conversation = true) => {
|
|
11014
|
+
const generation = selectionGeneration;
|
|
11015
|
+
const authSignal = authentication.session.abortController.signal;
|
|
11016
|
+
const token = await getValidChatAuthToken(authentication);
|
|
11017
|
+
authSignal.throwIfAborted();
|
|
11018
|
+
if (conversation && generation !== selectionGeneration) throw new DOMException("Conversation changed", "AbortError");
|
|
11019
|
+
return {
|
|
11020
|
+
apiUrl: authentication.apiUrl,
|
|
11021
|
+
astralBeamToken: token,
|
|
11022
|
+
cache: "no-store",
|
|
11023
|
+
signal: conversation ? AbortSignal.any([requestController.signal, authSignal]) : authSignal,
|
|
11024
|
+
fetchClient: (input, init) => fetchAuthenticatedChat({
|
|
11025
|
+
...authentication,
|
|
11026
|
+
input,
|
|
11027
|
+
init
|
|
11028
|
+
})
|
|
11029
|
+
};
|
|
11030
|
+
};
|
|
9613
11031
|
let capabilitiesGeneration = 0;
|
|
9614
11032
|
let capabilityIdentity;
|
|
9615
11033
|
const resolveCapabilities = async () => {
|
|
9616
11034
|
const generation = ++capabilitiesGeneration;
|
|
11035
|
+
const selection = selectionGeneration;
|
|
11036
|
+
if (state.thread?.agentId === null) {
|
|
11037
|
+
update({ capabilities: { attachments: false } });
|
|
11038
|
+
return;
|
|
11039
|
+
}
|
|
11040
|
+
const agentId = state.thread ? state.thread.agentId : live.agentId;
|
|
9617
11041
|
try {
|
|
9618
|
-
const
|
|
9619
|
-
if (generation !== capabilitiesGeneration) return;
|
|
9620
|
-
const body = await getChatConfig(
|
|
9621
|
-
|
|
9622
|
-
astralBeamToken: token,
|
|
9623
|
-
signal: authentication.session.abortController.signal,
|
|
9624
|
-
fetchClient: (input, init) => fetchAuthenticatedChat({
|
|
9625
|
-
...authentication,
|
|
9626
|
-
input,
|
|
9627
|
-
init
|
|
9628
|
-
})
|
|
9629
|
-
});
|
|
9630
|
-
if (generation !== capabilitiesGeneration) return;
|
|
11042
|
+
const auth = await requestOptions();
|
|
11043
|
+
if (generation !== capabilitiesGeneration || selection !== selectionGeneration) return;
|
|
11044
|
+
const body = await getChatConfig(agentId ? { agentId } : {}, auth);
|
|
11045
|
+
if (generation !== capabilitiesGeneration || selection !== selectionGeneration) return;
|
|
9631
11046
|
const attachments = body.capabilities?.attachments !== false;
|
|
9632
11047
|
update({ capabilities: { attachments } });
|
|
9633
11048
|
debug?.("mount", "agent capabilities resolved", { attachments });
|
|
@@ -9636,23 +11051,38 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
9636
11051
|
}
|
|
9637
11052
|
};
|
|
9638
11053
|
const renderCleanups = /* @__PURE__ */ new Map();
|
|
11054
|
+
const restoredWidgets = /* @__PURE__ */ new Set();
|
|
11055
|
+
const restoringWidgets = /* @__PURE__ */ new Set();
|
|
9639
11056
|
const disposeRenders = () => {
|
|
9640
11057
|
for (const cleanup of renderCleanups.values()) cleanup();
|
|
9641
11058
|
renderCleanups.clear();
|
|
11059
|
+
restoredWidgets.clear();
|
|
11060
|
+
restoringWidgets.clear();
|
|
9642
11061
|
};
|
|
9643
11062
|
const renderWidget = async (input, toolCallId) => {
|
|
11063
|
+
const generation = selectionGeneration;
|
|
9644
11064
|
const widgets = live.widgets ?? {};
|
|
9645
11065
|
if (!Object.hasOwn(widgets, input.widget)) throw new Error(`Unknown widget "${input.widget}"`);
|
|
9646
11066
|
const declaration = widgets[input.widget];
|
|
9647
11067
|
const validated = await validateParameters(declaration?.parameters, input.props ?? {});
|
|
11068
|
+
if (generation !== selectionGeneration || state.thread?.role === "viewer") return {
|
|
11069
|
+
widget: input.widget,
|
|
11070
|
+
rendered: false
|
|
11071
|
+
};
|
|
11072
|
+
if (declaration !== live.widgets?.[input.widget]) return renderWidget(input, toolCallId);
|
|
9648
11073
|
if (validated == null) throw new Error(`Props for widget "${input.widget}" failed validation`);
|
|
11074
|
+
const onRenderWidget = live.onRenderWidget;
|
|
11075
|
+
if (!onRenderWidget) return {
|
|
11076
|
+
widget: input.widget,
|
|
11077
|
+
rendered: false
|
|
11078
|
+
};
|
|
9649
11079
|
renderCleanups.get(toolCallId)?.();
|
|
9650
11080
|
renderCleanups.delete(toolCallId);
|
|
9651
11081
|
let registered;
|
|
9652
11082
|
const release = () => {
|
|
9653
11083
|
if (renderCleanups.get(toolCallId) === registered) renderCleanups.delete(toolCallId);
|
|
9654
11084
|
};
|
|
9655
|
-
const cleanup =
|
|
11085
|
+
const cleanup = onRenderWidget({
|
|
9656
11086
|
widget: input.widget,
|
|
9657
11087
|
props: validated,
|
|
9658
11088
|
toolCallId,
|
|
@@ -9662,12 +11092,68 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
9662
11092
|
registered = cleanup;
|
|
9663
11093
|
renderCleanups.set(toolCallId, cleanup);
|
|
9664
11094
|
}
|
|
11095
|
+
restoredWidgets.add(toolCallId);
|
|
9665
11096
|
return {
|
|
9666
11097
|
widget: input.widget,
|
|
9667
|
-
rendered:
|
|
11098
|
+
rendered: true
|
|
9668
11099
|
};
|
|
9669
11100
|
};
|
|
9670
|
-
const
|
|
11101
|
+
const restoreCompletedWidgets = (messages) => {
|
|
11102
|
+
if (state.thread?.role === "viewer") return;
|
|
11103
|
+
const renderIds = /* @__PURE__ */ new Map();
|
|
11104
|
+
for (const message of state.messages) for (const part of message.parts) {
|
|
11105
|
+
if (part.type !== "tool-call" || part.name !== "render_widget") continue;
|
|
11106
|
+
const stored = part;
|
|
11107
|
+
if (!stored.widgetRenderId) continue;
|
|
11108
|
+
renderIds.set(savedToolCallId(message.id, part.id), stored.widgetRenderId);
|
|
11109
|
+
if (stored.applicationPartId) renderIds.set(savedToolCallId(message.id, stored.applicationPartId, stored.responseTargetId), stored.widgetRenderId);
|
|
11110
|
+
}
|
|
11111
|
+
for (const message of messages) for (const part of message.parts) {
|
|
11112
|
+
if (part.type !== "tool-call" || part.name !== "render_widget" || part.state !== "complete" || !part.input) continue;
|
|
11113
|
+
const stored = part;
|
|
11114
|
+
const upstream = stored.upstreamToolCallId;
|
|
11115
|
+
const renderId = stored.widgetRenderId ?? renderIds.get(savedToolCallId(message.id, part.id)) ?? (stored.applicationPartId ? renderIds.get(savedToolCallId(message.id, stored.applicationPartId, stored.responseTargetId)) : void 0) ?? (upstream && liveToolMessageIds.get(upstream) === message.id && restoredWidgets.has(upstream) ? upstream : part.id);
|
|
11116
|
+
stored.widgetRenderId = renderId;
|
|
11117
|
+
if (restoredWidgets.has(renderId) || restoringWidgets.has(renderId)) continue;
|
|
11118
|
+
restoringWidgets.add(renderId);
|
|
11119
|
+
const generation = selectionGeneration;
|
|
11120
|
+
const { widgets, onRenderWidget } = live;
|
|
11121
|
+
renderWidget(part.input, renderId).catch((error) => debug?.("error", "Saved widget could not be rendered", error)).finally(() => {
|
|
11122
|
+
if (generation !== selectionGeneration) return;
|
|
11123
|
+
restoringWidgets.delete(renderId);
|
|
11124
|
+
if (widgets !== live.widgets || onRenderWidget !== live.onRenderWidget) restoreCompletedWidgets(state.messages);
|
|
11125
|
+
});
|
|
11126
|
+
}
|
|
11127
|
+
};
|
|
11128
|
+
const buildTools = () => buildAgentTools(live.widgets ?? {}, live.tools ?? {}, renderWidget, debug).map((tool) => {
|
|
11129
|
+
if (!tool.execute) return tool;
|
|
11130
|
+
const execute = tool.execute;
|
|
11131
|
+
return {
|
|
11132
|
+
...tool,
|
|
11133
|
+
execute: async (input, context) => {
|
|
11134
|
+
const toolCallId = context?.toolCallId;
|
|
11135
|
+
if (!toolCallId || !liveToolCalls.has(toolCallId)) throw new Error("A saved tool call cannot execute again. Send a new message to request it.");
|
|
11136
|
+
const results = toolResults;
|
|
11137
|
+
const key = toolResultKey(toolCallId);
|
|
11138
|
+
const resultIdentity = identity;
|
|
11139
|
+
const apiUrl = authentication.apiUrl;
|
|
11140
|
+
try {
|
|
11141
|
+
const output = await execute(input, context);
|
|
11142
|
+
if (identity === resultIdentity && authentication.apiUrl === apiUrl) results.set(key, {
|
|
11143
|
+
outcome: "succeeded",
|
|
11144
|
+
output: output ?? null
|
|
11145
|
+
});
|
|
11146
|
+
return output;
|
|
11147
|
+
} catch (error) {
|
|
11148
|
+
if (identity === resultIdentity && authentication.apiUrl === apiUrl) results.set(key, {
|
|
11149
|
+
outcome: "unknown",
|
|
11150
|
+
output: { error: error instanceof Error ? error.message : String(error) }
|
|
11151
|
+
});
|
|
11152
|
+
throw error;
|
|
11153
|
+
}
|
|
11154
|
+
}
|
|
11155
|
+
};
|
|
11156
|
+
});
|
|
9671
11157
|
const declareTools = () => {
|
|
9672
11158
|
const tools = buildTools();
|
|
9673
11159
|
const agentTools = tools.map((tool) => {
|
|
@@ -9680,40 +11166,222 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
9680
11166
|
if (!sameAgentTools(state.agentTools, agentTools)) update({ agentTools });
|
|
9681
11167
|
return tools;
|
|
9682
11168
|
};
|
|
9683
|
-
const forwardedProps = () =>
|
|
9684
|
-
|
|
9685
|
-
|
|
9686
|
-
|
|
11169
|
+
const forwardedProps = () => live.debug ? { debug: true } : {};
|
|
11170
|
+
const threadRequest = async (init, auth) => {
|
|
11171
|
+
const thread = state.thread;
|
|
11172
|
+
if (!thread || typeof init.body !== "string") throw new Error("Open a conversation before sending.");
|
|
11173
|
+
const generation = selectionGeneration;
|
|
11174
|
+
const body = JSON.parse(init.body);
|
|
11175
|
+
let path = getRunChatUrl();
|
|
11176
|
+
let payload;
|
|
11177
|
+
const submission = body.messages.at(-1)?.role === "user" ? pendingSend : void 0;
|
|
11178
|
+
const previouslyAttempted = submission?.tools !== void 0;
|
|
11179
|
+
if (submission) payload = {
|
|
11180
|
+
...body,
|
|
11181
|
+
threadId: thread.id,
|
|
11182
|
+
resume: void 0,
|
|
11183
|
+
parentRunId: void 0,
|
|
11184
|
+
messages: [body.messages.at(-1)],
|
|
11185
|
+
tools: submission.tools ??= body.tools,
|
|
11186
|
+
forwardedProps: {
|
|
11187
|
+
...body.forwardedProps,
|
|
11188
|
+
clientId
|
|
11189
|
+
}
|
|
11190
|
+
};
|
|
11191
|
+
else {
|
|
11192
|
+
scopeCompletedToolCalls();
|
|
11193
|
+
const history = await loadThreadMessages(thread.id, auth, void 0, liveToolMessageIds);
|
|
11194
|
+
if (generation !== selectionGeneration) throw new DOMException("Conversation changed", "AbortError");
|
|
11195
|
+
update({ thread: threadFromRecord(history.thread, history.messages.length > 0) });
|
|
11196
|
+
retainToolResults(history);
|
|
11197
|
+
const available = history.pendingInteractions.filter((pending) => toolResults.has(toolResultKey(pending.toolCallId)));
|
|
11198
|
+
const source = available.find((pending) => pending.toolCallId === body.messages.at(-1)?.toolCallId) ?? available[0];
|
|
11199
|
+
const results = history.pendingInteractions.flatMap((pending) => {
|
|
11200
|
+
const submitted = toolResults.get(toolResultKey(pending.toolCallId));
|
|
11201
|
+
return submitted && pending.sourceMessageId === source?.sourceMessageId ? [{
|
|
11202
|
+
source_message_id: pending.sourceMessageId,
|
|
11203
|
+
source_part_id: pending.sourcePartId,
|
|
11204
|
+
response_target_id: pending.responseTargetId,
|
|
11205
|
+
...submitted
|
|
11206
|
+
}] : [];
|
|
11207
|
+
});
|
|
11208
|
+
if (results.length === 0) return new Response("", { headers: { "Content-Type": "text/event-stream" } });
|
|
11209
|
+
path = getResolveChatToolResultUrl(thread.id);
|
|
11210
|
+
payload = {
|
|
11211
|
+
client_id: clientId,
|
|
11212
|
+
run_id: body.runId,
|
|
11213
|
+
...body.parentRunId ? { parent_run_id: body.parentRunId } : {},
|
|
11214
|
+
results
|
|
11215
|
+
};
|
|
11216
|
+
}
|
|
11217
|
+
liveToolCalls.clear();
|
|
11218
|
+
update({ activeToolCallIds: [] });
|
|
11219
|
+
const headers = new Headers(init.headers);
|
|
11220
|
+
if (submission) headers.set("Idempotency-Key", submission.key);
|
|
11221
|
+
const response = await astralBeamChatFetch(path, {
|
|
11222
|
+
...auth,
|
|
11223
|
+
...init,
|
|
11224
|
+
headers,
|
|
11225
|
+
body: JSON.stringify(payload)
|
|
11226
|
+
}).catch((error) => {
|
|
11227
|
+
const limit = isAstralBeamApiError(error) ? error.body?.usage_limit : void 0;
|
|
11228
|
+
if (limit) update({ usageLimitReached: {
|
|
11229
|
+
name: limit.name,
|
|
11230
|
+
resetsAt: limit.resets_at
|
|
11231
|
+
} });
|
|
11232
|
+
if (submission && !previouslyAttempted && isAstralBeamApiError(error) && (error.status === 400 || error.status === 413 || error.status === 429)) delete submission.tools;
|
|
11233
|
+
throw error;
|
|
11234
|
+
});
|
|
11235
|
+
if (generation !== selectionGeneration) throw new DOMException("Conversation changed", "AbortError");
|
|
11236
|
+
if (response.headers.get("Content-Type")?.includes("application/json")) {
|
|
11237
|
+
const receipt = await response.json();
|
|
11238
|
+
if (generation !== selectionGeneration) throw new DOMException("Conversation changed", "AbortError");
|
|
11239
|
+
update({
|
|
11240
|
+
thread: {
|
|
11241
|
+
...state.thread,
|
|
11242
|
+
version: receipt.thread_version
|
|
11243
|
+
},
|
|
11244
|
+
...receipt.usage_limit ? { usageLimitReached: {
|
|
11245
|
+
name: receipt.usage_limit.name,
|
|
11246
|
+
resetsAt: receipt.usage_limit.resets_at
|
|
11247
|
+
} } : {}
|
|
11248
|
+
});
|
|
11249
|
+
if (submission) {
|
|
11250
|
+
const history = await loadThreadMessages(thread.id, auth, void 0, liveToolMessageIds);
|
|
11251
|
+
if (generation !== selectionGeneration) throw new DOMException("Conversation changed", "AbortError");
|
|
11252
|
+
const accepted = history.messages.find((message) => message.id === receipt.accepted_message_id);
|
|
11253
|
+
if (accepted) replaceAcceptedMessage(accepted);
|
|
11254
|
+
acceptPendingSend();
|
|
11255
|
+
}
|
|
11256
|
+
return new Response("", { headers: { "Content-Type": "text/event-stream" } });
|
|
11257
|
+
}
|
|
11258
|
+
return response;
|
|
11259
|
+
};
|
|
9687
11260
|
const connection = fetchServerSentEvents(() => resolveApiUrl(getRunChatUrl(), authentication.apiUrl), async () => {
|
|
9688
11261
|
const previousIdentity = identity;
|
|
9689
11262
|
const token = await getValidChatAuthToken(authentication);
|
|
9690
11263
|
if (previousIdentity !== void 0 && previousIdentity !== identity) throw new DOMException("Identity changed", "AbortError");
|
|
9691
|
-
return { fetchClient: (_input, init) =>
|
|
9692
|
-
|
|
9693
|
-
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
|
|
9697
|
-
input,
|
|
9698
|
-
|
|
9699
|
-
|
|
9700
|
-
|
|
11264
|
+
return { fetchClient: (_input, init) => {
|
|
11265
|
+
const auth = {
|
|
11266
|
+
apiUrl: authentication.apiUrl,
|
|
11267
|
+
astralBeamToken: token,
|
|
11268
|
+
...init?.signal ? { signal: init.signal } : {},
|
|
11269
|
+
cache: "no-store",
|
|
11270
|
+
fetchClient: (input, request) => fetchAuthenticatedChat({
|
|
11271
|
+
...authentication,
|
|
11272
|
+
input,
|
|
11273
|
+
init: request
|
|
11274
|
+
})
|
|
11275
|
+
};
|
|
11276
|
+
return threadRequest(init ?? {}, auth);
|
|
11277
|
+
} };
|
|
9701
11278
|
});
|
|
9702
11279
|
const connect = connection.connect;
|
|
9703
11280
|
connection.connect = async function* (...args) {
|
|
9704
11281
|
try {
|
|
9705
|
-
|
|
11282
|
+
for await (const chunk of connect(...args)) {
|
|
11283
|
+
if (chunk.type === EventType.TOOL_CALL_START && chunk.parentMessageId) liveToolMessageIds.set(chunk.toolCallId, chunk.parentMessageId);
|
|
11284
|
+
if (chunk.type !== EventType.MESSAGES_SNAPSHOT) {
|
|
11285
|
+
yield chunk;
|
|
11286
|
+
continue;
|
|
11287
|
+
}
|
|
11288
|
+
let aliases;
|
|
11289
|
+
yield {
|
|
11290
|
+
...chunk,
|
|
11291
|
+
messages: chunk.messages.map((message) => {
|
|
11292
|
+
if (message.role === "assistant") {
|
|
11293
|
+
aliases = historicalToolIds.get(message.id);
|
|
11294
|
+
return aliases && message.toolCalls ? {
|
|
11295
|
+
...message,
|
|
11296
|
+
toolCalls: message.toolCalls.map((call) => ({
|
|
11297
|
+
...call,
|
|
11298
|
+
id: aliases?.get(call.id) ?? call.id
|
|
11299
|
+
}))
|
|
11300
|
+
} : message;
|
|
11301
|
+
}
|
|
11302
|
+
if (message.role === "tool") return {
|
|
11303
|
+
...message,
|
|
11304
|
+
toolCallId: aliases?.get(message.toolCallId) ?? message.toolCallId
|
|
11305
|
+
};
|
|
11306
|
+
aliases = void 0;
|
|
11307
|
+
return message;
|
|
11308
|
+
})
|
|
11309
|
+
};
|
|
11310
|
+
}
|
|
9706
11311
|
} catch (error) {
|
|
9707
11312
|
throw error instanceof Error && isAstralBeamApiError(error.cause) ? error.cause : error;
|
|
9708
11313
|
}
|
|
9709
11314
|
};
|
|
9710
|
-
const createClient = () => {
|
|
11315
|
+
const createClient = (threadId = state.thread?.id) => {
|
|
11316
|
+
const generation = selectionGeneration;
|
|
11317
|
+
const adapter = { ...connection };
|
|
11318
|
+
delete adapter.hydrate;
|
|
11319
|
+
if (threadId) adapter.hydrate = (_id, options) => {
|
|
11320
|
+
const readGeneration = ++historyGeneration;
|
|
11321
|
+
if (!options?.before) update({ threadLoading: true });
|
|
11322
|
+
const read = (async () => {
|
|
11323
|
+
let history = await loadThreadMessages(threadId, await requestOptions(), options?.before, liveToolMessageIds);
|
|
11324
|
+
while (options?.before && history.messages.every((message) => message.role === "tool") && history.page_after) {
|
|
11325
|
+
const earlier = await loadThreadMessages(threadId, await requestOptions(), history.page_after, liveToolMessageIds);
|
|
11326
|
+
history = {
|
|
11327
|
+
...earlier,
|
|
11328
|
+
messages: [...earlier.messages, ...history.messages]
|
|
11329
|
+
};
|
|
11330
|
+
}
|
|
11331
|
+
if (generation !== selectionGeneration || readGeneration !== historyGeneration) throw new DOMException("Conversation changed", "AbortError");
|
|
11332
|
+
retainToolResults(history);
|
|
11333
|
+
threadRecords = options?.before ? [...history.messages, ...threadRecords] : history.messages;
|
|
11334
|
+
const pageIds = new Set(history.messages.map((message) => message.id));
|
|
11335
|
+
const messages = projectThreadMessages(threadRecords, history.pendingInteractions, liveToolMessageIds).filter((message) => pageIds.has(message.id));
|
|
11336
|
+
if (history.thread.role === "viewer") disposeRenders();
|
|
11337
|
+
const agentChanged = state.thread?.agentId !== history.thread.agent_id;
|
|
11338
|
+
update({
|
|
11339
|
+
thread: threadFromRecord(history.thread, history.messages.length > 0),
|
|
11340
|
+
messagesCursor: history.page_after ?? void 0,
|
|
11341
|
+
pendingInteractions: history.pendingInteractions,
|
|
11342
|
+
threadLoadFailed: false
|
|
11343
|
+
});
|
|
11344
|
+
restoreCompletedWidgets(messages);
|
|
11345
|
+
if (!options?.before && agentChanged) resolveCapabilities();
|
|
11346
|
+
if (!options?.before && messages.length === 0) next.setMessagesManually([]);
|
|
11347
|
+
return {
|
|
11348
|
+
messages,
|
|
11349
|
+
activeRun: null,
|
|
11350
|
+
interrupts: null,
|
|
11351
|
+
page: history.page_after ? {
|
|
11352
|
+
truncated: true,
|
|
11353
|
+
cursor: history.page_after
|
|
11354
|
+
} : { truncated: false }
|
|
11355
|
+
};
|
|
11356
|
+
})();
|
|
11357
|
+
if (!options?.before) {
|
|
11358
|
+
hydration = read;
|
|
11359
|
+
const settled = (failed) => queueMicrotask(() => {
|
|
11360
|
+
if (generation === selectionGeneration && readGeneration === historyGeneration) update({
|
|
11361
|
+
threadLoading: false,
|
|
11362
|
+
threadLoadFailed: failed
|
|
11363
|
+
});
|
|
11364
|
+
});
|
|
11365
|
+
read.then(() => settled(false), () => settled(true));
|
|
11366
|
+
}
|
|
11367
|
+
return read;
|
|
11368
|
+
};
|
|
9711
11369
|
const next = new ChatClient({
|
|
9712
|
-
connection,
|
|
11370
|
+
connection: adapter,
|
|
11371
|
+
threadId: threadId ?? clientId,
|
|
11372
|
+
persistence: true,
|
|
11373
|
+
history: { pageSize: 100 },
|
|
11374
|
+
queue: "drop",
|
|
9713
11375
|
tools: declareTools(),
|
|
9714
11376
|
forwardedProps: forwardedProps(),
|
|
9715
11377
|
onMessagesChange: (messages) => {
|
|
9716
|
-
if (client !== next) return;
|
|
11378
|
+
if (client !== next || generation !== selectionGeneration) return;
|
|
11379
|
+
restoreCompletedWidgets(messages);
|
|
11380
|
+
for (const message of messages) {
|
|
11381
|
+
if (message.role !== "user") continue;
|
|
11382
|
+
const saved = state.messages.find((previous) => previous.id === message.id);
|
|
11383
|
+
if (saved?.parts.some((part) => "savedAttachmentId" in part)) message.parts = saved.parts;
|
|
11384
|
+
}
|
|
9717
11385
|
update({
|
|
9718
11386
|
messages,
|
|
9719
11387
|
sandbox: collectSandboxActivity(messages),
|
|
@@ -9721,13 +11389,45 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
9721
11389
|
});
|
|
9722
11390
|
},
|
|
9723
11391
|
onStatusChange: (status) => {
|
|
9724
|
-
if (client === next) update({
|
|
11392
|
+
if (client === next && generation === selectionGeneration) update({
|
|
9725
11393
|
status,
|
|
9726
|
-
error: next.getError()
|
|
11394
|
+
error: next.getError(),
|
|
11395
|
+
...status === "submitted" ? { usageLimitReached: void 0 } : {}
|
|
9727
11396
|
});
|
|
9728
11397
|
},
|
|
11398
|
+
onInterruptStateChange: (interrupts) => {
|
|
11399
|
+
if (client === next) debug?.("tool", "interrupt state changed", interrupts);
|
|
11400
|
+
},
|
|
9729
11401
|
onCustomEvent: (eventType, data) => {
|
|
9730
11402
|
if (client !== next) return;
|
|
11403
|
+
if (eventType === "astralbeam_thread") {
|
|
11404
|
+
const event = data;
|
|
11405
|
+
if (state.thread?.id === event.threadId) {
|
|
11406
|
+
if (event.acceptedMessage && pendingSend && !pendingSend.accepted) replaceAcceptedMessage(event.acceptedMessage);
|
|
11407
|
+
if (event.acceptedMessageId) acceptPendingSend();
|
|
11408
|
+
if (event.saved) for (const id of event.executableToolCallIds ?? []) {
|
|
11409
|
+
if (!liveToolCalls.has(id)) toolResults.delete(toolResultKey(id));
|
|
11410
|
+
liveToolCalls.add(id);
|
|
11411
|
+
}
|
|
11412
|
+
update({
|
|
11413
|
+
thread: {
|
|
11414
|
+
...state.thread,
|
|
11415
|
+
version: event.version
|
|
11416
|
+
},
|
|
11417
|
+
activeToolCallIds: [...liveToolCalls],
|
|
11418
|
+
...event.acceptedMessageId ? { unsentMessage: void 0 } : {}
|
|
11419
|
+
});
|
|
11420
|
+
}
|
|
11421
|
+
return;
|
|
11422
|
+
}
|
|
11423
|
+
const limit = data;
|
|
11424
|
+
if (eventType === "astralbeam.usage_limit.reached" && typeof limit?.name === "string" && typeof limit.resetsAt === "string") {
|
|
11425
|
+
update({ usageLimitReached: {
|
|
11426
|
+
name: limit.name,
|
|
11427
|
+
resetsAt: limit.resetsAt
|
|
11428
|
+
} });
|
|
11429
|
+
return;
|
|
11430
|
+
}
|
|
9731
11431
|
const value = data?.state;
|
|
9732
11432
|
if (eventType === "astralbeam.sandbox.status" && (value === "starting" || value === "ready" || value === "error")) {
|
|
9733
11433
|
debug?.("sandbox", `sandbox ${value}`);
|
|
@@ -9736,72 +11436,381 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
9736
11436
|
}
|
|
9737
11437
|
debug?.("stream", `custom event "${eventType}"`, data);
|
|
9738
11438
|
},
|
|
9739
|
-
onChunk: (chunk) =>
|
|
9740
|
-
|
|
9741
|
-
|
|
9742
|
-
|
|
11439
|
+
onChunk: (chunk) => {
|
|
11440
|
+
if (client !== next) return;
|
|
11441
|
+
live.streamCallbacks?.onChunk?.(chunk);
|
|
11442
|
+
},
|
|
11443
|
+
onResponse: (response) => {
|
|
11444
|
+
if (client === next) live.streamCallbacks?.onResponse?.(response);
|
|
11445
|
+
},
|
|
11446
|
+
onFinish: (message) => {
|
|
11447
|
+
if (client === next) live.streamCallbacks?.onFinish?.(message);
|
|
11448
|
+
},
|
|
11449
|
+
onError: (error) => {
|
|
11450
|
+
if (client === next && (state.auth.status !== "error" || state.auth.error !== error)) live.streamCallbacks?.onError?.(error);
|
|
11451
|
+
}
|
|
9743
11452
|
});
|
|
9744
11453
|
return next;
|
|
9745
11454
|
};
|
|
9746
11455
|
let client = createClient();
|
|
9747
|
-
const replaceClient = () => {
|
|
11456
|
+
const replaceClient = (threadId = state.thread?.id) => {
|
|
9748
11457
|
client.stop();
|
|
9749
11458
|
const previous = client;
|
|
9750
|
-
|
|
11459
|
+
previous.detach();
|
|
11460
|
+
liveToolCalls.clear();
|
|
11461
|
+
liveToolMessageIds.clear();
|
|
11462
|
+
update({ activeToolCallIds: [] });
|
|
11463
|
+
client = createClient(threadId);
|
|
11464
|
+
if (started) client.attach();
|
|
9751
11465
|
previous.dispose();
|
|
9752
11466
|
};
|
|
9753
|
-
const
|
|
9754
|
-
|
|
9755
|
-
|
|
9756
|
-
|
|
9757
|
-
|
|
9758
|
-
|
|
9759
|
-
|
|
9760
|
-
|
|
9761
|
-
|
|
9762
|
-
|
|
9763
|
-
|
|
9764
|
-
|
|
9765
|
-
|
|
9766
|
-
|
|
9767
|
-
|
|
9768
|
-
|
|
9769
|
-
|
|
9770
|
-
|
|
9771
|
-
|
|
9772
|
-
|
|
9773
|
-
|
|
9774
|
-
|
|
11467
|
+
const scopeCompletedToolCalls = () => {
|
|
11468
|
+
historicalToolIds.clear();
|
|
11469
|
+
client.setMessagesManually(state.messages.map((message) => {
|
|
11470
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
11471
|
+
const parts = message.parts.map((part) => {
|
|
11472
|
+
if (part.type !== "tool-call" || webPartMetadata(part).providerExecuted) return part;
|
|
11473
|
+
const stored = part;
|
|
11474
|
+
const upstreamToolCallId = stored.upstreamToolCallId ?? part.id;
|
|
11475
|
+
if (liveToolMessageIds.get(upstreamToolCallId) === message.id && !isSettledToolCall(part)) return part;
|
|
11476
|
+
const id = savedToolCallId(message.id, stored.applicationPartId ?? upstreamToolCallId, stored.responseTargetId);
|
|
11477
|
+
aliases.set(upstreamToolCallId, id);
|
|
11478
|
+
return {
|
|
11479
|
+
...part,
|
|
11480
|
+
upstreamToolCallId,
|
|
11481
|
+
id,
|
|
11482
|
+
...part.name === "render_widget" && liveToolMessageIds.get(upstreamToolCallId) === message.id ? { widgetRenderId: stored.widgetRenderId ?? part.id } : {}
|
|
11483
|
+
};
|
|
11484
|
+
});
|
|
11485
|
+
if (aliases.size) historicalToolIds.set(message.id, aliases);
|
|
11486
|
+
return {
|
|
11487
|
+
...message,
|
|
11488
|
+
parts
|
|
11489
|
+
};
|
|
11490
|
+
}));
|
|
11491
|
+
};
|
|
11492
|
+
const changeSelection = (threadId) => {
|
|
11493
|
+
const previousId = state.thread?.id;
|
|
11494
|
+
if (previousId) {
|
|
11495
|
+
if (pendingSend && !pendingSend.accepted) pendingSends.set(previousId, pendingSend);
|
|
11496
|
+
else pendingSends.delete(previousId);
|
|
11497
|
+
threadToolResults.set(previousId, toolResults);
|
|
11498
|
+
}
|
|
11499
|
+
selectionGeneration++;
|
|
11500
|
+
historyGeneration++;
|
|
11501
|
+
sending = false;
|
|
11502
|
+
requestController.abort();
|
|
11503
|
+
requestController = new AbortController();
|
|
11504
|
+
pendingSend = void 0;
|
|
11505
|
+
toolResults = threadToolResults.get(threadId ?? "") ?? /* @__PURE__ */ new Map();
|
|
11506
|
+
historicalToolIds.clear();
|
|
11507
|
+
threadRecords = [];
|
|
11508
|
+
disposeRenders();
|
|
11509
|
+
update({
|
|
11510
|
+
thread: void 0,
|
|
11511
|
+
messages: [],
|
|
11512
|
+
unsentMessage: void 0,
|
|
11513
|
+
error: void 0,
|
|
11514
|
+
status: "ready",
|
|
11515
|
+
sandbox: {
|
|
11516
|
+
files: [],
|
|
11517
|
+
commands: []
|
|
11518
|
+
},
|
|
11519
|
+
sandboxStatus: void 0,
|
|
11520
|
+
usageLimitReached: void 0,
|
|
11521
|
+
pendingInteractions: [],
|
|
11522
|
+
threadLoadFailed: false,
|
|
11523
|
+
messagesCursor: void 0,
|
|
11524
|
+
olderMessagesLoading: false
|
|
11525
|
+
});
|
|
11526
|
+
replaceClient(threadId);
|
|
11527
|
+
};
|
|
11528
|
+
const openThread = async (id, restoring = false) => {
|
|
11529
|
+
if (!restoring) navigationGeneration++;
|
|
11530
|
+
changeSelection(id);
|
|
11531
|
+
const generation = selectionGeneration;
|
|
11532
|
+
update({ threadLoading: true });
|
|
11533
|
+
try {
|
|
11534
|
+
pendingSend = pendingSends.get(id);
|
|
11535
|
+
update({ unsentMessage: pendingSend?.content });
|
|
11536
|
+
if (!started) client.attach();
|
|
11537
|
+
await hydration;
|
|
11538
|
+
if (generation !== selectionGeneration) return;
|
|
11539
|
+
if (threadKey) selectedThread(threadKey, id);
|
|
11540
|
+
} catch (error) {
|
|
11541
|
+
if (generation === selectionGeneration) {
|
|
11542
|
+
if (restoring && (live.threadId === void 0 || live.threadId === "auto") && isAstralBeamApiError(error) && error.status === 404) {
|
|
11543
|
+
newThread();
|
|
11544
|
+
return;
|
|
11545
|
+
}
|
|
11546
|
+
update({ threadLoadFailed: true });
|
|
11547
|
+
reportError(error);
|
|
11548
|
+
}
|
|
11549
|
+
} finally {
|
|
11550
|
+
if (generation === selectionGeneration) update({ threadLoading: false });
|
|
11551
|
+
}
|
|
11552
|
+
};
|
|
11553
|
+
const newThread = () => {
|
|
11554
|
+
navigationGeneration++;
|
|
11555
|
+
changeSelection();
|
|
11556
|
+
update({ threadLoading: false });
|
|
11557
|
+
if (started) resolveCapabilities();
|
|
11558
|
+
if (threadKey) selectedThread(threadKey, null);
|
|
11559
|
+
else startWithNewThread = true;
|
|
11560
|
+
};
|
|
11561
|
+
const selectConfiguredThread = (restoring = false) => {
|
|
11562
|
+
let selected = live.threadId;
|
|
11563
|
+
if (selected === void 0 || selected === "auto") {
|
|
11564
|
+
if (!threadKey) return;
|
|
11565
|
+
selected = selectedThread(threadKey);
|
|
11566
|
+
}
|
|
11567
|
+
if (selected && selected !== "new") openThread(selected, restoring);
|
|
11568
|
+
else if (!restoring) newThread();
|
|
11569
|
+
};
|
|
11570
|
+
const ensureThread = async () => {
|
|
11571
|
+
if (state.thread) return;
|
|
11572
|
+
const generation = selectionGeneration;
|
|
11573
|
+
const options = await requestOptions();
|
|
11574
|
+
const record = await createChatThread(live.agentId ? { agent_id: live.agentId } : {}, options);
|
|
11575
|
+
if (generation !== selectionGeneration) throw new DOMException("Conversation changed", "AbortError");
|
|
11576
|
+
const thread = threadFromRecord(record, false);
|
|
11577
|
+
update({ thread });
|
|
11578
|
+
replaceClient();
|
|
11579
|
+
await hydration;
|
|
11580
|
+
resolveCapabilities();
|
|
11581
|
+
if (threadKey) selectedThread(threadKey, thread.id);
|
|
11582
|
+
};
|
|
11583
|
+
const refreshThread = async (preserveError = false, resetClient = true) => {
|
|
11584
|
+
if (!state.thread?.id) return;
|
|
11585
|
+
const generation = selectionGeneration;
|
|
11586
|
+
const previousError = state.error;
|
|
11587
|
+
update({
|
|
11588
|
+
threadLoading: true,
|
|
11589
|
+
olderMessagesLoading: false
|
|
11590
|
+
});
|
|
11591
|
+
try {
|
|
11592
|
+
if (resetClient) replaceClient();
|
|
11593
|
+
else {
|
|
11594
|
+
client.detach();
|
|
11595
|
+
client.attach();
|
|
11596
|
+
}
|
|
11597
|
+
await hydration;
|
|
11598
|
+
if (generation !== selectionGeneration) return;
|
|
11599
|
+
if (preserveError && previousError) update({
|
|
11600
|
+
error: previousError,
|
|
11601
|
+
status: "error"
|
|
11602
|
+
});
|
|
11603
|
+
} catch (error) {
|
|
11604
|
+
if (generation === selectionGeneration) {
|
|
11605
|
+
if (isAstralBeamApiError(error) && error.status === 404) {
|
|
11606
|
+
newThread();
|
|
11607
|
+
return;
|
|
11608
|
+
}
|
|
11609
|
+
reportError(error);
|
|
9775
11610
|
}
|
|
11611
|
+
} finally {
|
|
11612
|
+
if (generation === selectionGeneration) update({ threadLoading: false });
|
|
11613
|
+
}
|
|
11614
|
+
};
|
|
11615
|
+
const loadOlderMessages = async () => {
|
|
11616
|
+
if (!client.getHasOlderMessages() || state.olderMessagesLoading || state.threadLoading || sending) return;
|
|
11617
|
+
const generation = selectionGeneration;
|
|
11618
|
+
update({ olderMessagesLoading: true });
|
|
11619
|
+
try {
|
|
11620
|
+
await client.loadOlderMessages();
|
|
11621
|
+
} catch (error) {
|
|
11622
|
+
if (generation === selectionGeneration) reportError(error);
|
|
11623
|
+
} finally {
|
|
11624
|
+
if (generation === selectionGeneration) update({ olderMessagesLoading: false });
|
|
11625
|
+
}
|
|
11626
|
+
};
|
|
11627
|
+
const renameThread = async (title) => {
|
|
11628
|
+
const thread = state.thread;
|
|
11629
|
+
if (!thread || thread.role !== "manager") return false;
|
|
11630
|
+
const generation = selectionGeneration;
|
|
11631
|
+
try {
|
|
11632
|
+
const record = await updateChatThread(thread.id, {
|
|
11633
|
+
title,
|
|
11634
|
+
expected_version: thread.version
|
|
11635
|
+
}, await requestOptions());
|
|
11636
|
+
if (generation !== selectionGeneration) return false;
|
|
11637
|
+
const renamed = threadFromRecord(record, thread.hasMessages);
|
|
11638
|
+
update({
|
|
11639
|
+
thread: renamed,
|
|
11640
|
+
error: client.getError(),
|
|
11641
|
+
status: client.getStatus()
|
|
11642
|
+
});
|
|
11643
|
+
return true;
|
|
11644
|
+
} catch (error) {
|
|
11645
|
+
if (generation === selectionGeneration) reportError(error);
|
|
11646
|
+
return false;
|
|
11647
|
+
}
|
|
11648
|
+
};
|
|
11649
|
+
const deleteThread = async (thread = state.thread) => {
|
|
11650
|
+
if (!thread || thread.role !== "manager") return false;
|
|
11651
|
+
const generation = selectionGeneration;
|
|
11652
|
+
try {
|
|
11653
|
+
await deleteChatThread(thread.id, { expected_version: String(thread.version) }, await requestOptions());
|
|
11654
|
+
if (generation === selectionGeneration && state.thread?.id === thread.id) newThread();
|
|
11655
|
+
return true;
|
|
11656
|
+
} catch (error) {
|
|
11657
|
+
if (generation === selectionGeneration) reportError(error);
|
|
11658
|
+
return false;
|
|
11659
|
+
}
|
|
11660
|
+
};
|
|
11661
|
+
const addToolResult = async (result) => {
|
|
11662
|
+
const generation = selectionGeneration;
|
|
11663
|
+
if (sending || client.getIsLoading()) {
|
|
11664
|
+
reportError(/* @__PURE__ */ new Error("Wait for this client's current request to finish before responding."));
|
|
11665
|
+
return;
|
|
11666
|
+
}
|
|
11667
|
+
const current = authenticationState(authentication);
|
|
11668
|
+
const pending = state.pendingInteractions.find((item) => item.toolCallId === result.toolCallId);
|
|
11669
|
+
const closure = !("tool" in result) && pending && (state.thread?.role === "manager" || current.status === "ready" && pending.targetTenantUserId === current.currentUser.user.id);
|
|
11670
|
+
const questionnaire = "tool" in result && result.tool === "ask_questionnaire" && current.status === "ready" && pending?.targetTenantUserId === current.currentUser.user.id;
|
|
11671
|
+
if (state.thread?.role === "viewer" || !liveToolCalls.has(result.toolCallId) && !questionnaire && !closure && !toolResults.has(toolResultKey(result.toolCallId))) {
|
|
11672
|
+
reportError(/* @__PURE__ */ new Error("This tool call belongs to another session and cannot be executed here."));
|
|
11673
|
+
return;
|
|
11674
|
+
}
|
|
11675
|
+
if (closure && !toolResults.has(toolResultKey(result.toolCallId))) toolResults.set(toolResultKey(result.toolCallId), {
|
|
11676
|
+
outcome: "unknown",
|
|
11677
|
+
output: null
|
|
11678
|
+
});
|
|
11679
|
+
else if (!toolResults.has(toolResultKey(result.toolCallId)) && "tool" in result) {
|
|
11680
|
+
const output = result.output;
|
|
11681
|
+
toolResults.set(toolResultKey(result.toolCallId), {
|
|
11682
|
+
outcome: result.state === "output-error" ? "failed" : "succeeded",
|
|
11683
|
+
output: output ?? null
|
|
11684
|
+
});
|
|
11685
|
+
}
|
|
11686
|
+
scopeCompletedToolCalls();
|
|
11687
|
+
if (pending) {
|
|
11688
|
+
replaceClient();
|
|
11689
|
+
await hydration;
|
|
11690
|
+
if (generation !== selectionGeneration) return;
|
|
11691
|
+
update({ threadLoading: false });
|
|
11692
|
+
await client.append({
|
|
11693
|
+
role: "tool",
|
|
11694
|
+
toolCallId: result.toolCallId,
|
|
11695
|
+
content: JSON.stringify(toolResults.get(toolResultKey(result.toolCallId)))
|
|
11696
|
+
});
|
|
11697
|
+
} else if ("tool" in result) await client.addToolResult(result);
|
|
11698
|
+
if (generation === selectionGeneration) await refreshThread(client.getError() !== void 0, false);
|
|
11699
|
+
};
|
|
11700
|
+
const abandonToolCall = (toolCallId) => addToolResult({ toolCallId });
|
|
11701
|
+
const sendMessage = async (content, callbacks) => {
|
|
11702
|
+
const navigation = navigationGeneration;
|
|
11703
|
+
try {
|
|
11704
|
+
await getValidChatAuthToken(authentication);
|
|
11705
|
+
} catch (error) {
|
|
11706
|
+
if (navigation !== navigationGeneration) return;
|
|
11707
|
+
update({ unsentMessage: content });
|
|
11708
|
+
reportError(error);
|
|
11709
|
+
return;
|
|
11710
|
+
}
|
|
11711
|
+
if (navigation !== navigationGeneration) return;
|
|
11712
|
+
if (sending || state.threadLoading || state.status === "streaming") {
|
|
11713
|
+
reportError(/* @__PURE__ */ new Error("Wait for this client's current request to finish before sending."));
|
|
11714
|
+
return;
|
|
11715
|
+
}
|
|
11716
|
+
if (state.threadLoadFailed) {
|
|
11717
|
+
reportError(/* @__PURE__ */ new Error("Reopen this conversation or start a new one before sending."));
|
|
11718
|
+
return;
|
|
11719
|
+
}
|
|
11720
|
+
const samePendingContent = pendingSend !== void 0 && JSON.stringify(pendingSend.content) === JSON.stringify(content);
|
|
11721
|
+
const uncertainSend = pendingSend?.tools !== void 0 && !pendingSend.accepted ? pendingSend : void 0;
|
|
11722
|
+
const retrying = uncertainSend !== void 0 && samePendingContent;
|
|
11723
|
+
if (state.thread?.agentId === null && !retrying) {
|
|
11724
|
+
reportError(/* @__PURE__ */ new Error("This conversation’s agent is unavailable. Start a new conversation to continue."));
|
|
11725
|
+
return;
|
|
11726
|
+
}
|
|
11727
|
+
if (state.thread?.role === "viewer" && !retrying) {
|
|
11728
|
+
reportError(/* @__PURE__ */ new Error("You have read-only access to this conversation."));
|
|
11729
|
+
return;
|
|
11730
|
+
}
|
|
11731
|
+
if (uncertainSend && !samePendingContent) {
|
|
11732
|
+
update({ unsentMessage: uncertainSend.content });
|
|
11733
|
+
reportError(/* @__PURE__ */ new Error("The previous message’s acceptance is unconfirmed. Retry that message before sending different text, or start a new conversation."));
|
|
11734
|
+
return;
|
|
11735
|
+
}
|
|
11736
|
+
const generation = selectionGeneration;
|
|
11737
|
+
historyGeneration++;
|
|
11738
|
+
update({ olderMessagesLoading: false });
|
|
11739
|
+
sending = true;
|
|
11740
|
+
if (!pendingSend || pendingSend.accepted || !samePendingContent) {
|
|
11741
|
+
pendingSend = {
|
|
11742
|
+
content,
|
|
11743
|
+
accepted: false,
|
|
11744
|
+
key: newUuid(),
|
|
11745
|
+
callbacks
|
|
11746
|
+
};
|
|
11747
|
+
client.stop();
|
|
11748
|
+
liveToolCalls.clear();
|
|
11749
|
+
scopeCompletedToolCalls();
|
|
11750
|
+
liveToolMessageIds.clear();
|
|
11751
|
+
update({ activeToolCallIds: [] });
|
|
11752
|
+
}
|
|
11753
|
+
pendingSend.callbacks ??= callbacks;
|
|
11754
|
+
update({
|
|
11755
|
+
unsentMessage: content,
|
|
11756
|
+
error: void 0,
|
|
11757
|
+
status: "submitted"
|
|
11758
|
+
});
|
|
11759
|
+
try {
|
|
11760
|
+
await ensureThread();
|
|
11761
|
+
if (generation !== selectionGeneration) return;
|
|
11762
|
+
pendingSend.callbacks?.onThreadReady?.(state.thread.id);
|
|
11763
|
+
if (generation !== selectionGeneration) return;
|
|
11764
|
+
scopeCompletedToolCalls();
|
|
11765
|
+
await client.sendMessage(content);
|
|
11766
|
+
if (generation !== selectionGeneration) return;
|
|
11767
|
+
const failed = client.getError() !== void 0;
|
|
11768
|
+
if (pendingSend?.accepted) {
|
|
11769
|
+
pendingSend = void 0;
|
|
11770
|
+
update({ unsentMessage: void 0 });
|
|
11771
|
+
}
|
|
11772
|
+
await refreshThread(failed, false);
|
|
11773
|
+
} catch (error) {
|
|
11774
|
+
if (generation === selectionGeneration) reportError(error);
|
|
11775
|
+
} finally {
|
|
11776
|
+
if (generation === selectionGeneration) sending = false;
|
|
9776
11777
|
}
|
|
9777
11778
|
};
|
|
9778
11779
|
const observeAuthentication = () => {
|
|
9779
11780
|
const auth = authenticationState(authentication);
|
|
11781
|
+
const previous = state.auth;
|
|
9780
11782
|
if (auth.status === "ready") {
|
|
9781
11783
|
const nextIdentity = authenticationIdentity(auth.currentUser);
|
|
9782
11784
|
if (identity !== void 0 && identity !== nextIdentity) {
|
|
9783
|
-
|
|
9784
|
-
|
|
9785
|
-
|
|
9786
|
-
|
|
9787
|
-
|
|
9788
|
-
files: [],
|
|
9789
|
-
commands: []
|
|
9790
|
-
},
|
|
9791
|
-
sandboxStatus: void 0
|
|
9792
|
-
});
|
|
11785
|
+
navigationGeneration++;
|
|
11786
|
+
pendingSends.clear();
|
|
11787
|
+
threadToolResults.clear();
|
|
11788
|
+
toolResults.clear();
|
|
11789
|
+
pendingSend = void 0;
|
|
9793
11790
|
}
|
|
9794
11791
|
identity = nextIdentity;
|
|
11792
|
+
const nextThreadKey = `astralbeam:thread:${live.apiUrl ?? "https://astralbeam.ai/api"}:${nextIdentity}`;
|
|
11793
|
+
if (threadKey !== nextThreadKey) {
|
|
11794
|
+
changeSelection();
|
|
11795
|
+
threadKey = nextThreadKey;
|
|
11796
|
+
if (startWithNewThread) {
|
|
11797
|
+
selectedThread(nextThreadKey, null);
|
|
11798
|
+
startWithNewThread = false;
|
|
11799
|
+
} else selectConfiguredThread(true);
|
|
11800
|
+
}
|
|
9795
11801
|
if (capabilityIdentity !== nextIdentity) {
|
|
9796
11802
|
capabilityIdentity = nextIdentity;
|
|
9797
11803
|
resolveCapabilities();
|
|
9798
11804
|
}
|
|
9799
11805
|
}
|
|
9800
11806
|
update({ auth });
|
|
11807
|
+
if (auth.status === "error" && (previous.status !== "error" || previous.error !== auth.error)) live.streamCallbacks?.onError?.(auth.error);
|
|
9801
11808
|
};
|
|
9802
11809
|
const start = () => {
|
|
9803
11810
|
if (started) return;
|
|
9804
11811
|
started = true;
|
|
11812
|
+
client.attach();
|
|
11813
|
+
if (requestController.signal.aborted) requestController = new AbortController();
|
|
9805
11814
|
unsubscribeAuthentication = subscribeAuthentication(authentication, observeAuthentication);
|
|
9806
11815
|
observeAuthentication();
|
|
9807
11816
|
stopAuthentication = startAuthentication(authentication);
|
|
@@ -9817,6 +11826,8 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
9817
11826
|
updateOptions: (next) => {
|
|
9818
11827
|
const agent = live.agentId;
|
|
9819
11828
|
const apiUrl = live.apiUrl;
|
|
11829
|
+
const selectedId = live.threadId;
|
|
11830
|
+
const { widgets, onRenderWidget } = live;
|
|
9820
11831
|
live = {
|
|
9821
11832
|
...live,
|
|
9822
11833
|
...next
|
|
@@ -9831,13 +11842,22 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
9831
11842
|
tools: declareTools(),
|
|
9832
11843
|
forwardedProps: forwardedProps()
|
|
9833
11844
|
});
|
|
11845
|
+
if (live.apiUrl !== apiUrl) {
|
|
11846
|
+
navigationGeneration++;
|
|
11847
|
+
pendingSends.clear();
|
|
11848
|
+
threadToolResults.clear();
|
|
11849
|
+
toolResults.clear();
|
|
11850
|
+
pendingSend = void 0;
|
|
11851
|
+
changeSelection();
|
|
11852
|
+
threadKey = void 0;
|
|
11853
|
+
update({ threadLoading: false });
|
|
11854
|
+
observeAuthentication();
|
|
11855
|
+
} else if (live.threadId !== selectedId) selectConfiguredThread();
|
|
11856
|
+
if (widgets !== live.widgets || onRenderWidget !== live.onRenderWidget) restoreCompletedWidgets(state.messages);
|
|
9834
11857
|
if (started && (live.agentId !== agent || live.apiUrl !== apiUrl)) resolveCapabilities();
|
|
9835
11858
|
},
|
|
9836
|
-
sendMessage
|
|
9837
|
-
|
|
9838
|
-
return client.sendMessage(content);
|
|
9839
|
-
},
|
|
9840
|
-
addToolResult: (result) => client.addToolResult(result),
|
|
11859
|
+
sendMessage,
|
|
11860
|
+
addToolResult,
|
|
9841
11861
|
stop: () => client.stop(),
|
|
9842
11862
|
retryAuthentication: () => {
|
|
9843
11863
|
getValidChatAuthToken({
|
|
@@ -9845,25 +11865,78 @@ function createAstralBeamChat(options, deferStart = false) {
|
|
|
9845
11865
|
force: true
|
|
9846
11866
|
}).catch(() => void 0);
|
|
9847
11867
|
},
|
|
9848
|
-
reload: () =>
|
|
11868
|
+
reload: async () => {
|
|
11869
|
+
const generation = selectionGeneration;
|
|
11870
|
+
await refreshThread();
|
|
11871
|
+
if (generation !== selectionGeneration || state.error) return;
|
|
11872
|
+
const attempted = /* @__PURE__ */ new Set();
|
|
11873
|
+
while (generation === selectionGeneration) {
|
|
11874
|
+
const pending = state.pendingInteractions.find((item) => !attempted.has(item.sourceMessageId) && toolResults.has(toolResultKey(item.toolCallId)));
|
|
11875
|
+
if (!pending) return;
|
|
11876
|
+
attempted.add(pending.sourceMessageId);
|
|
11877
|
+
await addToolResult({ toolCallId: pending.toolCallId });
|
|
11878
|
+
if (state.error) return;
|
|
11879
|
+
}
|
|
11880
|
+
},
|
|
11881
|
+
searchThreads: async (q = "", cursor, signal) => {
|
|
11882
|
+
const options = await requestOptions();
|
|
11883
|
+
const page = await listChatThreads({
|
|
11884
|
+
q,
|
|
11885
|
+
page_size: 50,
|
|
11886
|
+
...cursor ? { page_after: cursor } : {}
|
|
11887
|
+
}, {
|
|
11888
|
+
...options,
|
|
11889
|
+
signal: AbortSignal.any([options.signal, ...signal ? [signal] : []])
|
|
11890
|
+
});
|
|
11891
|
+
return {
|
|
11892
|
+
items: page.items.map((record) => threadFromRecord(record)),
|
|
11893
|
+
page_after: page.page_after
|
|
11894
|
+
};
|
|
11895
|
+
},
|
|
11896
|
+
openThread,
|
|
11897
|
+
renameThread,
|
|
11898
|
+
deleteThread,
|
|
11899
|
+
refreshThread,
|
|
11900
|
+
loadOlderMessages,
|
|
11901
|
+
uploadAttachment: async ({ data, filename, mimeType }) => {
|
|
11902
|
+
const agentId = state.thread ? state.thread.agentId : live.agentId;
|
|
11903
|
+
const [encoded, options] = await Promise.all([data, requestOptions(false)]);
|
|
11904
|
+
return uploadChatFile({
|
|
11905
|
+
...agentId ? { agentId } : {},
|
|
11906
|
+
type: mimeType.startsWith("image/") ? "image" : "document",
|
|
11907
|
+
source: {
|
|
11908
|
+
type: "data",
|
|
11909
|
+
value: encoded,
|
|
11910
|
+
mimeType
|
|
11911
|
+
},
|
|
11912
|
+
metadata: { filename }
|
|
11913
|
+
}, options);
|
|
11914
|
+
},
|
|
11915
|
+
getFile: async (fileId) => {
|
|
11916
|
+
const thread = state.thread;
|
|
11917
|
+
if (!thread) throw new Error("Open a conversation before downloading files.");
|
|
11918
|
+
return (await getChatFile({
|
|
11919
|
+
threadId: thread.id,
|
|
11920
|
+
fileId
|
|
11921
|
+
}, await requestOptions())).blob();
|
|
11922
|
+
},
|
|
11923
|
+
getAttachment: async (messageId, partId) => {
|
|
11924
|
+
const thread = state.thread;
|
|
11925
|
+
if (!thread) throw new Error("Open a conversation before downloading attachments.");
|
|
11926
|
+
return (await getChatAttachment(thread.id, messageId, partId, await requestOptions())).blob();
|
|
11927
|
+
},
|
|
11928
|
+
abandonToolCall,
|
|
9849
11929
|
reset: () => {
|
|
9850
11930
|
debug?.("status", "conversation reset");
|
|
9851
|
-
|
|
9852
|
-
disposeRenders();
|
|
9853
|
-
update({
|
|
9854
|
-
messages: [],
|
|
9855
|
-
status: "ready",
|
|
9856
|
-
sandbox: {
|
|
9857
|
-
files: [],
|
|
9858
|
-
commands: []
|
|
9859
|
-
},
|
|
9860
|
-
sandboxStatus: void 0,
|
|
9861
|
-
error: void 0
|
|
9862
|
-
});
|
|
11931
|
+
newThread();
|
|
9863
11932
|
},
|
|
9864
11933
|
dispose: () => {
|
|
11934
|
+
client.detach();
|
|
9865
11935
|
disposeRenders();
|
|
9866
11936
|
client.stop();
|
|
11937
|
+
requestController.abort();
|
|
11938
|
+
selectionGeneration++;
|
|
11939
|
+
threadKey = void 0;
|
|
9867
11940
|
capabilitiesGeneration++;
|
|
9868
11941
|
capabilityIdentity = void 0;
|
|
9869
11942
|
stopAuthentication?.();
|