@astralbeam/sdk 0.16.0 → 0.18.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.
Files changed (50) hide show
  1. package/README.md +11 -4
  2. package/dist/{api-DzeMhfHU.js → api-B3UxSTtl.js} +200 -10
  3. package/dist/api.d.ts +2 -2
  4. package/dist/api.js +1 -2
  5. package/dist/auth-lifecycle-B0BXyDr7.js +25 -0
  6. package/dist/badge-B9WuChHI.js +1 -0
  7. package/dist/client.d.ts +57 -8
  8. package/dist/client.js +1 -1
  9. package/dist/constants-C-Yp0Vhg.js +1 -0
  10. package/dist/{core-D84VNYWJ.js → core-CLWlvgYl.js} +1534 -129
  11. package/dist/core.d.ts +2 -2
  12. package/dist/core.js +1 -2
  13. package/dist/css-BGIxQoYs.js +1 -0
  14. package/dist/css-DgaLhXQH.js +1 -0
  15. package/dist/{debug-qLts7gEt.js → debug-DLDY8CZb.js} +1 -1
  16. package/dist/diff-woXpYk--.js +1 -0
  17. package/dist/github-dark-C-LZuMrd.js +1 -0
  18. package/dist/github-light-EUqPIrTm.js +1 -0
  19. package/dist/highlighter-Bd_oZUcA.js +152 -0
  20. package/dist/html-B3xvRgDO.js +1 -0
  21. package/dist/{index-CM3pzsKR.d.ts → index-DDfmeUeU.d.ts} +209 -86
  22. package/dist/{index-CH3RVjha.d.ts → index-DFxtXIXy.d.ts} +232 -20
  23. package/dist/item-a9y_9nk7.js +1 -0
  24. package/dist/javascript-BzbQS41l.js +1 -0
  25. package/dist/javascript-CpIGwZ_Y.js +1 -0
  26. package/dist/json-qhed-kSA.js +1 -0
  27. package/dist/jsx-Bz0zcwM4.js +1 -0
  28. package/dist/listings-DzxJtGCD.js +1 -0
  29. package/dist/markdown-BYOwaDjH.js +1 -0
  30. package/dist/mcp-servers-ESbOt00F.js +1 -0
  31. package/dist/python-gzcpVVnB.js +1 -0
  32. package/dist/react.d.ts +23 -16
  33. package/dist/react.js +46 -8
  34. package/dist/server.d.ts +19 -25
  35. package/dist/server.js +196 -349
  36. package/dist/shellscript-CLZ0U2zV.js +1 -0
  37. package/dist/sql-CEbI0hMM.js +1 -0
  38. package/dist/styles.generated-D4k7izMB.js +80 -0
  39. package/dist/tsx-udAQXfEw.js +1 -0
  40. package/dist/typescript-bsJCZSQ-.js +1 -0
  41. package/dist/validate-BOw-BAyv.js +140 -0
  42. package/dist/widget-DGmCPqzk.js +24 -0
  43. package/dist/yaml-rwi0_p6S.js +1 -0
  44. package/package.json +20 -17
  45. package/dist/constants-enyqxaJi.js +0 -1
  46. package/dist/listings-dAoOEUGK.js +0 -1
  47. package/dist/rolldown-runtime-Bh1tDfsg.js +0 -1
  48. package/dist/styles.generated-Ucyw8D9G.js +0 -98
  49. package/dist/type_checks-C-WTHaWs.js +0 -117
  50. package/dist/widget-h5LX5aq8.js +0 -11
@@ -1,11 +1,21 @@
1
- import { $ as listChatMessages, C as getCurrentUser, U as getResolveChatToolResultUrl, W as getRunChatUrl, _ as getChatConfig, dt as updateChatThread, f as createChatThread, g as getChatAttachment, gt as resolveApiUrl, h as deleteChatThread, ht as isAstralBeamApiError, mt as astralBeamChatFetch, tt as listChatThreads } from "./api-DzeMhfHU.js";
2
- import { d as JWTInvalid, h as strictDecoder, r as isObject, s as decode } from "./type_checks-C-WTHaWs.js";
1
+ import { A as getCurrentUser, At as personalMcpTestConnection, Bt as astralBeamChatFetch, C as getChatConfig, Ct as personalMcpAuthorizeConnection, Dt as personalMcpDisconnectConnection, Et as personalMcpCreateConnection, Ht as resolveApiUrl, It as updateChatThread, Ot as personalMcpGetCatalog, S as getChatAttachment, Tt as personalMcpCompleteAuthorization, Vt as isAstralBeamApiError, at as getResolveChatToolResultUrl, gt as listChatMessages, kt as personalMcpSetHeaders, ot as getRunChatUrl, v as createChatThread, vt as listChatThreads, w as getChatFile, wt as personalMcpBindBrowser, x as deleteChatThread, zt as uploadChatFile } from "./api-B3UxSTtl.js";
2
+ import { _ as strictDecoder, i as isObject, l as decode, p as JWTInvalid } from "./validate-BOw-BAyv.js";
3
3
  //#region \0rolldown/runtime.js
4
- var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
4
+ var __defProp = Object.defineProperty;
5
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod, mod.exports), 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
- //#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/util/decode_jwt.js
16
+ //#region ../node_modules/.bun/jose@6.2.12/node_modules/jose/dist/webapi/util/decode_jwt.js
7
17
  function decodeJwt(jwt) {
8
- if (typeof jwt !== "string") throw new JWTInvalid("JWTs must use Compact JWS serialization, JWT must be a string");
18
+ if (typeof jwt != "string") throw new JWTInvalid("JWTs must use Compact JWS serialization, JWT must be a string");
9
19
  const { 1: payload, length } = jwt.split(".");
10
20
  if (length === 5) throw new JWTInvalid("Only JWTs using Compact JWS serialization can be decoded");
11
21
  if (length !== 3) throw new JWTInvalid("Invalid 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.36.1/node_modules/@tanstack/ai-client/dist/esm/response-stream.js
39
+ //#region ../node_modules/.bun/@tanstack+ai-client@0.39.2+367daa2260c029d6/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.36.1/node_modules/@tanstack/ai-client/dist/esm/sse-utils.js
61
+ //#region ../node_modules/.bun/@tanstack+ai-client@0.39.2+367daa2260c029d6/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.36.1/node_modules/@tanstack/ai-client/dist/esm/message-date-normalizer.js
68
+ //#region ../node_modules/.bun/@tanstack+ai-client@0.39.2+367daa2260c029d6/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.64.0/node_modules/@tanstack/ai/dist/esm/utilities/ag-ui-usage.js
100
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/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.64.0/node_modules/@tanstack/ai/dist/esm/utilities/merge-metadata.js
145
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/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
  }
@@ -172,7 +182,7 @@ function withTanstackMetadata(value, tanstack) {
172
182
  };
173
183
  }
174
184
  //#endregion
175
- //#region node_modules/.deno/@ag-ui+core@1.0.0/node_modules/@ag-ui/core/dist/version-CTNE2I0_.mjs
185
+ //#region ../node_modules/.bun/@ag-ui+core@1.0.0+969a6d035afea0f4/node_modules/@ag-ui/core/dist/version-CTNE2I0_.mjs
176
186
  /**
177
187
  * The discriminator carried by every event.
178
188
  */
@@ -211,7 +221,7 @@ let EventType = /* @__PURE__ */ function(EventType) {
211
221
  return EventType;
212
222
  }({});
213
223
  //#endregion
214
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/utilities/reasoning-encrypted-value.js
224
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/utilities/reasoning-encrypted-value.js
215
225
  /**
216
226
  * Id prefix for the reasoning message of a redacted thinking block (Anthropic
217
227
  * `redacted_thinking`). AG-UI's `encryptedValue` does not say what kind of
@@ -223,7 +233,7 @@ function isRedactedThinkingId(id) {
223
233
  return typeof id === "string" && id.startsWith("redacted_thinking-");
224
234
  }
225
235
  //#endregion
226
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/interrupt-serialization.js
236
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/interrupt-serialization.js
227
237
  var SHA256_K = new Uint32Array([
228
238
  1116352408,
229
239
  1899447441,
@@ -398,7 +408,7 @@ function cloneAndDeepFreezeJson(value) {
398
408
  return clone;
399
409
  }
400
410
  //#endregion
401
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/interrupts.js
411
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/interrupts.js
402
412
  function canonicalizeInterruptResolutions(resolutions) {
403
413
  const frozen = cloneAndDeepFreezeJson([...resolutions].sort((left, right) => left.interruptId.localeCompare(right.interruptId)));
404
414
  const canonicalResolutions = canonicalInterruptJson(frozen);
@@ -409,7 +419,7 @@ function canonicalizeInterruptResolutions(resolutions) {
409
419
  });
410
420
  }
411
421
  //#endregion
412
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/activities/chat/tools/schema-converter.js
422
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/activities/chat/tools/schema-converter.js
413
423
  /**
414
424
  * Build a JSONSchema object from any plain key/value source. The `JSONSchema`
415
425
  * interface's `[key: string]: any` index signature makes every property
@@ -677,7 +687,7 @@ async function validateWithStandardSchema(schema, data) {
677
687
  };
678
688
  }
679
689
  //#endregion
680
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/activities/chat/tools/approval-schema.js
690
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/activities/chat/tools/approval-schema.js
681
691
  var jsonSchemaKeywords = /* @__PURE__ */ new Set([
682
692
  "$schema",
683
693
  "$id",
@@ -753,13 +763,15 @@ function normalizeApprovalSchema(approvalSchema, inputSchema) {
753
763
  const normalizedInput = inputSchema === void 0 ? null : schemaToWire(inputSchema);
754
764
  let approve = null;
755
765
  let reject = null;
756
- if (approvalSchema !== void 0) if (isStandardSchema(approvalSchema) || isRawJsonSchema(approvalSchema)) {
757
- approve = schemaToWire(approvalSchema);
758
- reject = approve;
759
- } else if (isApprovalBranchMap(approvalSchema)) {
760
- approve = approvalSchema.approve === void 0 ? null : schemaToWire(approvalSchema.approve);
761
- reject = approvalSchema.reject === void 0 ? null : schemaToWire(approvalSchema.reject);
762
- } else throw new TypeError("approvalSchema must be a SchemaInput or a nonempty map containing approve or reject.");
766
+ if (approvalSchema !== void 0) {
767
+ if (isStandardSchema(approvalSchema) || isRawJsonSchema(approvalSchema)) {
768
+ approve = schemaToWire(approvalSchema);
769
+ reject = approve;
770
+ } else if (isApprovalBranchMap(approvalSchema)) {
771
+ approve = approvalSchema.approve === void 0 ? null : schemaToWire(approvalSchema.approve);
772
+ reject = approvalSchema.reject === void 0 ? null : schemaToWire(approvalSchema.reject);
773
+ } else throw new TypeError("approvalSchema must be a SchemaInput or a nonempty map containing approve or reject.");
774
+ }
763
775
  const responseSchema = { oneOf: [decisionEnvelope({
764
776
  approved: true,
765
777
  payload: approve,
@@ -789,7 +801,7 @@ function hashSchemaInput(schema) {
789
801
  return digestInterruptJson(canonicalInterruptJson(schemaToWire(schema).jsonSchema ?? { standardValidator: "unserialized" }));
790
802
  }
791
803
  //#endregion
792
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/interrupt-resume.js
804
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/interrupt-resume.js
793
805
  /**
794
806
  * The `Interrupt.metadata` key under which this package's resume binding
795
807
  * travels.
@@ -910,7 +922,7 @@ function readInterruptBinding(descriptor) {
910
922
  };
911
923
  }
912
924
  //#endregion
913
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/interrupt-definition.js
925
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/interrupt-definition.js
914
926
  var INTERRUPT_PAYLOAD_METADATA_KEY = "tanstack:interruptPayload";
915
927
  function schemaJson(schema, name) {
916
928
  if (!isStandardJSONSchema(schema)) throw new TypeError(`${name} must be a Standard Schema with a JSON Schema converter.`);
@@ -935,7 +947,7 @@ function hashInterruptDefinitionSchema(schema) {
935
947
  return digestInterruptJson(schemaJson(schema, "Interrupt schema").canonicalJson);
936
948
  }
937
949
  //#endregion
938
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/generic-interrupt-continuation.js
950
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/generic-interrupt-continuation.js
939
951
  /**
940
952
  * `ResumeEntry.metadata` key for a first-party generic request.
941
953
  *
@@ -974,7 +986,7 @@ function genericInterruptContinuationFromDescriptor(interrupt) {
974
986
  };
975
987
  }
976
988
  //#endregion
977
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/utilities/provider-executed.js
989
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/utilities/provider-executed.js
978
990
  /**
979
991
  * Narrow a tool call's opaque `metadata` to the provider-executed convention.
980
992
  * Returns the typed metadata when the call is provider-executed, else `null`.
@@ -1004,7 +1016,7 @@ function isAssistantSegmentOf(id, parentId) {
1004
1016
  return id?.startsWith(`${parentId}-segment-`) === true;
1005
1017
  }
1006
1018
  //#endregion
1007
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/utilities/tool-result.js
1019
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/utilities/tool-result.js
1008
1020
  var CONTENT_PART_TYPES = /* @__PURE__ */ new Set([
1009
1021
  "text",
1010
1022
  "image",
@@ -1065,7 +1077,7 @@ function normalizeToolResult(result) {
1065
1077
  return JSON.stringify(result);
1066
1078
  }
1067
1079
  //#endregion
1068
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/utilities/subagent-wire.js
1080
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/utilities/subagent-wire.js
1069
1081
  function isRecord$2(value) {
1070
1082
  return typeof value === "object" && value !== null && !Array.isArray(value);
1071
1083
  }
@@ -1169,7 +1181,7 @@ function splitSubagentWire(messages) {
1169
1181
  };
1170
1182
  }
1171
1183
  //#endregion
1172
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/activities/chat/messages.js
1184
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/activities/chat/messages.js
1173
1185
  function isRecord$1(value) {
1174
1186
  return typeof value === "object" && value !== null && !Array.isArray(value);
1175
1187
  }
@@ -1362,6 +1374,7 @@ function assistantMetadata(uiMessage) {
1362
1374
  */
1363
1375
  function uiMessageToModelMessages(uiMessage) {
1364
1376
  if (uiMessage.role === "system") return [];
1377
+ if (uiMessage.role === "activity") return [];
1365
1378
  if (uiMessage.role !== "assistant") return [buildUserOrToolMessage(uiMessage)];
1366
1379
  return buildAssistantMessages(uiMessage);
1367
1380
  }
@@ -1491,6 +1504,7 @@ function buildAssistantMessages(uiMessage) {
1491
1504
  }
1492
1505
  break;
1493
1506
  case "ui-resource": break;
1507
+ case "activity": break;
1494
1508
  case "subagent": {
1495
1509
  const block = part.subagent.parentToolCallId === void 0 ? subagentHistoryText(part) : "";
1496
1510
  if (block !== "") {
@@ -1707,6 +1721,15 @@ function aguiSnapshotMessageToUIMessage(message) {
1707
1721
  }] : []
1708
1722
  });
1709
1723
  }
1724
+ case "activity": return applySnapshotMetadata(message, {
1725
+ id,
1726
+ role: "activity",
1727
+ parts: [{
1728
+ type: "activity",
1729
+ activityType: message.activityType,
1730
+ content: structuredClone(message.content)
1731
+ }]
1732
+ });
1710
1733
  default: return applySnapshotMetadata(message, {
1711
1734
  id,
1712
1735
  role: "assistant",
@@ -1752,15 +1775,23 @@ function applySnapshotMetadata(source, ui) {
1752
1775
  }
1753
1776
  function snapshotStructuredOutput(value) {
1754
1777
  if (value == null || value.status !== "streaming" && value.status !== "complete" && value.status !== "error" || typeof value.raw !== "string") return;
1755
- return {
1778
+ const base = {
1756
1779
  type: "structured-output",
1757
- status: value.status,
1758
1780
  raw: value.raw,
1759
1781
  ...value.partial !== void 0 ? { partial: value.partial } : {},
1760
- ...value.data !== void 0 ? { data: value.data } : {},
1761
1782
  ...value.reasoning ? { reasoning: value.reasoning } : {},
1762
1783
  ...value.errorMessage !== void 0 ? { errorMessage: value.errorMessage } : {}
1763
1784
  };
1785
+ if (value.status !== "complete") return {
1786
+ ...base,
1787
+ status: value.status
1788
+ };
1789
+ if (value.data === void 0) return void 0;
1790
+ return {
1791
+ ...base,
1792
+ status: "complete",
1793
+ data: value.data
1794
+ };
1764
1795
  }
1765
1796
  /**
1766
1797
  * Convert AG-UI user message content into `UIMessage` parts.
@@ -1818,7 +1849,7 @@ function generateMessageId() {
1818
1849
  return `msg-${Date.now()}-${Math.random().toString(36).substring(7)}`;
1819
1850
  }
1820
1851
  //#endregion
1821
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/utilities/ag-ui-wire.js
1852
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/utilities/ag-ui-wire.js
1822
1853
  function isRecord(value) {
1823
1854
  return typeof value === "object" && value !== null && !Array.isArray(value);
1824
1855
  }
@@ -1849,15 +1880,35 @@ function rebuiltToolMetadata(metadata, createdAt, id, content, anchorOwnsUiResou
1849
1880
  * on assistant messages are additionally emitted as fan-out
1850
1881
  * `{role:'tool',...}` and `{role:'reasoning',...}` entries for strict AG-UI
1851
1882
  * server consumers. Set `includeSnapshotStructuredOutput` to retain complete
1852
- * structured-output metadata for UI snapshots.
1883
+ * structured-output metadata for UI snapshots. Set `includeActivity` to emit
1884
+ * AG-UI `ActivityMessage` rows (MESSAGES_SNAPSHOT only — default omit so
1885
+ * RunAgentInput never carries activity).
1853
1886
  */
1854
1887
  function uiMessagesToWire(messages, options) {
1855
1888
  const wire = [];
1856
1889
  const usedWireIds = new Set(messages.flatMap((message) => "id" in message && message.id && message.role !== "tool" ? [message.id] : []));
1857
1890
  const includeSnapshotStructuredOutput = options?.includeSnapshotStructuredOutput ?? false;
1891
+ const includeActivity = options?.includeActivity ?? false;
1858
1892
  const assistantIds = /* @__PURE__ */ new Set();
1859
1893
  for (const msg of messages) if (msg.role === "assistant" && msg.id !== void 0) assistantIds.add(msg.id);
1860
1894
  for (const msg of messages) {
1895
+ if (msg.role === "activity") {
1896
+ if (includeActivity && "parts" in msg) {
1897
+ const part = msg.parts.find((p) => p.type === "activity");
1898
+ if (part) {
1899
+ const activity = {
1900
+ id: msg.id,
1901
+ role: "activity",
1902
+ activityType: part.activityType,
1903
+ content: structuredClone(part.content),
1904
+ ...msg.metadata != null && { metadata: msg.metadata },
1905
+ ...part.subagentRunId !== void 0 && { subagentRunId: part.subagentRunId }
1906
+ };
1907
+ wire.push(activity);
1908
+ }
1909
+ }
1910
+ continue;
1911
+ }
1861
1912
  if (!("parts" in msg) && msg.role === "tool" && msg.toolCallId) {
1862
1913
  const id = uniqueToolWireId(toolWireId(msg.id, msg.toolCallId, assistantIds), usedWireIds);
1863
1914
  const metadata = rebuiltToolMetadata(msg.metadata, msg.createdAt, msg.id, msg.content);
@@ -1888,14 +1939,15 @@ function uiMessagesToWire(messages, options) {
1888
1939
  parts: []
1889
1940
  };
1890
1941
  const segments = [current];
1891
- for (const part of parts) if (part.type === "thinking") if (current.parts.some((p) => p.type === "tool-call" && isProviderExecutedToolCall(p))) {
1892
- current = {
1893
- thinking: [part],
1894
- parts: []
1895
- };
1896
- segments.push(current);
1897
- } else current.thinking.push(part);
1898
- else current.parts.push(part);
1942
+ for (const part of parts) if (part.type === "thinking") {
1943
+ if (current.parts.some((p) => p.type === "tool-call" && isProviderExecutedToolCall(p))) {
1944
+ current = {
1945
+ thinking: [part],
1946
+ parts: []
1947
+ };
1948
+ segments.push(current);
1949
+ } else current.thinking.push(part);
1950
+ } else current.parts.push(part);
1899
1951
  segments.forEach((segment, index) => {
1900
1952
  for (const part of segment.thinking) {
1901
1953
  const reasoning = {
@@ -2132,7 +2184,7 @@ function hashContent(s) {
2132
2184
  return Math.abs(h).toString(36);
2133
2185
  }
2134
2186
  //#endregion
2135
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/utilities/restore-inbound-chunk.js
2187
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/utilities/restore-inbound-chunk.js
2136
2188
  /**
2137
2189
  * Rebuild TanStack `TokenUsage` (`promptTokens`) from spec `usage[]` plus
2138
2190
  * leftover fields in `metadata.tanstack.usage`. Restore in-process aliases
@@ -2169,7 +2221,7 @@ function restoreInboundChunk(chunk) {
2169
2221
  return next;
2170
2222
  }
2171
2223
  //#endregion
2172
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/activities/chat/tools/tool-definition.js
2224
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/activities/chat/tools/tool-definition.js
2173
2225
  /**
2174
2226
  * Create an isomorphic tool definition that can be used directly or instantiated for server/client
2175
2227
  *
@@ -2267,7 +2319,7 @@ function toolDefinition(config) {
2267
2319
  };
2268
2320
  }
2269
2321
  //#endregion
2270
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/utilities/chunk-ids.js
2322
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/utilities/chunk-ids.js
2271
2323
  function stringField(value) {
2272
2324
  return typeof value === "string" && value !== "" ? value : void 0;
2273
2325
  }
@@ -2280,7 +2332,7 @@ function getChunkRunId(chunk) {
2280
2332
  return stringField(tanstackMetadata(chunk)?.runId);
2281
2333
  }
2282
2334
  //#endregion
2283
- //#region node_modules/.deno/partial-json@0.1.7/node_modules/partial-json/dist/options.js
2335
+ //#region ../node_modules/.bun/partial-json@0.1.7/node_modules/partial-json/dist/options.js
2284
2336
  var require_options = /* @__PURE__ */ __commonJSMin(((exports) => {
2285
2337
  /**
2286
2338
  * Sometimes you don't allow every type to be partially parsed.
@@ -2370,9 +2422,9 @@ var require_options = /* @__PURE__ */ __commonJSMin(((exports) => {
2370
2422
  exports.default = exports.Allow;
2371
2423
  }));
2372
2424
  //#endregion
2373
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/activities/chat/stream/json-parser.js
2374
- var import_dist = (/* @__PURE__ */ __commonJSMin(((exports) => {
2375
- var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
2425
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/activities/chat/stream/json-parser.js
2426
+ var import_dist = (/* @__PURE__ */ __commonJSMin(((exports, module, this$1) => {
2427
+ var __createBinding = this$1 && this$1.__createBinding || (Object.create ? (function(o, m, k, k2) {
2376
2428
  if (k2 === void 0) k2 = k;
2377
2429
  var desc = Object.getOwnPropertyDescriptor(m, k);
2378
2430
  if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) desc = {
@@ -2386,8 +2438,8 @@ var import_dist = (/* @__PURE__ */ __commonJSMin(((exports) => {
2386
2438
  if (k2 === void 0) k2 = k;
2387
2439
  o[k2] = m[k];
2388
2440
  }));
2389
- var __exportStar = exports && exports.__exportStar || function(m, exports$1) {
2390
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports$1, p)) __createBinding(exports$1, m, p);
2441
+ var __exportStar = this$1 && this$1.__exportStar || function(m, exports) {
2442
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
2391
2443
  };
2392
2444
  Object.defineProperty(exports, "__esModule", { value: true });
2393
2445
  exports.Allow = exports.MalformedJSON = exports.PartialJSON = exports.parseJSON = exports.parse = void 0;
@@ -2592,7 +2644,7 @@ function parsePartialJSON(jsonString) {
2592
2644
  return defaultJSONParser.parse(jsonString);
2593
2645
  }
2594
2646
  //#endregion
2595
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/activities/chat/stream/strategies.js
2647
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/activities/chat/stream/strategies.js
2596
2648
  /**
2597
2649
  * Immediate Strategy - emit on every chunk (default behavior)
2598
2650
  */
@@ -2602,7 +2654,7 @@ var ImmediateStrategy = class {
2602
2654
  }
2603
2655
  };
2604
2656
  //#endregion
2605
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/utilities/errors.js
2657
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/utilities/errors.js
2606
2658
  /**
2607
2659
  * Convert an AG-UI RUN_ERROR event to the Error shape exposed to consumers.
2608
2660
  * Preserves the provider code and sanitized raw event when available, while
@@ -2616,7 +2668,732 @@ function runErrorEventToError(chunk) {
2616
2668
  return error;
2617
2669
  }
2618
2670
  //#endregion
2619
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/activities/chat/stream/message-updaters.js
2671
+ //#region ../node_modules/.bun/fast-json-patch@3.1.1/node_modules/fast-json-patch/module/helpers.mjs
2672
+ /*!
2673
+ * https://github.com/Starcounter-Jack/JSON-Patch
2674
+ * (c) 2017-2022 Joachim Wester
2675
+ * MIT licensed
2676
+ */
2677
+ var __extends = (function() {
2678
+ var extendStatics = function(d, b) {
2679
+ extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d, b) {
2680
+ d.__proto__ = b;
2681
+ } || function(d, b) {
2682
+ for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
2683
+ };
2684
+ return extendStatics(d, b);
2685
+ };
2686
+ return function(d, b) {
2687
+ extendStatics(d, b);
2688
+ function __() {
2689
+ this.constructor = d;
2690
+ }
2691
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
2692
+ };
2693
+ })();
2694
+ var _hasOwnProperty = Object.prototype.hasOwnProperty;
2695
+ function hasOwnProperty(obj, key) {
2696
+ return _hasOwnProperty.call(obj, key);
2697
+ }
2698
+ function _objectKeys(obj) {
2699
+ if (Array.isArray(obj)) {
2700
+ var keys_1 = new Array(obj.length);
2701
+ for (var k = 0; k < keys_1.length; k++) keys_1[k] = "" + k;
2702
+ return keys_1;
2703
+ }
2704
+ if (Object.keys) return Object.keys(obj);
2705
+ var keys = [];
2706
+ for (var i in obj) if (hasOwnProperty(obj, i)) keys.push(i);
2707
+ return keys;
2708
+ }
2709
+ /**
2710
+ * Deeply clone the object.
2711
+ * https://jsperf.com/deep-copy-vs-json-stringify-json-parse/25 (recursiveDeepCopy)
2712
+ * @param {any} obj value to clone
2713
+ * @return {any} cloned obj
2714
+ */
2715
+ function _deepClone(obj) {
2716
+ switch (typeof obj) {
2717
+ case "object": return JSON.parse(JSON.stringify(obj));
2718
+ case "undefined": return null;
2719
+ default: return obj;
2720
+ }
2721
+ }
2722
+ function isInteger(str) {
2723
+ var i = 0;
2724
+ var len = str.length;
2725
+ var charCode;
2726
+ while (i < len) {
2727
+ charCode = str.charCodeAt(i);
2728
+ if (charCode >= 48 && charCode <= 57) {
2729
+ i++;
2730
+ continue;
2731
+ }
2732
+ return false;
2733
+ }
2734
+ return true;
2735
+ }
2736
+ /**
2737
+ * Escapes a json pointer path
2738
+ * @param path The raw pointer
2739
+ * @return the Escaped path
2740
+ */
2741
+ function escapePathComponent(path) {
2742
+ if (path.indexOf("/") === -1 && path.indexOf("~") === -1) return path;
2743
+ return path.replace(/~/g, "~0").replace(/\//g, "~1");
2744
+ }
2745
+ /**
2746
+ * Unescapes a json pointer path
2747
+ * @param path The escaped pointer
2748
+ * @return The unescaped path
2749
+ */
2750
+ function unescapePathComponent(path) {
2751
+ return path.replace(/~1/g, "/").replace(/~0/g, "~");
2752
+ }
2753
+ /**
2754
+ * Recursively checks whether an object has any undefined values inside.
2755
+ */
2756
+ function hasUndefined(obj) {
2757
+ if (obj === void 0) return true;
2758
+ if (obj) {
2759
+ if (Array.isArray(obj)) {
2760
+ for (var i_1 = 0, len = obj.length; i_1 < len; i_1++) if (hasUndefined(obj[i_1])) return true;
2761
+ } else if (typeof obj === "object") {
2762
+ var objKeys = _objectKeys(obj);
2763
+ var objKeysLength = objKeys.length;
2764
+ for (var i = 0; i < objKeysLength; i++) if (hasUndefined(obj[objKeys[i]])) return true;
2765
+ }
2766
+ }
2767
+ return false;
2768
+ }
2769
+ function patchErrorMessageFormatter(message, args) {
2770
+ var messageParts = [message];
2771
+ for (var key in args) {
2772
+ var value = typeof args[key] === "object" ? JSON.stringify(args[key], null, 2) : args[key];
2773
+ if (typeof value !== "undefined") messageParts.push(key + ": " + value);
2774
+ }
2775
+ return messageParts.join("\n");
2776
+ }
2777
+ var PatchError = function(_super) {
2778
+ __extends(PatchError, _super);
2779
+ function PatchError(message, name, index, operation, tree) {
2780
+ var _newTarget = this.constructor;
2781
+ var _this = _super.call(this, patchErrorMessageFormatter(message, {
2782
+ name,
2783
+ index,
2784
+ operation,
2785
+ tree
2786
+ })) || this;
2787
+ _this.name = name;
2788
+ _this.index = index;
2789
+ _this.operation = operation;
2790
+ _this.tree = tree;
2791
+ Object.setPrototypeOf(_this, _newTarget.prototype);
2792
+ _this.message = patchErrorMessageFormatter(message, {
2793
+ name,
2794
+ index,
2795
+ operation,
2796
+ tree
2797
+ });
2798
+ return _this;
2799
+ }
2800
+ return PatchError;
2801
+ }(Error);
2802
+ //#endregion
2803
+ //#region ../node_modules/.bun/fast-json-patch@3.1.1/node_modules/fast-json-patch/module/core.mjs
2804
+ var core_exports = /* @__PURE__ */ __exportAll({
2805
+ JsonPatchError: () => JsonPatchError,
2806
+ _areEquals: () => _areEquals,
2807
+ applyOperation: () => applyOperation,
2808
+ applyPatch: () => applyPatch,
2809
+ applyReducer: () => applyReducer,
2810
+ deepClone: () => deepClone,
2811
+ getValueByPointer: () => getValueByPointer,
2812
+ validate: () => validate,
2813
+ validator: () => validator
2814
+ });
2815
+ var JsonPatchError = PatchError;
2816
+ var deepClone = _deepClone;
2817
+ var objOps = {
2818
+ add: function(obj, key, document) {
2819
+ obj[key] = this.value;
2820
+ return { newDocument: document };
2821
+ },
2822
+ remove: function(obj, key, document) {
2823
+ var removed = obj[key];
2824
+ delete obj[key];
2825
+ return {
2826
+ newDocument: document,
2827
+ removed
2828
+ };
2829
+ },
2830
+ replace: function(obj, key, document) {
2831
+ var removed = obj[key];
2832
+ obj[key] = this.value;
2833
+ return {
2834
+ newDocument: document,
2835
+ removed
2836
+ };
2837
+ },
2838
+ move: function(obj, key, document) {
2839
+ var removed = getValueByPointer(document, this.path);
2840
+ if (removed) removed = _deepClone(removed);
2841
+ var originalValue = applyOperation(document, {
2842
+ op: "remove",
2843
+ path: this.from
2844
+ }).removed;
2845
+ applyOperation(document, {
2846
+ op: "add",
2847
+ path: this.path,
2848
+ value: originalValue
2849
+ });
2850
+ return {
2851
+ newDocument: document,
2852
+ removed
2853
+ };
2854
+ },
2855
+ copy: function(obj, key, document) {
2856
+ var valueToCopy = getValueByPointer(document, this.from);
2857
+ applyOperation(document, {
2858
+ op: "add",
2859
+ path: this.path,
2860
+ value: _deepClone(valueToCopy)
2861
+ });
2862
+ return { newDocument: document };
2863
+ },
2864
+ test: function(obj, key, document) {
2865
+ return {
2866
+ newDocument: document,
2867
+ test: _areEquals(obj[key], this.value)
2868
+ };
2869
+ },
2870
+ _get: function(obj, key, document) {
2871
+ this.value = obj[key];
2872
+ return { newDocument: document };
2873
+ }
2874
+ };
2875
+ var arrOps = {
2876
+ add: function(arr, i, document) {
2877
+ if (isInteger(i)) arr.splice(i, 0, this.value);
2878
+ else arr[i] = this.value;
2879
+ return {
2880
+ newDocument: document,
2881
+ index: i
2882
+ };
2883
+ },
2884
+ remove: function(arr, i, document) {
2885
+ return {
2886
+ newDocument: document,
2887
+ removed: arr.splice(i, 1)[0]
2888
+ };
2889
+ },
2890
+ replace: function(arr, i, document) {
2891
+ var removed = arr[i];
2892
+ arr[i] = this.value;
2893
+ return {
2894
+ newDocument: document,
2895
+ removed
2896
+ };
2897
+ },
2898
+ move: objOps.move,
2899
+ copy: objOps.copy,
2900
+ test: objOps.test,
2901
+ _get: objOps._get
2902
+ };
2903
+ /**
2904
+ * Retrieves a value from a JSON document by a JSON pointer.
2905
+ * Returns the value.
2906
+ *
2907
+ * @param document The document to get the value from
2908
+ * @param pointer an escaped JSON pointer
2909
+ * @return The retrieved value
2910
+ */
2911
+ function getValueByPointer(document, pointer) {
2912
+ if (pointer == "") return document;
2913
+ var getOriginalDestination = {
2914
+ op: "_get",
2915
+ path: pointer
2916
+ };
2917
+ applyOperation(document, getOriginalDestination);
2918
+ return getOriginalDestination.value;
2919
+ }
2920
+ /**
2921
+ * Apply a single JSON Patch Operation on a JSON document.
2922
+ * Returns the {newDocument, result} of the operation.
2923
+ * It modifies the `document` and `operation` objects - it gets the values by reference.
2924
+ * If you would like to avoid touching your values, clone them:
2925
+ * `jsonpatch.applyOperation(document, jsonpatch._deepClone(operation))`.
2926
+ *
2927
+ * @param document The document to patch
2928
+ * @param operation The operation to apply
2929
+ * @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.
2930
+ * @param mutateDocument Whether to mutate the original document or clone it before applying
2931
+ * @param banPrototypeModifications Whether to ban modifications to `__proto__`, defaults to `true`.
2932
+ * @return `{newDocument, result}` after the operation
2933
+ */
2934
+ function applyOperation(document, operation, validateOperation, mutateDocument, banPrototypeModifications, index) {
2935
+ if (validateOperation === void 0) validateOperation = false;
2936
+ if (mutateDocument === void 0) mutateDocument = true;
2937
+ if (banPrototypeModifications === void 0) banPrototypeModifications = true;
2938
+ if (index === void 0) index = 0;
2939
+ if (validateOperation) {
2940
+ if (typeof validateOperation == "function") validateOperation(operation, 0, document, operation.path);
2941
+ else validator(operation, 0);
2942
+ }
2943
+ if (operation.path === "") {
2944
+ var returnValue = { newDocument: document };
2945
+ if (operation.op === "add") {
2946
+ returnValue.newDocument = operation.value;
2947
+ return returnValue;
2948
+ } else if (operation.op === "replace") {
2949
+ returnValue.newDocument = operation.value;
2950
+ returnValue.removed = document;
2951
+ return returnValue;
2952
+ } else if (operation.op === "move" || operation.op === "copy") {
2953
+ returnValue.newDocument = getValueByPointer(document, operation.from);
2954
+ if (operation.op === "move") returnValue.removed = document;
2955
+ return returnValue;
2956
+ } else if (operation.op === "test") {
2957
+ returnValue.test = _areEquals(document, operation.value);
2958
+ if (returnValue.test === false) throw new JsonPatchError("Test operation failed", "TEST_OPERATION_FAILED", index, operation, document);
2959
+ returnValue.newDocument = document;
2960
+ return returnValue;
2961
+ } else if (operation.op === "remove") {
2962
+ returnValue.removed = document;
2963
+ returnValue.newDocument = null;
2964
+ return returnValue;
2965
+ } else if (operation.op === "_get") {
2966
+ operation.value = document;
2967
+ return returnValue;
2968
+ } else if (validateOperation) throw new JsonPatchError("Operation `op` property is not one of operations defined in RFC-6902", "OPERATION_OP_INVALID", index, operation, document);
2969
+ else return returnValue;
2970
+ } else {
2971
+ if (!mutateDocument) document = _deepClone(document);
2972
+ var keys = (operation.path || "").split("/");
2973
+ var obj = document;
2974
+ var t = 1;
2975
+ var len = keys.length;
2976
+ var existingPathFragment = void 0;
2977
+ var key = void 0;
2978
+ var validateFunction = void 0;
2979
+ if (typeof validateOperation == "function") validateFunction = validateOperation;
2980
+ else validateFunction = validator;
2981
+ while (true) {
2982
+ key = keys[t];
2983
+ if (key && key.indexOf("~") != -1) key = unescapePathComponent(key);
2984
+ 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");
2985
+ if (validateOperation) {
2986
+ if (existingPathFragment === void 0) {
2987
+ if (obj[key] === void 0) existingPathFragment = keys.slice(0, t).join("/");
2988
+ else if (t == len - 1) existingPathFragment = operation.path;
2989
+ if (existingPathFragment !== void 0) validateFunction(operation, 0, document, existingPathFragment);
2990
+ }
2991
+ }
2992
+ t++;
2993
+ if (Array.isArray(obj)) {
2994
+ if (key === "-") key = obj.length;
2995
+ 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);
2996
+ else if (isInteger(key)) key = ~~key;
2997
+ if (t >= len) {
2998
+ 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);
2999
+ var returnValue = arrOps[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
+ } else if (t >= len) {
3004
+ var returnValue = objOps[operation.op].call(operation, obj, key, document);
3005
+ if (returnValue.test === false) throw new JsonPatchError("Test operation failed", "TEST_OPERATION_FAILED", index, operation, document);
3006
+ return returnValue;
3007
+ }
3008
+ obj = obj[key];
3009
+ if (validateOperation && t < len && (!obj || typeof obj !== "object")) throw new JsonPatchError("Cannot perform operation at the desired path", "OPERATION_PATH_UNRESOLVABLE", index, operation, document);
3010
+ }
3011
+ }
3012
+ }
3013
+ /**
3014
+ * Apply a full JSON Patch array on a JSON document.
3015
+ * Returns the {newDocument, result} of the patch.
3016
+ * It modifies the `document` object and `patch` - it gets the values by reference.
3017
+ * If you would like to avoid touching your values, clone them:
3018
+ * `jsonpatch.applyPatch(document, jsonpatch._deepClone(patch))`.
3019
+ *
3020
+ * @param document The document to patch
3021
+ * @param patch The patch to apply
3022
+ * @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.
3023
+ * @param mutateDocument Whether to mutate the original document or clone it before applying
3024
+ * @param banPrototypeModifications Whether to ban modifications to `__proto__`, defaults to `true`.
3025
+ * @return An array of `{newDocument, result}` after the patch
3026
+ */
3027
+ function applyPatch(document, patch, validateOperation, mutateDocument, banPrototypeModifications) {
3028
+ if (mutateDocument === void 0) mutateDocument = true;
3029
+ if (banPrototypeModifications === void 0) banPrototypeModifications = true;
3030
+ if (validateOperation) {
3031
+ if (!Array.isArray(patch)) throw new JsonPatchError("Patch sequence must be an array", "SEQUENCE_NOT_AN_ARRAY");
3032
+ }
3033
+ if (!mutateDocument) document = _deepClone(document);
3034
+ var results = new Array(patch.length);
3035
+ for (var i = 0, length_1 = patch.length; i < length_1; i++) {
3036
+ results[i] = applyOperation(document, patch[i], validateOperation, true, banPrototypeModifications, i);
3037
+ document = results[i].newDocument;
3038
+ }
3039
+ results.newDocument = document;
3040
+ return results;
3041
+ }
3042
+ /**
3043
+ * Apply a single JSON Patch Operation on a JSON document.
3044
+ * Returns the updated document.
3045
+ * Suitable as a reducer.
3046
+ *
3047
+ * @param document The document to patch
3048
+ * @param operation The operation to apply
3049
+ * @return The updated document
3050
+ */
3051
+ function applyReducer(document, operation, index) {
3052
+ var operationResult = applyOperation(document, operation);
3053
+ if (operationResult.test === false) throw new JsonPatchError("Test operation failed", "TEST_OPERATION_FAILED", index, operation, document);
3054
+ return operationResult.newDocument;
3055
+ }
3056
+ /**
3057
+ * Validates a single operation. Called from `jsonpatch.validate`. Throws `JsonPatchError` in case of an error.
3058
+ * @param {object} operation - operation object (patch)
3059
+ * @param {number} index - index of operation in the sequence
3060
+ * @param {object} [document] - object where the operation is supposed to be applied
3061
+ * @param {string} [existingPathFragment] - comes along with `document`
3062
+ */
3063
+ function validator(operation, index, document, existingPathFragment) {
3064
+ if (typeof operation !== "object" || operation === null || Array.isArray(operation)) throw new JsonPatchError("Operation is not an object", "OPERATION_NOT_AN_OBJECT", index, operation, document);
3065
+ 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);
3066
+ else if (typeof operation.path !== "string") throw new JsonPatchError("Operation `path` property is not a string", "OPERATION_PATH_INVALID", index, operation, document);
3067
+ 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);
3068
+ 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);
3069
+ 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);
3070
+ 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);
3071
+ else if (document) {
3072
+ if (operation.op == "add") {
3073
+ var pathLen = operation.path.split("/").length;
3074
+ var existingPathLen = existingPathFragment.split("/").length;
3075
+ 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);
3076
+ } else if (operation.op === "replace" || operation.op === "remove" || operation.op === "_get") {
3077
+ if (operation.path !== existingPathFragment) throw new JsonPatchError("Cannot perform the operation at a path that does not exist", "OPERATION_PATH_UNRESOLVABLE", index, operation, document);
3078
+ } else if (operation.op === "move" || operation.op === "copy") {
3079
+ var error = validate([{
3080
+ op: "_get",
3081
+ path: operation.from,
3082
+ value: void 0
3083
+ }], document);
3084
+ 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);
3085
+ }
3086
+ }
3087
+ }
3088
+ /**
3089
+ * Validates a sequence of operations. If `document` parameter is provided, the sequence is additionally validated against the object document.
3090
+ * If error is encountered, returns a JsonPatchError object
3091
+ * @param sequence
3092
+ * @param document
3093
+ * @returns {JsonPatchError|undefined}
3094
+ */
3095
+ function validate(sequence, document, externalValidator) {
3096
+ try {
3097
+ if (!Array.isArray(sequence)) throw new JsonPatchError("Patch sequence must be an array", "SEQUENCE_NOT_AN_ARRAY");
3098
+ if (document) applyPatch(_deepClone(document), _deepClone(sequence), externalValidator || true);
3099
+ else {
3100
+ externalValidator = externalValidator || validator;
3101
+ for (var i = 0; i < sequence.length; i++) externalValidator(sequence[i], i, document, void 0);
3102
+ }
3103
+ } catch (e) {
3104
+ if (e instanceof JsonPatchError) return e;
3105
+ else throw e;
3106
+ }
3107
+ }
3108
+ function _areEquals(a, b) {
3109
+ if (a === b) return true;
3110
+ if (a && b && typeof a == "object" && typeof b == "object") {
3111
+ var arrA = Array.isArray(a), arrB = Array.isArray(b), i, length, key;
3112
+ if (arrA && arrB) {
3113
+ length = a.length;
3114
+ if (length != b.length) return false;
3115
+ for (i = length; i-- !== 0;) if (!_areEquals(a[i], b[i])) return false;
3116
+ return true;
3117
+ }
3118
+ if (arrA != arrB) return false;
3119
+ var keys = Object.keys(a);
3120
+ length = keys.length;
3121
+ if (length !== Object.keys(b).length) return false;
3122
+ for (i = length; i-- !== 0;) if (!b.hasOwnProperty(keys[i])) return false;
3123
+ for (i = length; i-- !== 0;) {
3124
+ key = keys[i];
3125
+ if (!_areEquals(a[key], b[key])) return false;
3126
+ }
3127
+ return true;
3128
+ }
3129
+ return a !== a && b !== b;
3130
+ }
3131
+ //#endregion
3132
+ //#region ../node_modules/.bun/fast-json-patch@3.1.1/node_modules/fast-json-patch/module/duplex.mjs
3133
+ /*!
3134
+ * https://github.com/Starcounter-Jack/JSON-Patch
3135
+ * (c) 2017-2021 Joachim Wester
3136
+ * MIT license
3137
+ */
3138
+ var duplex_exports = /* @__PURE__ */ __exportAll({
3139
+ compare: () => compare,
3140
+ generate: () => generate,
3141
+ observe: () => observe,
3142
+ unobserve: () => unobserve
3143
+ });
3144
+ var beforeDict = /* @__PURE__ */ new WeakMap();
3145
+ var Mirror = function() {
3146
+ function Mirror(obj) {
3147
+ this.observers = /* @__PURE__ */ new Map();
3148
+ this.obj = obj;
3149
+ }
3150
+ return Mirror;
3151
+ }();
3152
+ var ObserverInfo = function() {
3153
+ function ObserverInfo(callback, observer) {
3154
+ this.callback = callback;
3155
+ this.observer = observer;
3156
+ }
3157
+ return ObserverInfo;
3158
+ }();
3159
+ function getMirror(obj) {
3160
+ return beforeDict.get(obj);
3161
+ }
3162
+ function getObserverFromMirror(mirror, callback) {
3163
+ return mirror.observers.get(callback);
3164
+ }
3165
+ function removeObserverFromMirror(mirror, observer) {
3166
+ mirror.observers.delete(observer.callback);
3167
+ }
3168
+ /**
3169
+ * Detach an observer from an object
3170
+ */
3171
+ function unobserve(root, observer) {
3172
+ observer.unobserve();
3173
+ }
3174
+ /**
3175
+ * Observes changes made to an object, which can then be retrieved using generate
3176
+ */
3177
+ function observe(obj, callback) {
3178
+ var patches = [];
3179
+ var observer;
3180
+ var mirror = getMirror(obj);
3181
+ if (!mirror) {
3182
+ mirror = new Mirror(obj);
3183
+ beforeDict.set(obj, mirror);
3184
+ } else {
3185
+ var observerInfo = getObserverFromMirror(mirror, callback);
3186
+ observer = observerInfo && observerInfo.observer;
3187
+ }
3188
+ if (observer) return observer;
3189
+ observer = {};
3190
+ mirror.value = _deepClone(obj);
3191
+ if (callback) {
3192
+ observer.callback = callback;
3193
+ observer.next = null;
3194
+ var dirtyCheck = function() {
3195
+ generate(observer);
3196
+ };
3197
+ var fastCheck = function() {
3198
+ clearTimeout(observer.next);
3199
+ observer.next = setTimeout(dirtyCheck);
3200
+ };
3201
+ if (typeof window !== "undefined") {
3202
+ window.addEventListener("mouseup", fastCheck);
3203
+ window.addEventListener("keyup", fastCheck);
3204
+ window.addEventListener("mousedown", fastCheck);
3205
+ window.addEventListener("keydown", fastCheck);
3206
+ window.addEventListener("change", fastCheck);
3207
+ }
3208
+ }
3209
+ observer.patches = patches;
3210
+ observer.object = obj;
3211
+ observer.unobserve = function() {
3212
+ generate(observer);
3213
+ clearTimeout(observer.next);
3214
+ removeObserverFromMirror(mirror, observer);
3215
+ if (typeof window !== "undefined") {
3216
+ window.removeEventListener("mouseup", fastCheck);
3217
+ window.removeEventListener("keyup", fastCheck);
3218
+ window.removeEventListener("mousedown", fastCheck);
3219
+ window.removeEventListener("keydown", fastCheck);
3220
+ window.removeEventListener("change", fastCheck);
3221
+ }
3222
+ };
3223
+ mirror.observers.set(callback, new ObserverInfo(callback, observer));
3224
+ return observer;
3225
+ }
3226
+ /**
3227
+ * Generate an array of patches from an observer
3228
+ */
3229
+ function generate(observer, invertible) {
3230
+ if (invertible === void 0) invertible = false;
3231
+ var mirror = beforeDict.get(observer.object);
3232
+ _generate(mirror.value, observer.object, observer.patches, "", invertible);
3233
+ if (observer.patches.length) applyPatch(mirror.value, observer.patches);
3234
+ var temp = observer.patches;
3235
+ if (temp.length > 0) {
3236
+ observer.patches = [];
3237
+ if (observer.callback) observer.callback(temp);
3238
+ }
3239
+ return temp;
3240
+ }
3241
+ function _generate(mirror, obj, patches, path, invertible) {
3242
+ if (obj === mirror) return;
3243
+ if (typeof obj.toJSON === "function") obj = obj.toJSON();
3244
+ var newKeys = _objectKeys(obj);
3245
+ var oldKeys = _objectKeys(mirror);
3246
+ var deleted = false;
3247
+ for (var t = oldKeys.length - 1; t >= 0; t--) {
3248
+ var key = oldKeys[t];
3249
+ var oldVal = mirror[key];
3250
+ if (hasOwnProperty(obj, key) && !(obj[key] === void 0 && oldVal !== void 0 && Array.isArray(obj) === false)) {
3251
+ var newVal = obj[key];
3252
+ 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);
3253
+ else if (oldVal !== newVal) {
3254
+ if (invertible) patches.push({
3255
+ op: "test",
3256
+ path: path + "/" + escapePathComponent(key),
3257
+ value: _deepClone(oldVal)
3258
+ });
3259
+ patches.push({
3260
+ op: "replace",
3261
+ path: path + "/" + escapePathComponent(key),
3262
+ value: _deepClone(newVal)
3263
+ });
3264
+ }
3265
+ } else if (Array.isArray(mirror) === Array.isArray(obj)) {
3266
+ if (invertible) patches.push({
3267
+ op: "test",
3268
+ path: path + "/" + escapePathComponent(key),
3269
+ value: _deepClone(oldVal)
3270
+ });
3271
+ patches.push({
3272
+ op: "remove",
3273
+ path: path + "/" + escapePathComponent(key)
3274
+ });
3275
+ deleted = true;
3276
+ } else {
3277
+ if (invertible) patches.push({
3278
+ op: "test",
3279
+ path,
3280
+ value: mirror
3281
+ });
3282
+ patches.push({
3283
+ op: "replace",
3284
+ path,
3285
+ value: obj
3286
+ });
3287
+ }
3288
+ }
3289
+ if (!deleted && newKeys.length == oldKeys.length) return;
3290
+ for (var t = 0; t < newKeys.length; t++) {
3291
+ var key = newKeys[t];
3292
+ if (!hasOwnProperty(mirror, key) && obj[key] !== void 0) patches.push({
3293
+ op: "add",
3294
+ path: path + "/" + escapePathComponent(key),
3295
+ value: _deepClone(obj[key])
3296
+ });
3297
+ }
3298
+ }
3299
+ /**
3300
+ * Create an array of patches from the differences in two objects
3301
+ */
3302
+ function compare(tree1, tree2, invertible) {
3303
+ if (invertible === void 0) invertible = false;
3304
+ var patches = [];
3305
+ _generate(tree1, tree2, patches, "", invertible);
3306
+ return patches;
3307
+ }
3308
+ //#endregion
3309
+ //#region ../node_modules/.bun/fast-json-patch@3.1.1/node_modules/fast-json-patch/index.mjs
3310
+ /**
3311
+ * Default export for backwards compat
3312
+ */
3313
+ var fast_json_patch_default = Object.assign({}, core_exports, duplex_exports, {
3314
+ JsonPatchError: PatchError,
3315
+ deepClone: _deepClone,
3316
+ escapePathComponent,
3317
+ unescapePathComponent
3318
+ });
3319
+ //#endregion
3320
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/activities/chat/activity-records.js
3321
+ function isActivityPart(part) {
3322
+ return part.type === "activity";
3323
+ }
3324
+ function isActivityContent(value) {
3325
+ return value != null && typeof value === "object" && !Array.isArray(value);
3326
+ }
3327
+ function applyActivitySnapshotToUIMessages(messages, chunk) {
3328
+ const { messageId, activityType, content } = chunk;
3329
+ const replace = chunk.replace ?? true;
3330
+ const existingIndex = messages.findIndex((m) => m.id === messageId);
3331
+ const existing = existingIndex >= 0 ? messages[existingIndex] : void 0;
3332
+ if (existing && existing.role !== "activity") {
3333
+ console.warn(`ACTIVITY_SNAPSHOT: Message '${messageId}' is not an activity message`);
3334
+ return messages;
3335
+ }
3336
+ if (existing && !replace) return messages;
3337
+ const metadata = mergeMetadata(existing?.role === "activity" ? existing.metadata : void 0, chunk.metadata);
3338
+ const next = {
3339
+ id: messageId,
3340
+ role: "activity",
3341
+ parts: [{
3342
+ type: "activity",
3343
+ activityType,
3344
+ content: structuredClone(content ?? {})
3345
+ }],
3346
+ ...metadata != null ? { metadata } : {},
3347
+ ...existing?.role === "activity" && existing.createdAt != null ? { createdAt: existing.createdAt } : {},
3348
+ ...existing?.role === "activity" && existing.name != null ? { name: existing.name } : {}
3349
+ };
3350
+ if (existingIndex === -1) return [...messages, next];
3351
+ return messages.map((msg, index) => index === existingIndex ? next : msg);
3352
+ }
3353
+ function applyActivityDeltaToUIMessages(messages, chunk) {
3354
+ const { messageId, activityType, patch } = chunk;
3355
+ const existingIndex = messages.findIndex((m) => m.id === messageId);
3356
+ if (existingIndex === -1) {
3357
+ console.warn(`ACTIVITY_DELTA: No activity message '${messageId}'`);
3358
+ return messages;
3359
+ }
3360
+ const existing = messages[existingIndex];
3361
+ if (existing == null || existing.role !== "activity") {
3362
+ console.warn(`ACTIVITY_DELTA: Message '${messageId}' is not an activity message`);
3363
+ return messages;
3364
+ }
3365
+ const activityPart = existing.parts.find(isActivityPart);
3366
+ if (activityPart && activityPart.activityType !== activityType) {
3367
+ console.warn(`ACTIVITY_DELTA: activityType '${activityType}' does not match '${activityPart.activityType}' for '${messageId}'`);
3368
+ return messages;
3369
+ }
3370
+ const baseContent = structuredClone(activityPart?.content ?? {});
3371
+ try {
3372
+ const result = fast_json_patch_default.applyPatch(baseContent, patch ?? [], true, false);
3373
+ if (!isActivityContent(result.newDocument)) {
3374
+ console.warn(`ACTIVITY_DELTA: patched content for '${messageId}' is not an object`);
3375
+ return messages;
3376
+ }
3377
+ const nextPart = {
3378
+ type: "activity",
3379
+ activityType,
3380
+ content: structuredClone(result.newDocument)
3381
+ };
3382
+ const parts = activityPart ? existing.parts.map((part) => part.type === "activity" ? nextPart : part) : [nextPart];
3383
+ const metadata = mergeMetadata(existing.metadata, chunk.metadata);
3384
+ return messages.map((msg, index) => index === existingIndex ? {
3385
+ ...msg,
3386
+ parts,
3387
+ ...metadata != null ? { metadata } : {}
3388
+ } : msg);
3389
+ } catch (error) {
3390
+ const errorMessage = error instanceof Error ? error.message : String(error);
3391
+ console.warn(`Failed to apply activity patch for '${messageId}': ${errorMessage}`);
3392
+ return messages;
3393
+ }
3394
+ }
3395
+ //#endregion
3396
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/activities/chat/stream/message-updaters.js
2620
3397
  /**
2621
3398
  * Message Updaters (Internal)
2622
3399
  *
@@ -2918,7 +3695,7 @@ function updateThinkingPart(messages, messageId, stepId, content, signature) {
2918
3695
  });
2919
3696
  }
2920
3697
  //#endregion
2921
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/activities/chat/stream/processor.js
3698
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/activities/chat/stream/processor.js
2922
3699
  /**
2923
3700
  * Unified Stream Processor
2924
3701
  *
@@ -2939,6 +3716,28 @@ function updateThinkingPart(messages, messageId, stepId, content, signature) {
2939
3716
  * adapter contract, single-shot flows, and expected UIMessage output.
2940
3717
  */
2941
3718
  var STRUCTURED_OUTPUT_UPDATE_BATCH_SIZE = 12;
3719
+ /**
3720
+ * Events that leave this processor's open *_CHUNK stream open.
3721
+ * RAW, activity events, and REASONING_ENCRYPTED_VALUE match the AG-UI client.
3722
+ * Subagent lifecycle events stay here too: the child processor owns that
3723
+ * lane, and SUBAGENT_FINISHED or SUBAGENT_ERROR finalizes the child.
3724
+ */
3725
+ var CHUNK_PASS_THROUGH = /* @__PURE__ */ new Set([
3726
+ "RAW",
3727
+ "ACTIVITY_SNAPSHOT",
3728
+ "ACTIVITY_DELTA",
3729
+ "REASONING_ENCRYPTED_VALUE",
3730
+ "SUBAGENT_STARTED",
3731
+ "SUBAGENT_FINISHED",
3732
+ "SUBAGENT_ERROR"
3733
+ ]);
3734
+ /** A run-level event closes every open shorthand lane, including children. */
3735
+ var RUN_LEVEL_CLOSES_LANES = /* @__PURE__ */ new Set([
3736
+ "RUN_STARTED",
3737
+ "RUN_FINISHED",
3738
+ "RUN_ERROR",
3739
+ "MESSAGES_SNAPSHOT"
3740
+ ]);
2942
3741
  function interruptBatchHasGeneric(interrupts) {
2943
3742
  return interrupts.some((interrupt) => {
2944
3743
  const metadata = interrupt.metadata;
@@ -2964,6 +3763,19 @@ function serializeToolInput(input) {
2964
3763
  }
2965
3764
  }
2966
3765
  /**
3766
+ * The input of a tool call from its raw arguments: `{}` for an empty string,
3767
+ * `undefined` when the arguments are not complete JSON (for example cut off)
3768
+ * or are `null`.
3769
+ */
3770
+ function parseToolArguments(args) {
3771
+ if (args.trim() === "") return {};
3772
+ try {
3773
+ return JSON.parse(args) ?? void 0;
3774
+ } catch {
3775
+ return;
3776
+ }
3777
+ }
3778
+ /**
2967
3779
  * StreamProcessor - State machine for processing AI response streams
2968
3780
  *
2969
3781
  * Manages the full UIMessage[] conversation and emits events on changes.
@@ -2990,9 +3802,12 @@ var StreamProcessor = class StreamProcessor {
2990
3802
  toolCallToMessage = /* @__PURE__ */ new Map();
2991
3803
  pendingManualMessageId = null;
2992
3804
  pendingThinkingStepId = null;
3805
+ openChunk = null;
2993
3806
  structuredMessageIds = /* @__PURE__ */ new Set();
2994
3807
  structuredOutputUpdateBatches = /* @__PURE__ */ new Map();
2995
3808
  activeRuns = /* @__PURE__ */ new Set();
3809
+ runToolCallIds = [];
3810
+ toolCallsSentToClient = /* @__PURE__ */ new Set();
2996
3811
  childProcessors = /* @__PURE__ */ new Map();
2997
3812
  childToolCalls = /* @__PURE__ */ new Map();
2998
3813
  finishReason = null;
@@ -3199,6 +4014,7 @@ var StreamProcessor = class StreamProcessor {
3199
4014
  this.structuredMessageIds.clear();
3200
4015
  this.structuredOutputUpdateBatches.clear();
3201
4016
  this.pendingManualMessageId = null;
4017
+ this.openChunk = null;
3202
4018
  this.childProcessors.clear();
3203
4019
  this.childToolCalls.clear();
3204
4020
  this.emitMessagesChange();
@@ -3219,7 +4035,7 @@ var StreamProcessor = class StreamProcessor {
3219
4035
  *
3220
4036
  * Central dispatch for all AG-UI events. Each event type maps to a specific
3221
4037
  * handler. Events not listed in the switch are intentionally ignored
3222
- * (STEP_STARTED, STATE_SNAPSHOT, STATE_DELTA).
4038
+ * (STATE_SNAPSHOT, STATE_DELTA).
3223
4039
  *
3224
4040
  * @see docs/chat-architecture.md#adapter-contract — Expected event types and ordering
3225
4041
  */
@@ -3230,6 +4046,10 @@ var StreamProcessor = class StreamProcessor {
3230
4046
  index: this.recording.chunks.length
3231
4047
  });
3232
4048
  if (this.routeToChild(chunk)) return;
4049
+ for (const event of this.expandChunk(chunk)) this.dispatchChunk(event);
4050
+ }
4051
+ /** Send one event, after expandChunk(), to its handler. */
4052
+ dispatchChunk(chunk) {
3233
4053
  switch (chunk.type) {
3234
4054
  case "SUBAGENT_STARTED":
3235
4055
  this.handleSubagentStartedEvent(chunk);
@@ -3289,7 +4109,178 @@ var StreamProcessor = class StreamProcessor {
3289
4109
  case "TOOL_CALL_RESULT":
3290
4110
  this.handleToolCallResultEvent(chunk);
3291
4111
  break;
3292
- case "STEP_STARTED": this.handleStepStartedEvent(chunk);
4112
+ case "STEP_STARTED":
4113
+ this.handleStepStartedEvent(chunk);
4114
+ break;
4115
+ case "ACTIVITY_SNAPSHOT":
4116
+ this.handleActivitySnapshotEvent(chunk);
4117
+ break;
4118
+ case "ACTIVITY_DELTA": this.handleActivityDeltaEvent(chunk);
4119
+ }
4120
+ }
4121
+ /**
4122
+ * AG-UI lets a producer send one TEXT_MESSAGE_CHUNK, TOOL_CALL_CHUNK or
4123
+ * REASONING_MESSAGE_CHUNK in place of the START / CONTENT (ARGS) / END
4124
+ * events. A chunk with a new id opens a stream. A chunk with the same id or
4125
+ * no id continues it. Any other event closes it, except the ones in
4126
+ * CHUNK_PASS_THROUGH. Expand the shorthand into the START / CONTENT (ARGS)
4127
+ * / END events, so both forms build the same message.
4128
+ */
4129
+ expandChunk(chunk) {
4130
+ const open = this.openChunk;
4131
+ const timestamp = chunk.timestamp;
4132
+ switch (chunk.type) {
4133
+ case "TEXT_MESSAGE_CHUNK": {
4134
+ const id = this.chunkStreamId("TEXT_MESSAGE", chunk.messageId, chunk.type);
4135
+ if (id === void 0) return this.closeChunk();
4136
+ const events = [];
4137
+ if (open?.family !== "TEXT_MESSAGE" || open.id !== id) {
4138
+ events.push(...this.closeChunk(), {
4139
+ type: EventType.TEXT_MESSAGE_START,
4140
+ messageId: id,
4141
+ role: chunk.role ?? "assistant",
4142
+ ...chunk.name !== void 0 ? { name: chunk.name } : {},
4143
+ timestamp
4144
+ });
4145
+ this.openChunk = {
4146
+ family: "TEXT_MESSAGE",
4147
+ id
4148
+ };
4149
+ }
4150
+ if (chunk.delta !== void 0 || chunk.metadata !== void 0) events.push({
4151
+ type: EventType.TEXT_MESSAGE_CONTENT,
4152
+ messageId: id,
4153
+ delta: chunk.delta ?? "",
4154
+ metadata: chunk.metadata,
4155
+ timestamp
4156
+ });
4157
+ return events;
4158
+ }
4159
+ case "TOOL_CALL_CHUNK": {
4160
+ const id = this.chunkStreamId("TOOL_CALL", chunk.toolCallId, chunk.type);
4161
+ if (id === void 0) return this.closeChunk();
4162
+ const events = [];
4163
+ if (open?.family !== "TOOL_CALL" || open.id !== id) {
4164
+ if (chunk.toolCallName === void 0) {
4165
+ console.warn(`[StreamProcessor] Dropped TOOL_CALL_CHUNK ${id}: the first chunk of a tool call needs a toolCallName`);
4166
+ return this.closeChunk();
4167
+ }
4168
+ events.push(...this.closeChunk(), {
4169
+ type: EventType.TOOL_CALL_START,
4170
+ toolCallId: id,
4171
+ toolCallName: chunk.toolCallName,
4172
+ parentMessageId: chunk.parentMessageId,
4173
+ metadata: chunk.metadata,
4174
+ timestamp
4175
+ });
4176
+ this.openChunk = {
4177
+ family: "TOOL_CALL",
4178
+ id
4179
+ };
4180
+ }
4181
+ if (chunk.delta !== void 0 || chunk.metadata !== void 0) events.push({
4182
+ type: EventType.TOOL_CALL_ARGS,
4183
+ toolCallId: id,
4184
+ delta: chunk.delta ?? "",
4185
+ ...chunk.metadata !== void 0 ? { metadata: chunk.metadata } : {},
4186
+ timestamp
4187
+ });
4188
+ return events;
4189
+ }
4190
+ case "REASONING_MESSAGE_CHUNK": {
4191
+ const id = this.chunkStreamId("REASONING_MESSAGE", chunk.messageId, chunk.type);
4192
+ if (id === void 0) return this.closeChunk();
4193
+ const events = [];
4194
+ if (open?.family !== "REASONING_MESSAGE" || open.id !== id) {
4195
+ events.push(...this.closeChunk(), {
4196
+ type: EventType.REASONING_MESSAGE_START,
4197
+ messageId: id,
4198
+ role: "reasoning",
4199
+ timestamp
4200
+ });
4201
+ this.openChunk = {
4202
+ family: "REASONING_MESSAGE",
4203
+ id
4204
+ };
4205
+ }
4206
+ if (chunk.delta !== void 0 || chunk.metadata !== void 0) events.push({
4207
+ type: EventType.REASONING_MESSAGE_CONTENT,
4208
+ messageId: id,
4209
+ delta: chunk.delta ?? "",
4210
+ ...chunk.metadata !== void 0 ? { metadata: chunk.metadata } : {},
4211
+ timestamp
4212
+ });
4213
+ return events;
4214
+ }
4215
+ default: {
4216
+ const events = open && !CHUNK_PASS_THROUGH.has(chunk.type) ? this.closeChunk() : [];
4217
+ if (RUN_LEVEL_CLOSES_LANES.has(chunk.type)) this.closeChildChunkLanes();
4218
+ return [...events, chunk];
4219
+ }
4220
+ }
4221
+ }
4222
+ /** Synthesize *_END on every nested shorthand lane and apply those events there. */
4223
+ closeChildChunkLanes() {
4224
+ for (const child of this.childProcessors.values()) {
4225
+ for (const event of child.closeChunk()) child.dispatchChunk(event);
4226
+ child.closeChildChunkLanes();
4227
+ }
4228
+ }
4229
+ /**
4230
+ * The child an untagged chunk with no id continues: the only child whose
4231
+ * subtree has an open chunk stream of its kind, when this processor has
4232
+ * none. The AG-UI client resolves a chunk that tags only its opener the
4233
+ * same way.
4234
+ */
4235
+ childContinuing(chunk) {
4236
+ let family;
4237
+ if (chunk.type === "TEXT_MESSAGE_CHUNK" && chunk.messageId === void 0) family = "TEXT_MESSAGE";
4238
+ else if (chunk.type === "REASONING_MESSAGE_CHUNK" && chunk.messageId === void 0) family = "REASONING_MESSAGE";
4239
+ else if (chunk.type === "TOOL_CALL_CHUNK" && chunk.toolCallId === void 0) family = "TOOL_CALL";
4240
+ else return;
4241
+ if (this.openChunkCount(family) !== 1) return void 0;
4242
+ for (const [id, child] of this.childProcessors) if (child.openChunkCount(family) === 1) return id;
4243
+ }
4244
+ /**
4245
+ * How many open chunk streams of a kind this processor and all its nested
4246
+ * children hold.
4247
+ */
4248
+ openChunkCount(family) {
4249
+ let count = this.openChunk?.family === family ? 1 : 0;
4250
+ for (const child of this.childProcessors.values()) count += child.openChunkCount(family);
4251
+ return count;
4252
+ }
4253
+ /**
4254
+ * The id a chunk opens or continues. A chunk with no id continues. If it
4255
+ * continues nothing, the caller drops it and closes the open stream, so a
4256
+ * later chunk with no id cannot continue that stream either.
4257
+ */
4258
+ chunkStreamId(family, id, type) {
4259
+ if (id !== void 0) return id;
4260
+ if (this.openChunk?.family === family) return this.openChunk.id;
4261
+ console.warn(`[StreamProcessor] Dropped ${type}: it has no id and continues nothing`);
4262
+ }
4263
+ closeChunk() {
4264
+ const open = this.openChunk;
4265
+ if (!open) return [];
4266
+ this.openChunk = null;
4267
+ const timestamp = Date.now();
4268
+ switch (open.family) {
4269
+ case "TEXT_MESSAGE": return [{
4270
+ type: EventType.TEXT_MESSAGE_END,
4271
+ messageId: open.id,
4272
+ timestamp
4273
+ }];
4274
+ case "TOOL_CALL": return [{
4275
+ type: EventType.TOOL_CALL_END,
4276
+ toolCallId: open.id,
4277
+ timestamp
4278
+ }];
4279
+ case "REASONING_MESSAGE": return [{
4280
+ type: EventType.REASONING_MESSAGE_END,
4281
+ messageId: open.id,
4282
+ timestamp
4283
+ }];
3293
4284
  }
3294
4285
  }
3295
4286
  /**
@@ -3366,7 +4357,7 @@ var StreamProcessor = class StreamProcessor {
3366
4357
  * MESSAGES_SNAPSHOT) but whose transient state was cleared. In that case we
3367
4358
  * hydrate state from the existing message rather than creating a duplicate.
3368
4359
  */
3369
- ensureAssistantMessage(preferredId) {
4360
+ ensureAssistantMessage(preferredId, fallbackToActive = true) {
3370
4361
  if (preferredId) {
3371
4362
  const state = this.getMessageState(preferredId);
3372
4363
  if (state) {
@@ -3377,7 +4368,7 @@ var StreamProcessor = class StreamProcessor {
3377
4368
  };
3378
4369
  }
3379
4370
  }
3380
- const activeId = this.getActiveAssistantMessageId();
4371
+ const activeId = fallbackToActive ? this.getActiveAssistantMessageId() : null;
3381
4372
  if (activeId) {
3382
4373
  const state = this.getMessageState(activeId);
3383
4374
  if (state) {
@@ -3390,7 +4381,8 @@ var StreamProcessor = class StreamProcessor {
3390
4381
  }
3391
4382
  if (preferredId) {
3392
4383
  const existingMsg = this.messages.find((m) => m.id === preferredId);
3393
- if (existingMsg) {
4384
+ if (existingMsg?.role === "activity") preferredId = void 0;
4385
+ else if (existingMsg) {
3394
4386
  const state = this.createMessageState(preferredId, existingMsg.role);
3395
4387
  this.activeMessageIds.add(preferredId);
3396
4388
  const lastPart = existingMsg.parts.length > 0 ? existingMsg.parts[existingMsg.parts.length - 1] : null;
@@ -3415,7 +4407,7 @@ var StreamProcessor = class StreamProcessor {
3415
4407
  this.messages = [...this.messages, assistantMessage];
3416
4408
  const state = this.createMessageState(id, "assistant");
3417
4409
  this.activeMessageIds.add(id);
3418
- this.pendingManualMessageId = id;
4410
+ if (!preferredId) this.pendingManualMessageId = id;
3419
4411
  this.events.onStreamStart?.();
3420
4412
  this.emitMessagesChange();
3421
4413
  return {
@@ -3585,7 +4577,9 @@ var StreamProcessor = class StreamProcessor {
3585
4577
  /**
3586
4578
  * Send a child's chunk to that child's processor, so the card keeps text,
3587
4579
  * reasoning, tool calls, results, and nested children. A tool event without
3588
- * `subagentRunId` follows its `TOOL_CALL_START`.
4580
+ * `subagentRunId` follows its `TOOL_CALL_START` or `TOOL_CALL_CHUNK`. An
4581
+ * untagged chunk with no id follows a child's open chunk stream (see
4582
+ * childContinuing()).
3589
4583
  */
3590
4584
  routeToChild(chunk) {
3591
4585
  let id;
@@ -3595,6 +4589,7 @@ var StreamProcessor = class StreamProcessor {
3595
4589
  id = chunk.subagentRunId;
3596
4590
  } else if ("subagentRunId" in chunk && chunk.subagentRunId) id = chunk.subagentRunId;
3597
4591
  else if ("toolCallId" in chunk && typeof chunk.toolCallId === "string") id = this.childToolCalls.get(chunk.toolCallId);
4592
+ else id = this.childContinuing(chunk);
3598
4593
  if (id === void 0) return false;
3599
4594
  const owner = this.childOwning(id);
3600
4595
  if (owner === void 0) {
@@ -3603,34 +4598,45 @@ var StreamProcessor = class StreamProcessor {
3603
4598
  return true;
3604
4599
  }
3605
4600
  if (this.findSubagentPart(owner)?.part.subagent.status === "error") return true;
3606
- if (chunk.type === "TOOL_CALL_START") this.childToolCalls.set(chunk.toolCallId, owner);
4601
+ if ((chunk.type === "TOOL_CALL_START" || chunk.type === "TOOL_CALL_CHUNK") && chunk.toolCallId !== void 0) this.childToolCalls.set(chunk.toolCallId, owner);
3607
4602
  this.updateChild(owner, (child) => child.processChunk(chunk));
3608
4603
  return true;
3609
4604
  }
4605
+ renameMessage(fromId, toId) {
4606
+ this.messages = this.messages.map((msg) => msg.id === fromId ? {
4607
+ ...msg,
4608
+ id: toId
4609
+ } : msg);
4610
+ const existingState = this.messageStates.get(fromId);
4611
+ if (existingState) {
4612
+ existingState.id = toId;
4613
+ this.messageStates.delete(fromId);
4614
+ this.messageStates.set(toId, existingState);
4615
+ }
4616
+ this.activeMessageIds.delete(fromId);
4617
+ this.activeMessageIds.add(toId);
4618
+ for (const [toolCallId, mappedMessageId] of this.toolCallToMessage) if (mappedMessageId === fromId) this.toolCallToMessage.set(toolCallId, toId);
4619
+ if (this.structuredMessageIds.delete(fromId)) this.structuredMessageIds.add(toId);
4620
+ const batch = this.structuredOutputUpdateBatches.get(fromId);
4621
+ if (batch) {
4622
+ this.structuredOutputUpdateBatches.delete(fromId);
4623
+ this.structuredOutputUpdateBatches.set(toId, batch);
4624
+ }
4625
+ }
3610
4626
  /**
3611
4627
  * Handle TEXT_MESSAGE_START event
3612
4628
  */
3613
4629
  handleTextMessageStartEvent(chunk) {
3614
4630
  const { messageId, role } = chunk;
4631
+ if (this.messages.some((m) => m.id === messageId && m.role === "activity")) {
4632
+ console.warn(`TEXT_MESSAGE_START: Dropped text for '${messageId}', the id of an activity message`);
4633
+ return;
4634
+ }
3615
4635
  const uiRole = role === "user" || role === "system" ? role : "assistant";
3616
4636
  if (this.pendingManualMessageId) {
3617
4637
  const pendingId = this.pendingManualMessageId;
3618
4638
  this.pendingManualMessageId = null;
3619
- if (pendingId !== messageId) {
3620
- this.messages = this.messages.map((msg) => msg.id === pendingId ? {
3621
- ...msg,
3622
- id: messageId
3623
- } : msg);
3624
- const existingState = this.messageStates.get(pendingId);
3625
- if (existingState) {
3626
- existingState.id = messageId;
3627
- this.messageStates.delete(pendingId);
3628
- this.messageStates.set(messageId, existingState);
3629
- }
3630
- this.activeMessageIds.delete(pendingId);
3631
- this.activeMessageIds.add(messageId);
3632
- for (const [toolCallId, mappedMessageId] of this.toolCallToMessage) if (mappedMessageId === pendingId) this.toolCallToMessage.set(toolCallId, messageId);
3633
- }
4639
+ if (pendingId !== messageId) this.renameMessage(pendingId, messageId);
3634
4640
  let pendingState = this.messageStates.get(messageId);
3635
4641
  if (!pendingState) {
3636
4642
  pendingState = this.createMessageState(messageId, uiRole);
@@ -3641,6 +4647,7 @@ var StreamProcessor = class StreamProcessor {
3641
4647
  pendingState.lastEmittedText = "";
3642
4648
  pendingState.hasToolCallsSinceTextStart = false;
3643
4649
  }
4650
+ this.applySenderName(messageId, chunk.name);
3644
4651
  this.mergeMessageMetadata(messageId, chunk.metadata);
3645
4652
  this.emitMessagesChange();
3646
4653
  return;
@@ -3655,6 +4662,7 @@ var StreamProcessor = class StreamProcessor {
3655
4662
  existingState.lastEmittedText = "";
3656
4663
  existingState.hasToolCallsSinceTextStart = false;
3657
4664
  }
4665
+ this.applySenderName(messageId, chunk.name);
3658
4666
  this.mergeMessageMetadata(messageId, chunk.metadata);
3659
4667
  return;
3660
4668
  }
@@ -3667,10 +4675,18 @@ var StreamProcessor = class StreamProcessor {
3667
4675
  this.messages = [...this.messages, newMessage];
3668
4676
  this.createMessageState(messageId, uiRole);
3669
4677
  this.activeMessageIds.add(messageId);
4678
+ this.applySenderName(messageId, chunk.name);
3670
4679
  this.mergeMessageMetadata(messageId, chunk.metadata);
3671
4680
  this.events.onStreamStart?.();
3672
4681
  this.emitMessagesChange();
3673
4682
  }
4683
+ applySenderName(messageId, name) {
4684
+ if (name === void 0) return;
4685
+ this.messages = this.messages.map((msg) => msg.id === messageId ? {
4686
+ ...msg,
4687
+ name
4688
+ } : msg);
4689
+ }
3674
4690
  /**
3675
4691
  * Handle TEXT_MESSAGE_END event
3676
4692
  */
@@ -3700,10 +4716,31 @@ var StreamProcessor = class StreamProcessor {
3700
4716
  metadata: prev.metadata
3701
4717
  };
3702
4718
  });
3703
- this.messages = this.attachSnapshotSubagents(reconciled, top, groups, prevMessages);
4719
+ this.messages = this.mergeOmittedActivity(prevMessages, this.attachSnapshotSubagents(reconciled, top, groups, prevMessages));
3704
4720
  this.emitMessagesChange();
3705
4721
  }
3706
4722
  /**
4723
+ * Snapshot is authoritative for user/assistant/system. Activity omitted
4724
+ * from the snapshot (TanStack chat() still builds snapshots from
4725
+ * ModelMessage[]) stays in the transcript so persist/reconnect cannot
4726
+ * wipe it. Snapshot activity rows win when the id is present.
4727
+ *
4728
+ * Keep every snapshot row, including two assistants that share an id
4729
+ * (agent-loop retry reuses `currentMessageId`). A Map keyed by id would
4730
+ * drop the earlier error tool-call (#1192).
4731
+ */
4732
+ mergeOmittedActivity(prevMessages, snapshot) {
4733
+ const snapshotIds = new Set(snapshot.map((msg) => msg.id));
4734
+ const omitted = prevMessages.filter((msg) => msg.role === "activity" && !snapshotIds.has(msg.id));
4735
+ if (omitted.length === 0) return snapshot;
4736
+ const out = [...snapshot];
4737
+ for (const activity of omitted) {
4738
+ const prevIndex = prevMessages.findIndex((msg) => msg.id === activity.id);
4739
+ out.splice(Math.min(Math.max(prevIndex, 0), out.length), 0, activity);
4740
+ }
4741
+ return out;
4742
+ }
4743
+ /**
3707
4744
  * Put subagent cards back on a snapshot. Child wire messages (tagged with
3708
4745
  * `subagentRunId`) become a card on the nearest assistant message before
3709
4746
  * them, or a new assistant message when there is none. A card that the
@@ -3923,6 +4960,10 @@ var StreamProcessor = class StreamProcessor {
3923
4960
  * @see docs/chat-architecture.md#uimessage-part-ordering-invariants — Replace vs. push logic
3924
4961
  */
3925
4962
  handleTextMessageContentEvent(chunk) {
4963
+ if (this.messages.some((m) => m.id === chunk.messageId && m.role === "activity")) {
4964
+ console.warn(`TEXT_MESSAGE_CONTENT: Dropped text for '${chunk.messageId}', the id of an activity message`);
4965
+ return;
4966
+ }
3926
4967
  const { messageId, state } = this.ensureAssistantMessage(chunk.messageId);
3927
4968
  this.mergeMessageMetadata(messageId, chunk.metadata);
3928
4969
  if (this.structuredMessageIds.has(messageId)) {
@@ -3966,8 +5007,25 @@ var StreamProcessor = class StreamProcessor {
3966
5007
  * @see docs/chat-architecture.md#adapter-contract — Ordering requirements
3967
5008
  */
3968
5009
  handleToolCallStartEvent(chunk) {
5010
+ const pendingId = this.pendingManualMessageId;
5011
+ const parentId = chunk.parentMessageId;
5012
+ if (pendingId && parentId && parentId !== pendingId) {
5013
+ const parent = this.messages.find((m) => m.id === parentId);
5014
+ const placeholder = this.messages.find((m) => m.id === pendingId);
5015
+ if (!parent) {
5016
+ this.pendingManualMessageId = null;
5017
+ this.renameMessage(pendingId, parentId);
5018
+ } else if (parent.role === "assistant" && placeholder) {
5019
+ this.pendingManualMessageId = null;
5020
+ this.messages = this.messages.filter((m) => m.id !== pendingId).map((m) => m.id === parentId ? {
5021
+ ...m,
5022
+ parts: [...m.parts, ...placeholder.parts]
5023
+ } : m);
5024
+ this.renameMessage(pendingId, parentId);
5025
+ }
5026
+ }
3969
5027
  const targetMessageId = chunk.parentMessageId ?? this.getActiveAssistantMessageId();
3970
- const { messageId, state } = this.ensureAssistantMessage(targetMessageId ?? void 0);
5028
+ const { messageId, state } = this.ensureAssistantMessage(targetMessageId ?? void 0, chunk.parentMessageId === void 0);
3971
5029
  state.hasToolCallsSinceTextStart = true;
3972
5030
  const toolCallId = chunk.toolCallId;
3973
5031
  if (!state.toolCalls.get(toolCallId)) {
@@ -3985,6 +5043,7 @@ var StreamProcessor = class StreamProcessor {
3985
5043
  };
3986
5044
  state.toolCalls.set(toolCallId, newToolCall);
3987
5045
  state.toolCallOrder.push(toolCallId);
5046
+ this.runToolCallIds.push(toolCallId);
3988
5047
  this.toolCallToMessage.set(toolCallId, messageId);
3989
5048
  this.messages = updateToolCallPart(this.messages, messageId, {
3990
5049
  id: chunk.toolCallId,
@@ -4018,6 +5077,7 @@ var StreamProcessor = class StreamProcessor {
4018
5077
  const existingToolCall = state.toolCalls.get(toolCallId);
4019
5078
  if (!existingToolCall) return;
4020
5079
  const wasAwaitingInput = existingToolCall.state === "awaiting-input";
5080
+ if (chunk.metadata !== void 0) existingToolCall.metadata = mergeMetadata(existingToolCall.metadata, chunk.metadata);
4021
5081
  existingToolCall.arguments += chunk.delta || "";
4022
5082
  if (wasAwaitingInput && chunk.delta) existingToolCall.state = "input-streaming";
4023
5083
  existingToolCall.parsedArguments = this.jsonParser.parse(existingToolCall.arguments);
@@ -4025,7 +5085,8 @@ var StreamProcessor = class StreamProcessor {
4025
5085
  id: existingToolCall.id,
4026
5086
  name: existingToolCall.name,
4027
5087
  arguments: existingToolCall.arguments,
4028
- state: existingToolCall.state
5088
+ state: existingToolCall.state,
5089
+ ...existingToolCall.metadata !== void 0 && { metadata: existingToolCall.metadata }
4029
5090
  });
4030
5091
  this.emitMessagesChange();
4031
5092
  this.events.onToolCallStateChange?.(messageId, existingToolCall.id, existingToolCall.state, existingToolCall.arguments);
@@ -4102,6 +5163,10 @@ var StreamProcessor = class StreamProcessor {
4102
5163
  * runs are still active before finalizing.
4103
5164
  */
4104
5165
  handleRunStartedEvent(chunk) {
5166
+ if (this.activeRuns.size === 0) {
5167
+ this.runToolCallIds = [];
5168
+ this.toolCallsSentToClient.clear();
5169
+ }
4105
5170
  this.activeRuns.add(chunk.runId);
4106
5171
  }
4107
5172
  /**
@@ -4122,11 +5187,39 @@ var StreamProcessor = class StreamProcessor {
4122
5187
  if (this.activeRuns.size === 0) {
4123
5188
  this.completeAllToolCalls();
4124
5189
  if (this.finishReason === "tool_calls" && chunk.outcome?.type !== "interrupt") return;
5190
+ if (!chunk.outcome || chunk.outcome.type === "success") this.handlePendingToolCalls(chunk.outcome?.pendingToolCallIds);
4125
5191
  this.isDone = true;
4126
5192
  this.finalizeStream();
4127
5193
  }
4128
5194
  }
4129
5195
  /**
5196
+ * AG-UI ends a run that calls a frontend tool with a success outcome and
5197
+ * leaves the call unanswered. The pending calls are the ones named in
5198
+ * `pendingToolCallIds` that this run started, or else every call this run
5199
+ * started that has no result. Fire onToolCall once for each, so the client
5200
+ * runs it and continues.
5201
+ */
5202
+ handlePendingToolCalls(pendingToolCallIds) {
5203
+ const ids = pendingToolCallIds?.length ? pendingToolCallIds.filter((id) => this.runToolCallIds.includes(id)) : this.runToolCallIds;
5204
+ const parts = this.messages.flatMap((msg) => msg.parts ?? []);
5205
+ for (const toolCallId of ids) {
5206
+ if (this.toolCallsSentToClient.has(toolCallId)) continue;
5207
+ const part = parts.find((p) => p.type === "tool-call" && p.id === toolCallId);
5208
+ 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;
5209
+ const input = part.input ?? parseToolArguments(part.arguments);
5210
+ if (input === void 0) {
5211
+ console.warn(`[StreamProcessor] Did not run tool call ${toolCallId}: the arguments of ${part.name} are not complete JSON`);
5212
+ continue;
5213
+ }
5214
+ this.toolCallsSentToClient.add(toolCallId);
5215
+ this.events.onToolCall?.({
5216
+ toolCallId,
5217
+ toolName: part.name,
5218
+ input
5219
+ });
5220
+ }
5221
+ }
5222
+ /**
4130
5223
  * Apply interrupt state to tool-call parts, then fire the client events.
4131
5224
  * A child's interrupt updates the child's card. `emit` is false there, so
4132
5225
  * the events fire once, from the top processor.
@@ -4168,6 +5261,7 @@ var StreamProcessor = class StreamProcessor {
4168
5261
  }
4169
5262
  if (kind === "client_tool" || interrupt.reason === "client_tool_input") {
4170
5263
  if (hasGeneric || !emit) continue;
5264
+ this.toolCallsSentToClient.add(toolCallId);
4171
5265
  this.events.onToolCall?.({
4172
5266
  toolCallId,
4173
5267
  toolName,
@@ -4228,6 +5322,24 @@ var StreamProcessor = class StreamProcessor {
4228
5322
  this.pendingThinkingStepId = stepId;
4229
5323
  }
4230
5324
  /**
5325
+ * Handle ACTIVITY_SNAPSHOT. Creates or replaces a frontend-only activity
5326
+ * message. Does not create MessageStreamState (that path feeds
5327
+ * ProcessorResult.content).
5328
+ */
5329
+ handleActivitySnapshotEvent(chunk) {
5330
+ this.messages = applyActivitySnapshotToUIMessages(this.messages, chunk);
5331
+ this.emitMessagesChange();
5332
+ }
5333
+ /**
5334
+ * Handle ACTIVITY_DELTA. Applies RFC 6902 patches to an existing activity
5335
+ * `content`. Missing or non-activity ids are no-ops. Patch failure leaves
5336
+ * the previous content in place.
5337
+ */
5338
+ handleActivityDeltaEvent(chunk) {
5339
+ this.messages = applyActivityDeltaToUIMessages(this.messages, chunk);
5340
+ this.emitMessagesChange();
5341
+ }
5342
+ /**
4231
5343
  * Handle STEP_FINISHED event.
4232
5344
  *
4233
5345
  * Thinking *content* comes from REASONING_MESSAGE_CONTENT, not STEP_FINISHED.
@@ -4256,6 +5368,7 @@ var StreamProcessor = class StreamProcessor {
4256
5368
  */
4257
5369
  handleReasoningMessageContentEvent(chunk) {
4258
5370
  const { messageId, state } = this.ensureAssistantMessage(this.getActiveAssistantMessageId() ?? void 0);
5371
+ this.mergeMessageMetadata(messageId, chunk.metadata);
4259
5372
  state.hasSeenReasoningEvents = true;
4260
5373
  const delta = chunk.delta || "";
4261
5374
  this.consumePendingThinkingStep(state);
@@ -4368,6 +5481,7 @@ var StreamProcessor = class StreamProcessor {
4368
5481
  }
4369
5482
  if (chunk.name === "tool-input-available" && chunk.value) {
4370
5483
  const { toolCallId, toolName, input } = chunk.value;
5484
+ this.toolCallsSentToClient.add(toolCallId);
4371
5485
  this.events.onToolCall?.({
4372
5486
  toolCallId,
4373
5487
  toolName,
@@ -4546,6 +5660,8 @@ var StreamProcessor = class StreamProcessor {
4546
5660
  */
4547
5661
  finalizeStream() {
4548
5662
  this.isDone = true;
5663
+ for (const event of this.closeChunk()) this.dispatchChunk(event);
5664
+ this.closeChildChunkLanes();
4549
5665
  let lastAssistantMessage;
4550
5666
  for (const messageId of this.activeMessageIds) {
4551
5667
  const state = this.getMessageState(messageId);
@@ -4663,6 +5779,7 @@ var StreamProcessor = class StreamProcessor {
4663
5779
  this.structuredOutputUpdateBatches.clear();
4664
5780
  this.pendingManualMessageId = null;
4665
5781
  this.pendingThinkingStepId = null;
5782
+ this.openChunk = null;
4666
5783
  this.finishReason = null;
4667
5784
  this.hasError = false;
4668
5785
  this.isDone = false;
@@ -4702,14 +5819,14 @@ function createReplayStream(recording) {
4702
5819
  } };
4703
5820
  }
4704
5821
  //#endregion
4705
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/byok/providers.js
5822
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/byok/providers.js
4706
5823
  /** `[a-z][a-z0-9-]{0,63}` — lowercase, no underscores, max 64 chars. */
4707
5824
  var BYOK_PROVIDER_ID_PATTERN = /^[a-z][a-z0-9-]{0,63}$/;
4708
5825
  function isProviderId(value) {
4709
5826
  return typeof value === "string" && BYOK_PROVIDER_ID_PATTERN.test(value);
4710
5827
  }
4711
5828
  //#endregion
4712
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/byok/missing.js
5829
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/byok/missing.js
4713
5830
  function isByokMissingBody(value) {
4714
5831
  if (typeof value !== "object" || value === null) return false;
4715
5832
  if (!("error" in value)) return false;
@@ -4722,7 +5839,7 @@ function isByokMissingBody(value) {
4722
5839
  return true;
4723
5840
  }
4724
5841
  //#endregion
4725
- //#region node_modules/.deno/@tanstack+ai@0.64.0/node_modules/@tanstack/ai/dist/esm/byok/errors.js
5842
+ //#region ../node_modules/.bun/@tanstack+ai@0.68.0+367daa2260c029d6/node_modules/@tanstack/ai/dist/esm/byok/errors.js
4726
5843
  var ByokMissingError = class extends Error {
4727
5844
  provider;
4728
5845
  constructor(provider) {
@@ -4748,7 +5865,7 @@ var ByokUnresolvedProviderError = class extends Error {
4748
5865
  }
4749
5866
  };
4750
5867
  //#endregion
4751
- //#region node_modules/.deno/@tanstack+ai-client@0.36.1/node_modules/@tanstack/ai-client/dist/esm/connection-adapters.js
5868
+ //#region ../node_modules/.bun/@tanstack+ai-client@0.39.2+367daa2260c029d6/node_modules/@tanstack/ai-client/dist/esm/connection-adapters.js
4752
5869
  /**
4753
5870
  * Associates connect-wrapped chunks with the run they were produced under.
4754
5871
  * Content events (TEXT_MESSAGE_CONTENT, TOOL_CALL_*, …) carry no `runId` of
@@ -4941,6 +6058,9 @@ async function* readStreamLines(reader, abortSignal) {
4941
6058
  buffer += decoder.decode();
4942
6059
  if (buffer.trim() && !abortSignal?.aborted) throw new StreamTruncatedError();
4943
6060
  } finally {
6061
+ try {
6062
+ reader.cancel().catch(() => {});
6063
+ } catch {}
4944
6064
  reader.releaseLock();
4945
6065
  }
4946
6066
  }
@@ -5443,7 +6563,7 @@ async function* abortableIterable(iterable, signal) {
5443
6563
  }
5444
6564
  }
5445
6565
  //#endregion
5446
- //#region node_modules/.deno/@tanstack+ai-client@0.36.1/node_modules/@tanstack/ai-client/dist/esm/interrupt-manager.js
6566
+ //#region ../node_modules/.bun/@tanstack+ai-client@0.39.2+367daa2260c029d6/node_modules/@tanstack/ai-client/dist/esm/interrupt-manager.js
5447
6567
  function isClientOwnedInterrupt(item) {
5448
6568
  return item.resumable;
5449
6569
  }
@@ -6385,7 +7505,7 @@ var InterruptManager = class {
6385
7505
  }
6386
7506
  };
6387
7507
  //#endregion
6388
- //#region node_modules/.deno/@tanstack+ai-client@0.36.1/node_modules/@tanstack/ai-client/dist/esm/byok/client.js
7508
+ //#region ../node_modules/.bun/@tanstack+ai-client@0.39.2+367daa2260c029d6/node_modules/@tanstack/ai-client/dist/esm/byok/client.js
6389
7509
  var registeredProviderIds = /* @__PURE__ */ new WeakMap();
6390
7510
  /**
6391
7511
  * Provider to stamp when the caller did not pass a slug.
@@ -6398,7 +7518,7 @@ function byokFallbackProviderId(byok) {
6398
7518
  if (registered.length === 1) return registered[0];
6399
7519
  }
6400
7520
  //#endregion
6401
- //#region node_modules/.deno/@tanstack+ai-client@0.36.1/node_modules/@tanstack/ai-client/dist/esm/byok/resolve.js
7521
+ //#region ../node_modules/.bun/@tanstack+ai-client@0.39.2+367daa2260c029d6/node_modules/@tanstack/ai-client/dist/esm/byok/resolve.js
6402
7522
  function resolveByokProviderId(byokProvider, ...candidates) {
6403
7523
  const fromFn = byokProvider?.();
6404
7524
  if (isProviderId(fromFn)) return fromFn;
@@ -6414,7 +7534,7 @@ async function prepareResolvedByokHeaders(byok, provider) {
6414
7534
  return byok.headers(provider);
6415
7535
  }
6416
7536
  //#endregion
6417
- //#region node_modules/.deno/@tanstack+ai-client@0.36.1/node_modules/@tanstack/ai-client/dist/esm/events.js
7537
+ //#region ../node_modules/.bun/@tanstack+ai-client@0.39.2+367daa2260c029d6/node_modules/@tanstack/ai-client/dist/esm/events.js
6418
7538
  /**
6419
7539
  * Abstract base class for ChatClient event emission
6420
7540
  */
@@ -6588,7 +7708,7 @@ var ChatClientEventEmitter = class {
6588
7708
  }
6589
7709
  };
6590
7710
  //#endregion
6591
- //#region node_modules/.deno/@tanstack+ai-client@0.36.1/node_modules/@tanstack/ai-client/dist/esm/devtools-noop.js
7711
+ //#region ../node_modules/.bun/@tanstack+ai-client@0.39.2+367daa2260c029d6/node_modules/@tanstack/ai-client/dist/esm/devtools-noop.js
6592
7712
  var NoOpChatClientEventEmitter = class extends ChatClientEventEmitter {
6593
7713
  emitEvent() {}
6594
7714
  };
@@ -6633,7 +7753,7 @@ var NoOpChatDevtoolsBridge = class {
6633
7753
  };
6634
7754
  var createNoOpChatDevtoolsBridge = (options) => new NoOpChatDevtoolsBridge(options);
6635
7755
  //#endregion
6636
- //#region node_modules/.deno/@tanstack+ai-client@0.36.1/node_modules/@tanstack/ai-client/dist/esm/client-persistor.js
7756
+ //#region ../node_modules/.bun/@tanstack+ai-client@0.39.2+367daa2260c029d6/node_modules/@tanstack/ai-client/dist/esm/client-persistor.js
6637
7757
  /** Normalize a raw `getItem` result (legacy bare array or combined record). */
6638
7758
  function normalizePersistedState(raw) {
6639
7759
  if (Array.isArray(raw)) return { messages: raw };
@@ -6732,12 +7852,13 @@ var ChatPersistor = class {
6732
7852
  }
6733
7853
  /**
6734
7854
  * Apply state from an async `getItem` once it resolves, unless the message
6735
- * list has already changed since hydration began.
7855
+ * list has already changed since hydration began. Returns a promise that
7856
+ * settles (never rejects) when it is done, or `undefined` for sync state.
6736
7857
  */
6737
7858
  hydrateAsync(persistedState) {
6738
7859
  if (!(persistedState instanceof Promise)) return;
6739
7860
  const hydrationGeneration = this.messagesGeneration;
6740
- persistedState.then((state) => {
7861
+ return persistedState.then((state) => {
6741
7862
  if (!state || this.messagesGeneration !== hydrationGeneration) return;
6742
7863
  this.lastResume = state.resume ?? null;
6743
7864
  this.lastMessages = state.messages;
@@ -6893,11 +8014,11 @@ var ChatPersistor = class {
6893
8014
  isRunlessChunkFromIgnoredRun(chunk) {
6894
8015
  if (getChunkRunId$1(chunk) || !this.currentRunlessRunId) return false;
6895
8016
  if (!this.ignoredActiveRunIds.has(this.currentRunlessRunId) && !this.clearedRunIds.has(this.currentRunlessRunId)) return false;
6896
- 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";
8017
+ 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";
6897
8018
  }
6898
8019
  };
6899
8020
  //#endregion
6900
- //#region node_modules/.deno/@tanstack+ai-client@0.36.1/node_modules/@tanstack/ai-client/dist/esm/cleared-stream-tracker.js
8021
+ //#region ../node_modules/.bun/@tanstack+ai-client@0.39.2+367daa2260c029d6/node_modules/@tanstack/ai-client/dist/esm/cleared-stream-tracker.js
6901
8022
  function getChunkToolCallId(chunk) {
6902
8023
  return "toolCallId" in chunk && typeof chunk.toolCallId === "string" ? chunk.toolCallId : void 0;
6903
8024
  }
@@ -6986,11 +8107,11 @@ var ClearedStreamTracker = class {
6986
8107
  isRunlessChunkFromIgnoredRun(chunk) {
6987
8108
  if (getChunkRunId$1(chunk) || !this.currentRunlessRunId) return false;
6988
8109
  if (!this.ignoredActiveRunIds.has(this.currentRunlessRunId) && !this.clearedRunIds.has(this.currentRunlessRunId)) return false;
6989
- 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";
8110
+ 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";
6990
8111
  }
6991
8112
  };
6992
8113
  //#endregion
6993
- //#region node_modules/.deno/@tanstack+ai-client@0.36.1/node_modules/@tanstack/ai-client/dist/esm/chat-client.js
8114
+ //#region ../node_modules/.bun/@tanstack+ai-client@0.39.2+367daa2260c029d6/node_modules/@tanstack/ai-client/dist/esm/chat-client.js
6994
8115
  var STREAM_PROCESSING_BUDGET_MS = 8;
6995
8116
  function yieldToHost() {
6996
8117
  const { scheduler } = globalThis;
@@ -7126,8 +8247,11 @@ var REJOIN_CONNECT_DEADLINE_MS = 2e3;
7126
8247
  var REJOIN_REBUILD_TRIGGERS = /* @__PURE__ */ new Set([
7127
8248
  "TEXT_MESSAGE_START",
7128
8249
  "TEXT_MESSAGE_CONTENT",
8250
+ "TEXT_MESSAGE_CHUNK",
7129
8251
  "REASONING_MESSAGE_CONTENT",
8252
+ "REASONING_MESSAGE_CHUNK",
7130
8253
  "TOOL_CALL_START",
8254
+ "TOOL_CALL_CHUNK",
7131
8255
  "MESSAGES_SNAPSHOT",
7132
8256
  "SUBAGENT_STARTED"
7133
8257
  ]);
@@ -7231,6 +8355,7 @@ var ChatClient = class {
7231
8355
  currentMessageId = null;
7232
8356
  postStreamActions = [];
7233
8357
  pendingToolExecutions = /* @__PURE__ */ new Map();
8358
+ handingOverPendingToolCalls = false;
7234
8359
  activeClientTools = null;
7235
8360
  activeContext = void 0;
7236
8361
  continuationPending = false;
@@ -7256,6 +8381,12 @@ var ChatClient = class {
7256
8381
  hydrationError;
7257
8382
  /** Whether a view is currently watching. See `attach` / `detach`. */
7258
8383
  tailing = false;
8384
+ /** `historyGeneration` of the mount hydration GET still in flight, if any. */
8385
+ hydrationInFlight;
8386
+ /** An async storage adapter is still reading the persisted transcript. */
8387
+ storeHydrating = false;
8388
+ /** See {@link getIsHydrating}. */
8389
+ isHydrating = false;
7259
8390
  /** Constructor inputs `attach()` needs on every re-attach, not just the first. */
7260
8391
  rejoinRunId;
7261
8392
  cachesMessages;
@@ -7310,6 +8441,7 @@ var ChatClient = class {
7310
8441
  onSubscriptionChange: options.onSubscriptionChange || (() => {}),
7311
8442
  onConnectionStatusChange: options.onConnectionStatusChange || (() => {}),
7312
8443
  onSessionGeneratingChange: options.onSessionGeneratingChange || (() => {}),
8444
+ onHydratingChange: options.onHydratingChange || (() => {}),
7313
8445
  onQueueChange: options.onQueueChange || (() => {}),
7314
8446
  onResumeStateChange: options.onResumeStateChange || (() => {}),
7315
8447
  onRunIdChange: options.onRunIdChange || (() => {}),
@@ -7391,6 +8523,10 @@ var ChatClient = class {
7391
8523
  onToolCall: (args) => {
7392
8524
  const clientTool = (this.activeClientTools ?? this.clientToolsRef.current).get(args.toolName);
7393
8525
  const executeFunc = clientTool?.execute;
8526
+ if (this.handingOverPendingToolCalls && clientTool?.needsApproval === true) {
8527
+ console.warn(`[ChatClient] Did not run tool call ${args.toolCallId}: ${args.toolName} needs approval, and the server did not ask for it`);
8528
+ return;
8529
+ }
7394
8530
  if (executeFunc) {
7395
8531
  const continuationGeneration = this.continuationGeneration;
7396
8532
  const runEventContext = this.devtoolsBridge.getCurrentRunEventContext();
@@ -7437,9 +8573,17 @@ var ChatClient = class {
7437
8573
  }
7438
8574
  });
7439
8575
  this.syncSubagentHandles();
7440
- this.persistor?.hydrateAsync(persistedState);
8576
+ const storeHydration = this.persistor?.hydrateAsync(persistedState);
8577
+ if (storeHydration) {
8578
+ this.storeHydrating = true;
8579
+ storeHydration.finally(() => {
8580
+ this.storeHydrating = false;
8581
+ this.syncIsHydrating();
8582
+ });
8583
+ }
7441
8584
  this.rejoinRunId = rejoinRunId;
7442
8585
  this.cachesMessages = cachesMessages;
8586
+ this.isHydrating = this.storeHydrating || !cachesMessages && !!this.connection.hydrate;
7443
8587
  }
7444
8588
  /**
7445
8589
  * START TAILING: re-attach to an in-flight run so its chunks arrive here.
@@ -7542,21 +8686,30 @@ var ChatClient = class {
7542
8686
  */
7543
8687
  hydrateFromServer() {
7544
8688
  const hydrate = this.connection.hydrate;
7545
- if (!hydrate) return;
7546
- if (this.isLoading || this.abortController) return;
7547
- if (this.disposed) return;
8689
+ if (!hydrate || this.isLoading || this.abortController || this.disposed) {
8690
+ this.syncIsHydrating();
8691
+ return;
8692
+ }
8693
+ if (this.hydrationInFlight === this.historyGeneration) return;
7548
8694
  const pageSize = this.historyPageSize;
7549
8695
  const hydrateOptions = pageSize === void 0 ? void 0 : { limit: pageSize };
7550
8696
  (async () => {
7551
8697
  let result;
7552
8698
  const generation = this.historyGeneration;
8699
+ this.hydrationInFlight = generation;
8700
+ this.syncIsHydrating();
8701
+ const isCurrent = () => this.hydrationInFlight === generation && generation === this.historyGeneration;
8702
+ let current;
7553
8703
  try {
7554
8704
  result = await hydrate(this.threadId, hydrateOptions);
7555
8705
  } catch (cause) {
7556
- if (generation === this.historyGeneration) this.failHydration(cause);
8706
+ if (isCurrent()) this.failHydration(cause);
7557
8707
  return;
8708
+ } finally {
8709
+ current = isCurrent();
8710
+ if (this.hydrationInFlight === generation) this.hydrationInFlight = void 0;
7558
8711
  }
7559
- if (generation !== this.historyGeneration) return;
8712
+ if (!current) return;
7560
8713
  if (this.disposed || !this.tailing) return;
7561
8714
  if (this.isLoading || this.abortController) return;
7562
8715
  if (this.hydrationError && this.error === this.hydrationError) {
@@ -7578,7 +8731,7 @@ var ChatClient = class {
7578
8731
  pendingInterrupts: result.interrupts.pending
7579
8732
  });
7580
8733
  else if (result.activeRun?.runId) this.maybeRejoinInFlight(result.activeRun.runId);
7581
- })();
8734
+ })().finally(() => this.syncIsHydrating());
7582
8735
  }
7583
8736
  /**
7584
8737
  * Surface a mount-hydration failure (`persistence: true`) on the observable
@@ -7847,6 +9000,17 @@ var ChatClient = class {
7847
9000
  this.isLoading = isLoading;
7848
9001
  this.callbacksRef.current.onLoadingChange(isLoading);
7849
9002
  this.events.loadingChanged(isLoading);
9003
+ if (isLoading) this.supersedeHydration();
9004
+ }
9005
+ /**
9006
+ * A send or a clear now owns the transcript. A load that is still pending can
9007
+ * no longer paint it (the generation guards drop its result), so it no longer
9008
+ * counts as hydrating.
9009
+ */
9010
+ supersedeHydration() {
9011
+ this.hydrationInFlight = void 0;
9012
+ this.storeHydrating = false;
9013
+ this.syncIsHydrating();
7850
9014
  }
7851
9015
  setStatus(status) {
7852
9016
  this.status = status;
@@ -7863,6 +9027,12 @@ var ChatClient = class {
7863
9027
  this.callbacksRef.current.onConnectionStatusChange(status);
7864
9028
  this.devtoolsBridge.emitSnapshot();
7865
9029
  }
9030
+ syncIsHydrating() {
9031
+ const isHydrating = this.hydrationInFlight !== void 0 || this.storeHydrating;
9032
+ if (this.isHydrating === isHydrating) return;
9033
+ this.isHydrating = isHydrating;
9034
+ this.callbacksRef.current.onHydratingChange(isHydrating);
9035
+ }
7866
9036
  setSessionGenerating(isGenerating) {
7867
9037
  if (this.sessionGenerating === isGenerating) return;
7868
9038
  this.sessionGenerating = isGenerating;
@@ -8128,7 +9298,12 @@ var ChatClient = class {
8128
9298
  this.resolveJoinedRun(chunk);
8129
9299
  return;
8130
9300
  }
8131
- this.processor.processChunk(chunk);
9301
+ this.handingOverPendingToolCalls = chunk.type === "RUN_FINISHED" && chunk.outcome?.type !== "interrupt";
9302
+ try {
9303
+ this.processor.processChunk(chunk);
9304
+ } finally {
9305
+ this.handingOverPendingToolCalls = false;
9306
+ }
8132
9307
  this.syncSubagentHandles();
8133
9308
  this.updateRunLifecycle(chunk);
8134
9309
  this.observeInterruptState(chunk);
@@ -8351,6 +9526,14 @@ var ChatClient = class {
8351
9526
  if (this.hasPendingInterrupts()) throw new Error("ChatClient: cannot append normal input while pending interrupts exist. Use resumeInterrupts() instead.");
8352
9527
  const normalizedMessage = normalizeToUIMessage(message, generateMessageId);
8353
9528
  if (normalizedMessage.role === "system") return;
9529
+ if (normalizedMessage.role === "activity") {
9530
+ const uiMessage = normalizedMessage;
9531
+ this.events.messageAppended(uiMessage);
9532
+ const messages = this.processor.getMessages();
9533
+ this.processor.setMessages([...messages, uiMessage]);
9534
+ this.devtoolsBridge.emitSnapshot();
9535
+ return;
9536
+ }
8354
9537
  const uiMessage = normalizedMessage;
8355
9538
  this.events.messageAppended(uiMessage);
8356
9539
  const messages = this.processor.getMessages();
@@ -8567,6 +9750,7 @@ var ChatClient = class {
8567
9750
  this.persistor?.beginClear();
8568
9751
  this.processor.clearMessages();
8569
9752
  this.resetHistoryPaging();
9753
+ this.supersedeHydration();
8570
9754
  this.discardPendingSends();
8571
9755
  this.persistor?.remove();
8572
9756
  this.stoppedSubagentIds.clear();
@@ -8825,16 +10009,17 @@ var ChatClient = class {
8825
10009
  this.rememberServerMessageIds(this.processor.getMessages());
8826
10010
  }
8827
10011
  messagesForSend(messages) {
8828
- if (this.historyPageSize === void 0) return messages;
10012
+ const forModel = messages.filter((message) => message.role !== "activity");
10013
+ if (this.historyPageSize === void 0) return forModel;
8829
10014
  const unknownMessages = [];
8830
- for (const message of messages) {
10015
+ for (const message of forModel) {
8831
10016
  if (this.knownServerMessageIds.has(message.id)) continue;
8832
10017
  unknownMessages.push(message);
8833
10018
  }
8834
10019
  if (unknownMessages.length > 0) return unknownMessages;
8835
- const lastUserIndex = messages.findLastIndex((message) => message.role === "user");
10020
+ const lastUserIndex = forModel.findLastIndex((message) => message.role === "user");
8836
10021
  if (lastUserIndex === -1) return [];
8837
- return messages.slice(lastUserIndex);
10022
+ return forModel.slice(lastUserIndex);
8838
10023
  }
8839
10024
  /**
8840
10025
  * True when an interrupt (or another direct send) claimed the client during
@@ -8956,6 +10141,15 @@ var ChatClient = class {
8956
10141
  return this.sessionGenerating;
8957
10142
  }
8958
10143
  /**
10144
+ * Whether the client is rebuilding the chat from persistence: the server
10145
+ * hydrate (`persistence: true`) or an async storage adapter. Turns false once
10146
+ * the transcript is applied and any in-flight run is re-joined (from then on
10147
+ * `isLoading` covers the stream), or when the load fails.
10148
+ */
10149
+ getIsHydrating() {
10150
+ return this.isHydrating;
10151
+ }
10152
+ /**
8959
10153
  * Get current error
8960
10154
  */
8961
10155
  getError() {
@@ -9006,6 +10200,7 @@ var ChatClient = class {
9006
10200
  if (options.onSubscriptionChange !== void 0) this.callbacksRef.current.onSubscriptionChange = options.onSubscriptionChange;
9007
10201
  if (options.onConnectionStatusChange !== void 0) this.callbacksRef.current.onConnectionStatusChange = options.onConnectionStatusChange;
9008
10202
  if (options.onSessionGeneratingChange !== void 0) this.callbacksRef.current.onSessionGeneratingChange = options.onSessionGeneratingChange;
10203
+ if (options.onHydratingChange !== void 0) this.callbacksRef.current.onHydratingChange = options.onHydratingChange;
9009
10204
  if (options.onQueueChange !== void 0) this.callbacksRef.current.onQueueChange = options.onQueueChange;
9010
10205
  if (options.onResumeStateChange !== void 0) this.callbacksRef.current.onResumeStateChange = options.onResumeStateChange;
9011
10206
  if (options.onRunIdChange !== void 0) this.callbacksRef.current.onRunIdChange = options.onRunIdChange;
@@ -9083,9 +10278,10 @@ function buildAgentTools(widgets, hostTools, renderWidget, debug) {
9083
10278
  ];
9084
10279
  }
9085
10280
  function buildRenderWidgetTool(widgets, render) {
10281
+ const catalog = Object.entries(widgets).map(([name, { description, parameters }]) => `- ${name}: ${description} Props schema: ${JSON.stringify(toJsonSchema(parameters))}`).join("\n");
9086
10282
  return toolDefinition({
9087
10283
  name: RENDER_WIDGET_TOOL,
9088
- description: "Render one of the host application's own UI widgets inline in the conversation. The widget appears in the transcript at the point of the call, so prefer it over describing the same information in text. Available widgets:\n" + Object.entries(widgets).map(([name, { description, parameters }]) => `- ${name}: ${description} Props schema: ${JSON.stringify(toJsonSchema(parameters))}`).join("\n"),
10284
+ description: "Render one of the host application's own UI widgets inline in the conversation. The widget appears in the transcript at the point of the call, so prefer it over describing the same information in text. Available widgets:\n" + catalog,
9089
10285
  inputSchema: {
9090
10286
  type: "object",
9091
10287
  properties: {
@@ -9332,6 +10528,7 @@ async function loadChatAuthToken(options) {
9332
10528
  } catch (cause) {
9333
10529
  signal.throwIfAborted();
9334
10530
  const error = cause instanceof Error ? cause : /* @__PURE__ */ new Error("Authentication failed");
10531
+ 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.";
9335
10532
  session.cached = void 0;
9336
10533
  publishAuthentication(options, {
9337
10534
  status: "error",
@@ -9450,6 +10647,100 @@ function startAuthentication(options) {
9450
10647
  };
9451
10648
  }
9452
10649
  //#endregion
10650
+ //#region src/core/mcp.ts
10651
+ async function manageMcpConnection(operation, options) {
10652
+ switch (operation.action) {
10653
+ case "connect": return personalMcpCreateConnection({ mcp_server_id: operation.mcpServerId }, options);
10654
+ case "headers": {
10655
+ const connection = await personalMcpCreateConnection({ mcp_server_id: operation.mcpServerId }, options);
10656
+ await personalMcpSetHeaders(connection.id, {
10657
+ lock_version: connection.lock_version,
10658
+ headers: operation.headers
10659
+ }, options);
10660
+ return { id: connection.id };
10661
+ }
10662
+ case "disconnect": return personalMcpDisconnectConnection(operation.id, options);
10663
+ case "test": return personalMcpTestConnection(operation.id, options);
10664
+ }
10665
+ }
10666
+ async function authorizeMcpConnection(input, requestOptions) {
10667
+ const popup = window.open("about:blank", "_blank", "popup,width=600,height=720");
10668
+ if (!popup) throw new Error("Allow popups to authorize this connection.");
10669
+ try {
10670
+ const id = input.id ?? (await personalMcpCreateConnection({ mcp_server_id: input.mcpServerId }, await requestOptions())).id;
10671
+ const response = await personalMcpAuthorizeConnection(id, await requestOptions());
10672
+ const attempt = {
10673
+ organizationId: response.attempt.organization_id,
10674
+ tenantId: response.attempt.tenant_id,
10675
+ connectionId: response.attempt.connection_id,
10676
+ id: response.attempt.id
10677
+ };
10678
+ const url = new URL(response.popup_url);
10679
+ url.searchParams.set("origin", window.location.origin);
10680
+ await new Promise((resolve, reject) => {
10681
+ let challenge;
10682
+ let bound = false;
10683
+ let finished = false;
10684
+ let completing = false;
10685
+ const cleanup = () => {
10686
+ finished = true;
10687
+ window.removeEventListener("message", receive);
10688
+ clearInterval(poll);
10689
+ clearTimeout(expiry);
10690
+ };
10691
+ const fail = (error) => {
10692
+ cleanup();
10693
+ reject(error instanceof Error ? error : /* @__PURE__ */ new Error("Authorization failed."));
10694
+ };
10695
+ const complete = async () => {
10696
+ if (completing || finished) return;
10697
+ completing = true;
10698
+ try {
10699
+ if (challenge) {
10700
+ if (!bound) {
10701
+ await personalMcpBindBrowser(id, {
10702
+ attempt_id: attempt.id,
10703
+ challenge
10704
+ }, await requestOptions());
10705
+ bound = true;
10706
+ }
10707
+ if (finished) return;
10708
+ const connected = await personalMcpCompleteAuthorization(id, { attempt_id: attempt.id }, await requestOptions());
10709
+ if (finished) return;
10710
+ if (connected) {
10711
+ cleanup();
10712
+ resolve();
10713
+ return;
10714
+ }
10715
+ }
10716
+ if (popup.closed) fail(/* @__PURE__ */ new Error("Authorization window closed."));
10717
+ } catch (error) {
10718
+ const status = error instanceof Error ? error.status : void 0;
10719
+ if (!(error instanceof TypeError) && status !== 429 && (status ?? 0) < 500) fail(error);
10720
+ } finally {
10721
+ completing = false;
10722
+ }
10723
+ };
10724
+ const receive = (event) => {
10725
+ if (event.source !== popup || event.origin !== url.origin) return;
10726
+ const data = event.data;
10727
+ if (!data?.attempt || data.attempt.id !== attempt.id || data.attempt.organizationId !== attempt.organizationId || data.attempt.tenantId !== attempt.tenantId || data.attempt.connectionId !== attempt.connectionId) return;
10728
+ if (data.type === "mcp-browser-challenge" && !challenge && typeof data.challenge === "string") {
10729
+ challenge = data.challenge;
10730
+ complete();
10731
+ }
10732
+ };
10733
+ const poll = setInterval(() => void complete(), 5e3);
10734
+ const expiry = setTimeout(() => fail(/* @__PURE__ */ new Error("Authorization expired. Try connecting again.")), 6e5);
10735
+ window.addEventListener("message", receive);
10736
+ popup.location.replace(url.href);
10737
+ });
10738
+ return id;
10739
+ } finally {
10740
+ popup.close();
10741
+ }
10742
+ }
10743
+ //#endregion
9453
10744
  //#region src/core/messages.ts
9454
10745
  function isSettledToolCall(part) {
9455
10746
  return part.state === "complete" || part.state === "error" || part.output !== void 0;
@@ -9463,6 +10754,11 @@ function hasPendingToolRun(messages, toolNames) {
9463
10754
  return messages.some((message) => message.parts.some((part) => part.type === "tool-call" && !isSettledToolCall(part) && part.name !== "ask_questionnaire" && toolNames.has(part.name)));
9464
10755
  }
9465
10756
  //#endregion
10757
+ //#region src/core/web.ts
10758
+ function webPartMetadata(part) {
10759
+ return part.metadata ?? {};
10760
+ }
10761
+ //#endregion
9466
10762
  //#region src/core/sandbox.ts
9467
10763
  const SANDBOX_TOOLS = [
9468
10764
  SANDBOX_WRITE_FILE_TOOL,
@@ -9513,19 +10809,19 @@ function sandboxPathLabel(part) {
9513
10809
  if (relative !== void 0 && relative !== ".") return relative;
9514
10810
  return text(part.output, "path") ?? text(part.input, "path");
9515
10811
  }
9516
- /** A `sandbox_publish_artifact` call whose output carries the download ticket. */
10812
+ /** A `sandbox_publish_artifact` call whose output carries a durable file reference. */
9517
10813
  function readSandboxArtifact(part) {
9518
10814
  if (part.name !== "sandbox_publish_artifact") return void 0;
9519
10815
  const path = text(part.output, "path") ?? text(part.input, "path");
9520
- const ticket = text(part.output, "ticket");
10816
+ const fileId = text(part.output, "fileId");
9521
10817
  return {
9522
10818
  toolCallId: part.id,
9523
10819
  path: path ?? "",
9524
10820
  label: sandboxPathLabel(part) ?? path ?? "",
9525
10821
  mimeType: text(part.output, "mimeType"),
9526
10822
  size: count(part.output, "size"),
9527
- ticket,
9528
- published: ticket !== void 0 && sandboxRefusal(part) === void 0
10823
+ fileId,
10824
+ published: fileId !== void 0 && sandboxRefusal(part) === void 0
9529
10825
  };
9530
10826
  }
9531
10827
  /** A `sandbox_run_command` call. `stdout` holds combined output on providers with no stderr. */
@@ -9627,6 +10923,10 @@ function projectThreadMessages(records, pendingInteractions = [], liveToolMessag
9627
10923
  const call = calls.get(savedToolCallId(message.source_assistant_message_id, message.source_tool_part_id, message.response_target_id));
9628
10924
  if (!call) continue;
9629
10925
  call.output = part.output ?? null;
10926
+ if (call.name === "sandbox_publish_artifact") {
10927
+ call.artifactMessageId = message.id;
10928
+ call.artifactPartId = String(part.id);
10929
+ }
9630
10930
  Object.assign(call, { resultOutcome: part.outcome });
9631
10931
  call.state = part.outcome === "succeeded" ? "complete" : "error";
9632
10932
  }
@@ -9634,7 +10934,12 @@ function projectThreadMessages(records, pendingInteractions = [], liveToolMessag
9634
10934
  }
9635
10935
  const parts = message.parts.flatMap((part) => {
9636
10936
  const source = part.source;
9637
- if ((part.type === "image" || part.type === "document") && source && typeof source === "object" && !Array.isArray(source) && "type" in source && source.type === "attachment") return [{
10937
+ if (typeof part.type === "string" && [
10938
+ "image",
10939
+ "document",
10940
+ "audio",
10941
+ "video"
10942
+ ].includes(part.type) && source && typeof source === "object" && !Array.isArray(source) && "type" in source && source.type === "attachment") return [{
9638
10943
  ...part,
9639
10944
  source: {
9640
10945
  ...source,
@@ -9644,12 +10949,14 @@ function projectThreadMessages(records, pendingInteractions = [], liveToolMessag
9644
10949
  savedAttachmentId: part.id
9645
10950
  }];
9646
10951
  if (part.type !== "tool-call") return [part];
10952
+ if (part.executionLocation === "provider") return [part];
9647
10953
  const toolCallId = String(part.toolCallId);
9648
10954
  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);
9649
10955
  return (targets.length ? targets : [void 0]).map((responseTargetId) => {
9650
10956
  const savedId = savedToolCallId(message.id, String(part.id), responseTargetId);
9651
10957
  const call = {
9652
10958
  ...part,
10959
+ savedToolTitle: part.declaration && typeof part.declaration === "object" && !Array.isArray(part.declaration) && "title" in part.declaration && typeof part.declaration.title === "string" ? part.declaration.title : void 0,
9653
10960
  id: liveToolMessageIds.get(toolCallId) === message.id ? toolCallId : savedId,
9654
10961
  upstreamToolCallId: toolCallId,
9655
10962
  applicationPartId: part.id,
@@ -9714,6 +11021,7 @@ function createAstralBeamChat(options, deferStart = false) {
9714
11021
  capabilities: { attachments: true },
9715
11022
  agentTools: [],
9716
11023
  sandboxStatus: void 0,
11024
+ usageLimitReached: void 0,
9717
11025
  sandbox: {
9718
11026
  files: [],
9719
11027
  commands: []
@@ -9764,6 +11072,14 @@ function createAstralBeamChat(options, deferStart = false) {
9764
11072
  } });
9765
11073
  pendingSend.callbacks?.onAccepted?.();
9766
11074
  };
11075
+ const replaceAcceptedMessage = (record) => {
11076
+ const messages = [...client.getMessages()];
11077
+ const index = messages.findLastIndex((message) => message.role === "user");
11078
+ if (index !== -1) {
11079
+ messages[index] = projectThreadMessages([record])[0];
11080
+ client.setMessagesManually(messages);
11081
+ }
11082
+ };
9767
11083
  const liveToolCalls = /* @__PURE__ */ new Set();
9768
11084
  const liveToolMessageIds = /* @__PURE__ */ new Map();
9769
11085
  const historicalToolIds = /* @__PURE__ */ new Map();
@@ -9793,17 +11109,22 @@ function createAstralBeamChat(options, deferStart = false) {
9793
11109
  error: failure,
9794
11110
  status: "error"
9795
11111
  });
9796
- live.streamCallbacks?.onError?.(failure);
11112
+ if (state.auth.status !== "error" || state.auth.error !== failure) live.streamCallbacks?.onError?.(failure);
11113
+ };
11114
+ const clearUnavailableMcpConnection = (id) => {
11115
+ update({ unavailableMcpConnections: state.unavailableMcpConnections?.filter((entry) => entry !== id) ?? [] });
9797
11116
  };
9798
- const requestOptions = async () => {
11117
+ const requestOptions = async (conversation = true) => {
9799
11118
  const generation = selectionGeneration;
11119
+ const authSignal = authentication.session.abortController.signal;
9800
11120
  const token = await getValidChatAuthToken(authentication);
9801
- if (generation !== selectionGeneration) throw new DOMException("Conversation changed", "AbortError");
11121
+ authSignal.throwIfAborted();
11122
+ if (conversation && generation !== selectionGeneration) throw new DOMException("Conversation changed", "AbortError");
9802
11123
  return {
9803
11124
  apiUrl: authentication.apiUrl,
9804
11125
  astralBeamToken: token,
9805
11126
  cache: "no-store",
9806
- signal: AbortSignal.any([requestController.signal, authentication.session.abortController.signal]),
11127
+ signal: conversation ? AbortSignal.any([requestController.signal, authSignal]) : authSignal,
9807
11128
  fetchClient: (input, init) => fetchAuthenticatedChat({
9808
11129
  ...authentication,
9809
11130
  input,
@@ -10007,6 +11328,11 @@ function createAstralBeamChat(options, deferStart = false) {
10007
11328
  headers,
10008
11329
  body: JSON.stringify(payload)
10009
11330
  }).catch((error) => {
11331
+ const limit = isAstralBeamApiError(error) ? error.body?.usage_limit : void 0;
11332
+ if (limit) update({ usageLimitReached: {
11333
+ name: limit.name,
11334
+ resetsAt: limit.resets_at
11335
+ } });
10010
11336
  if (submission && !previouslyAttempted && isAstralBeamApiError(error) && (error.status === 400 || error.status === 413 || error.status === 429)) delete submission.tools;
10011
11337
  throw error;
10012
11338
  });
@@ -10014,11 +11340,23 @@ function createAstralBeamChat(options, deferStart = false) {
10014
11340
  if (response.headers.get("Content-Type")?.includes("application/json")) {
10015
11341
  const receipt = await response.json();
10016
11342
  if (generation !== selectionGeneration) throw new DOMException("Conversation changed", "AbortError");
10017
- update({ thread: {
10018
- ...state.thread,
10019
- version: receipt.thread_version
10020
- } });
10021
- if (submission) acceptPendingSend();
11343
+ update({
11344
+ thread: {
11345
+ ...state.thread,
11346
+ version: receipt.thread_version
11347
+ },
11348
+ ...receipt.usage_limit ? { usageLimitReached: {
11349
+ name: receipt.usage_limit.name,
11350
+ resetsAt: receipt.usage_limit.resets_at
11351
+ } } : {}
11352
+ });
11353
+ if (submission) {
11354
+ const history = await loadThreadMessages(thread.id, auth, void 0, liveToolMessageIds);
11355
+ if (generation !== selectionGeneration) throw new DOMException("Conversation changed", "AbortError");
11356
+ const accepted = history.messages.find((message) => message.id === receipt.accepted_message_id);
11357
+ if (accepted) replaceAcceptedMessage(accepted);
11358
+ acceptPendingSend();
11359
+ }
10022
11360
  return new Response("", { headers: { "Content-Type": "text/event-stream" } });
10023
11361
  }
10024
11362
  return response;
@@ -10143,6 +11481,11 @@ function createAstralBeamChat(options, deferStart = false) {
10143
11481
  onMessagesChange: (messages) => {
10144
11482
  if (client !== next || generation !== selectionGeneration) return;
10145
11483
  restoreCompletedWidgets(messages);
11484
+ for (const message of messages) {
11485
+ if (message.role !== "user") continue;
11486
+ const saved = state.messages.find((previous) => previous.id === message.id);
11487
+ if (saved?.parts.some((part) => "savedAttachmentId" in part)) message.parts = saved.parts;
11488
+ }
10146
11489
  update({
10147
11490
  messages,
10148
11491
  sandbox: collectSandboxActivity(messages),
@@ -10152,7 +11495,8 @@ function createAstralBeamChat(options, deferStart = false) {
10152
11495
  onStatusChange: (status) => {
10153
11496
  if (client === next && generation === selectionGeneration) update({
10154
11497
  status,
10155
- error: next.getError()
11498
+ error: next.getError(),
11499
+ ...status === "submitted" ? { usageLimitReached: void 0 } : {}
10156
11500
  });
10157
11501
  },
10158
11502
  onInterruptStateChange: (interrupts) => {
@@ -10163,6 +11507,7 @@ function createAstralBeamChat(options, deferStart = false) {
10163
11507
  if (eventType === "astralbeam_thread") {
10164
11508
  const event = data;
10165
11509
  if (state.thread?.id === event.threadId) {
11510
+ if (event.acceptedMessage && pendingSend && !pendingSend.accepted) replaceAcceptedMessage(event.acceptedMessage);
10166
11511
  if (event.acceptedMessageId) acceptPendingSend();
10167
11512
  if (event.saved) for (const id of event.executableToolCallIds ?? []) {
10168
11513
  if (!liveToolCalls.has(id)) toolResults.delete(toolResultKey(id));
@@ -10179,6 +11524,24 @@ function createAstralBeamChat(options, deferStart = false) {
10179
11524
  }
10180
11525
  return;
10181
11526
  }
11527
+ if (eventType === "astralbeam_mcp_tools") {
11528
+ const event = data;
11529
+ const titles = {};
11530
+ for (const tool of event.tools ?? []) if (typeof tool.name === "string" && typeof tool.title === "string") titles[tool.name] = tool.title;
11531
+ update({
11532
+ serverToolTitles: titles,
11533
+ unavailableMcpConnections: event.unavailable ?? []
11534
+ });
11535
+ return;
11536
+ }
11537
+ const limit = data;
11538
+ if (eventType === "astralbeam.usage_limit.reached" && typeof limit?.name === "string" && typeof limit.resetsAt === "string") {
11539
+ update({ usageLimitReached: {
11540
+ name: limit.name,
11541
+ resetsAt: limit.resetsAt
11542
+ } });
11543
+ return;
11544
+ }
10182
11545
  const value = data?.state;
10183
11546
  if (eventType === "astralbeam.sandbox.status" && (value === "starting" || value === "ready" || value === "error")) {
10184
11547
  debug?.("sandbox", `sandbox ${value}`);
@@ -10189,6 +11552,10 @@ function createAstralBeamChat(options, deferStart = false) {
10189
11552
  },
10190
11553
  onChunk: (chunk) => {
10191
11554
  if (client !== next) return;
11555
+ if (chunk.type === EventType.RUN_STARTED) update({
11556
+ serverToolTitles: {},
11557
+ unavailableMcpConnections: []
11558
+ });
10192
11559
  live.streamCallbacks?.onChunk?.(chunk);
10193
11560
  },
10194
11561
  onResponse: (response) => {
@@ -10198,7 +11565,7 @@ function createAstralBeamChat(options, deferStart = false) {
10198
11565
  if (client === next) live.streamCallbacks?.onFinish?.(message);
10199
11566
  },
10200
11567
  onError: (error) => {
10201
- if (client === next) live.streamCallbacks?.onError?.(error);
11568
+ if (client === next && (state.auth.status !== "error" || state.auth.error !== error)) live.streamCallbacks?.onError?.(error);
10202
11569
  }
10203
11570
  });
10204
11571
  return next;
@@ -10220,7 +11587,7 @@ function createAstralBeamChat(options, deferStart = false) {
10220
11587
  client.setMessagesManually(state.messages.map((message) => {
10221
11588
  const aliases = /* @__PURE__ */ new Map();
10222
11589
  const parts = message.parts.map((part) => {
10223
- if (part.type !== "tool-call") return part;
11590
+ if (part.type !== "tool-call" || webPartMetadata(part).providerExecuted) return part;
10224
11591
  const stored = part;
10225
11592
  const upstreamToolCallId = stored.upstreamToolCallId ?? part.id;
10226
11593
  if (liveToolMessageIds.get(upstreamToolCallId) === message.id && !isSettledToolCall(part)) return part;
@@ -10268,7 +11635,10 @@ function createAstralBeamChat(options, deferStart = false) {
10268
11635
  commands: []
10269
11636
  },
10270
11637
  sandboxStatus: void 0,
11638
+ usageLimitReached: void 0,
10271
11639
  pendingInteractions: [],
11640
+ serverToolTitles: {},
11641
+ unavailableMcpConnections: [],
10272
11642
  threadLoadFailed: false,
10273
11643
  messagesCursor: void 0,
10274
11644
  olderMessagesLoading: false
@@ -10434,7 +11804,7 @@ function createAstralBeamChat(options, deferStart = false) {
10434
11804
  });
10435
11805
  }
10436
11806
  scopeCompletedToolCalls();
10437
- if (pending && (!("tool" in result) || result.toolCallId === savedToolCallId(pending.sourceMessageId, pending.sourcePartId, pending.responseTargetId))) {
11807
+ if (pending) {
10438
11808
  replaceClient();
10439
11809
  await hydration;
10440
11810
  if (generation !== selectionGeneration) return;
@@ -10528,6 +11898,7 @@ function createAstralBeamChat(options, deferStart = false) {
10528
11898
  };
10529
11899
  const observeAuthentication = () => {
10530
11900
  const auth = authenticationState(authentication);
11901
+ const previous = state.auth;
10531
11902
  if (auth.status === "ready") {
10532
11903
  const nextIdentity = authenticationIdentity(auth.currentUser);
10533
11904
  if (identity !== void 0 && identity !== nextIdentity) {
@@ -10553,6 +11924,7 @@ function createAstralBeamChat(options, deferStart = false) {
10553
11924
  }
10554
11925
  }
10555
11926
  update({ auth });
11927
+ if (auth.status === "error" && (previous.status !== "error" || previous.error !== auth.error)) live.streamCallbacks?.onError?.(auth.error);
10556
11928
  };
10557
11929
  const start = () => {
10558
11930
  if (started) return;
@@ -10646,11 +12018,44 @@ function createAstralBeamChat(options, deferStart = false) {
10646
12018
  deleteThread,
10647
12019
  refreshThread,
10648
12020
  loadOlderMessages,
12021
+ uploadAttachment: async ({ data, filename, mimeType }) => {
12022
+ const agentId = state.thread ? state.thread.agentId : live.agentId;
12023
+ const [encoded, options] = await Promise.all([data, requestOptions(false)]);
12024
+ return uploadChatFile({
12025
+ ...agentId ? { agentId } : {},
12026
+ type: mimeType.startsWith("image/") ? "image" : "document",
12027
+ source: {
12028
+ type: "data",
12029
+ value: encoded,
12030
+ mimeType
12031
+ },
12032
+ metadata: { filename }
12033
+ }, options);
12034
+ },
12035
+ getFile: async (fileId) => {
12036
+ const thread = state.thread;
12037
+ if (!thread) throw new Error("Open a conversation before downloading files.");
12038
+ return (await getChatFile({
12039
+ threadId: thread.id,
12040
+ fileId
12041
+ }, await requestOptions())).blob();
12042
+ },
10649
12043
  getAttachment: async (messageId, partId) => {
10650
12044
  const thread = state.thread;
10651
12045
  if (!thread) throw new Error("Open a conversation before downloading attachments.");
10652
12046
  return (await getChatAttachment(thread.id, messageId, partId, await requestOptions())).blob();
10653
12047
  },
12048
+ getMcpCatalog: async () => personalMcpGetCatalog(await requestOptions(false)),
12049
+ manageMcpConnection: async (operation) => {
12050
+ const result = await manageMcpConnection(operation, await requestOptions(false));
12051
+ if ("id" in operation) clearUnavailableMcpConnection(operation.id);
12052
+ else if (result && "id" in result) clearUnavailableMcpConnection(result.id);
12053
+ return result;
12054
+ },
12055
+ authorizeMcpConnection: async (input) => {
12056
+ const id = await authorizeMcpConnection(input, () => requestOptions(false));
12057
+ clearUnavailableMcpConnection(id);
12058
+ },
10654
12059
  abandonToolCall,
10655
12060
  reset: () => {
10656
12061
  debug?.("status", "conversation reset");