@dudousxd/nestjs-agent-react 0.32.0 → 0.34.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 (44) hide show
  1. package/README.md +7 -0
  2. package/dist/{client-C7eu9WMJ.d.cts → client-BdHUuqy-.d.cts} +36 -1
  3. package/dist/{client-C7eu9WMJ.d.ts → client-BdHUuqy-.d.ts} +36 -1
  4. package/dist/{generative-ui-VTZ1EADD.d.cts → generative-ui-CyHY8Lh1.d.cts} +32 -101
  5. package/dist/{generative-ui-VTZ1EADD.d.ts → generative-ui-DdUZPCXX.d.ts} +32 -101
  6. package/dist/genui-json-render.cjs +51 -8
  7. package/dist/genui-json-render.cjs.map +1 -1
  8. package/dist/genui-json-render.d.cts +2 -1
  9. package/dist/genui-json-render.d.ts +2 -1
  10. package/dist/genui-json-render.js +51 -8
  11. package/dist/genui-json-render.js.map +1 -1
  12. package/dist/genui-server-playwright.cjs +199 -0
  13. package/dist/genui-server-playwright.cjs.map +1 -0
  14. package/dist/genui-server-playwright.d.cts +18 -0
  15. package/dist/genui-server-playwright.d.ts +18 -0
  16. package/dist/genui-server-playwright.js +162 -0
  17. package/dist/genui-server-playwright.js.map +1 -0
  18. package/dist/genui-server.cjs +188 -0
  19. package/dist/genui-server.cjs.map +1 -0
  20. package/dist/genui-server.d.cts +36 -0
  21. package/dist/genui-server.d.ts +36 -0
  22. package/dist/genui-server.js +163 -0
  23. package/dist/genui-server.js.map +1 -0
  24. package/dist/genui.cjs +127 -8
  25. package/dist/genui.cjs.map +1 -1
  26. package/dist/genui.d.cts +5 -2
  27. package/dist/genui.d.ts +5 -2
  28. package/dist/genui.js +128 -8
  29. package/dist/genui.js.map +1 -1
  30. package/dist/index.cjs +559 -123
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +35 -10
  33. package/dist/index.d.ts +35 -10
  34. package/dist/index.js +552 -120
  35. package/dist/index.js.map +1 -1
  36. package/dist/media.cjs.map +1 -1
  37. package/dist/media.d.cts +1 -1
  38. package/dist/media.d.ts +1 -1
  39. package/dist/media.js.map +1 -1
  40. package/dist/react-registry-Di4IVrw-.d.cts +25 -0
  41. package/dist/react-registry-z9GFbTm9.d.ts +25 -0
  42. package/dist/types-DZtFsWec.d.cts +99 -0
  43. package/dist/types-DZtFsWec.d.ts +99 -0
  44. package/package.json +35 -5
package/dist/index.cjs CHANGED
@@ -78,8 +78,10 @@ __export(src_exports, {
78
78
  onThreadsEvent: () => onThreadsEvent,
79
79
  persistSpeechLang: () => persistSpeechLang,
80
80
  phraseFor: () => phraseFor,
81
+ proposalNeedsPolling: () => proposalNeedsPolling,
81
82
  readPath: () => readPath,
82
83
  readReasoningMs: () => readReasoningMs,
84
+ reconcileProposalMessages: () => reconcileProposalMessages,
83
85
  reframeAgUiStream: () => reframeAgUiStream,
84
86
  requireBackendMethod: () => requireBackendMethod,
85
87
  resolveResultView: () => resolveResultView,
@@ -87,9 +89,11 @@ __export(src_exports, {
87
89
  storedThreadToUiMessages: () => storedThreadToUiMessages,
88
90
  toolCallState: () => toolCallState,
89
91
  toolCatalogFrom: () => toolCatalogFrom,
92
+ useActionProposals: () => useActionProposals,
90
93
  useAgentBackend: () => useAgentBackend,
91
94
  useAgentChat: () => useAgentChat,
92
95
  useAgentConfig: () => useAgentConfig,
96
+ useAgentUiCapabilities: () => useAgentUiCapabilities,
93
97
  useAgents: () => useAgents,
94
98
  useAmbientRenderUi: () => useAmbientRenderUi,
95
99
  useApprovalCountdown: () => useApprovalCountdown,
@@ -121,9 +125,9 @@ function readErrorAnswer(text) {
121
125
  }
122
126
  if (body === null || typeof body !== "object")
123
127
  return { body, message: void 0, code: void 0 };
124
- const record = body;
125
- const message = typeof record.message === "string" && record.message !== "" ? record.message : Array.isArray(record.message) && record.message.length > 0 && record.message.every((each) => typeof each === "string") ? record.message.join("; ") : void 0;
126
- const code = typeof record.code === "string" && record.code !== "" ? record.code : void 0;
128
+ const record2 = body;
129
+ const message = typeof record2.message === "string" && record2.message !== "" ? record2.message : Array.isArray(record2.message) && record2.message.length > 0 && record2.message.every((each) => typeof each === "string") ? record2.message.join("; ") : void 0;
130
+ const code = typeof record2.code === "string" && record2.code !== "" ? record2.code : void 0;
127
131
  return { body, message, code };
128
132
  }
129
133
  async function readErrorResponse(response) {
@@ -200,6 +204,12 @@ var AgentClient = class {
200
204
  if (response.status === 202) {
201
205
  return { body: emptyStream(), queued: await response.json() };
202
206
  }
207
+ if (response.ok && response.headers.get("content-type")?.includes("application/json")) {
208
+ const decision = await response.json();
209
+ if (decision.proposalDecision !== void 0 && typeof decision.threadId === "string")
210
+ return { body: emptyStream(), threadId: decision.threadId, proposalDecision: decision };
211
+ throw new Error("Unexpected JSON chat response");
212
+ }
203
213
  if (!response.ok || !response.body) {
204
214
  throw await this.failure(response, "POST", `${this.agentPath()}/chat`);
205
215
  }
@@ -432,6 +442,54 @@ var AgentClient = class {
432
442
  * `remember` approves later calls of the same tool in the same thread; `via` names the surface
433
443
  * the decision came through (the server records `'web'` when omitted).
434
444
  */
445
+ async listActionProposals({ threadId }) {
446
+ const proposals = /* @__PURE__ */ new Map();
447
+ let after;
448
+ for (; ; ) {
449
+ const route = `/threads/${encodeURIComponent(threadId)}/action-proposals${after === void 0 ? "" : `?after=${encodeURIComponent(JSON.stringify(after))}`}`;
450
+ const response = await this.requestResponse("GET", route);
451
+ const page = await this.handleResponse(
452
+ response,
453
+ "GET",
454
+ `${this.agentPath()}${route}`
455
+ );
456
+ if (!Array.isArray(page)) throw new TypeError("Invalid action proposal page");
457
+ for (const proposal of page) proposals.set(proposal.id, proposal);
458
+ const header = response.headers.get("X-Action-Proposals-Next");
459
+ if (header === null) return [...proposals.values()];
460
+ let next;
461
+ try {
462
+ next = JSON.parse(decodeURIComponent(header));
463
+ } catch {
464
+ throw new TypeError("Invalid action proposal cursor");
465
+ }
466
+ if (typeof next !== "object" || next === null || !("createdAt" in next) || typeof next.createdAt !== "number" || !Number.isSafeInteger(next.createdAt) || !("id" in next) || typeof next.id !== "string" || next.id.length === 0 || next.id.length > 255 || after !== void 0 && (next.createdAt < after.createdAt || next.createdAt === after.createdAt && next.id <= after.id))
467
+ throw new TypeError("Invalid or non-advancing action proposal cursor");
468
+ after = { createdAt: next.createdAt, id: next.id };
469
+ }
470
+ }
471
+ approveActionProposal({
472
+ threadId,
473
+ proposalId,
474
+ remember
475
+ }) {
476
+ return this.request(
477
+ "POST",
478
+ `/threads/${encodeURIComponent(threadId)}/action-proposals/${encodeURIComponent(proposalId)}/approve`,
479
+ remember === void 0 ? {} : { remember }
480
+ );
481
+ }
482
+ rejectActionProposal({
483
+ threadId,
484
+ proposalId,
485
+ reason
486
+ }) {
487
+ return this.request(
488
+ "POST",
489
+ `/threads/${encodeURIComponent(threadId)}/action-proposals/${encodeURIComponent(proposalId)}/reject`,
490
+ reason === void 0 ? {} : { reason }
491
+ );
492
+ }
435
493
  approveToolCall(input) {
436
494
  return this.request("POST", "/tool-call/approve", input);
437
495
  }
@@ -488,6 +546,10 @@ var AgentClient = class {
488
546
  return this.options.credentials !== void 0 ? { credentials: this.options.credentials } : {};
489
547
  }
490
548
  async request(method, route, body) {
549
+ const response = await this.requestResponse(method, route, body);
550
+ return this.handleResponse(response, method, `${this.agentPath()}${route}`);
551
+ }
552
+ async requestResponse(method, route, body) {
491
553
  const path = `${this.agentPath()}${route}`;
492
554
  const response = await this.fetchImpl()(`${this.baseUrl()}${path}`, {
493
555
  method,
@@ -499,7 +561,7 @@ var AgentClient = class {
499
561
  ...body !== void 0 ? { body: JSON.stringify(body) } : {},
500
562
  ...this.credentials()
501
563
  });
502
- return this.handleResponse(response, method, path);
564
+ return response;
503
565
  }
504
566
  /** The error for a refused `response`, already reported to `onHttpError`. */
505
567
  async failure(response, method, path) {
@@ -655,6 +717,10 @@ var AgentChatTransport = class {
655
717
  return queuedChunkStream(response.queued);
656
718
  }
657
719
  this.captureHeaderMeta(response);
720
+ if (response.proposalDecision !== void 0) {
721
+ this.attemptLive = false;
722
+ return proposalDecisionChunkStream(response.proposalDecision);
723
+ }
658
724
  return this.toChunkStream(response, {
659
725
  ...headers !== void 0 ? { headers } : {},
660
726
  ...options.abortSignal ? { signal: options.abortSignal } : {}
@@ -781,7 +847,7 @@ var AgentChatTransport = class {
781
847
  let reasoningSeq = 0;
782
848
  const announced = /* @__PURE__ */ new Set();
783
849
  const toolMetadata = /* @__PURE__ */ new Map();
784
- const record = (meta) => {
850
+ const record2 = (meta) => {
785
851
  streamRunId = meta.runId;
786
852
  this.recordMeta(meta);
787
853
  };
@@ -1069,7 +1135,7 @@ var AgentChatTransport = class {
1069
1135
  }
1070
1136
  if (frame.event === "meta") {
1071
1137
  const meta = parseMeta(frame.data);
1072
- if (meta) record(meta);
1138
+ if (meta) record2(meta);
1073
1139
  } else if (frame.data) {
1074
1140
  const event = parseEvent(frame.data);
1075
1141
  if (event) emit(event);
@@ -1137,10 +1203,10 @@ function parseErrorFrame(data) {
1137
1203
  try {
1138
1204
  const parsed = JSON.parse(data);
1139
1205
  if (parsed !== null && typeof parsed === "object") {
1140
- const record = parsed;
1206
+ const record2 = parsed;
1141
1207
  return {
1142
- code: typeof record.code === "string" && record.code !== "" ? record.code : void 0,
1143
- message: typeof record.message === "string" && record.message !== "" ? record.message : fallback2.message
1208
+ code: typeof record2.code === "string" && record2.code !== "" ? record2.code : void 0,
1209
+ message: typeof record2.message === "string" && record2.message !== "" ? record2.message : fallback2.message
1144
1210
  };
1145
1211
  }
1146
1212
  } catch {
@@ -1180,6 +1246,21 @@ function delay(ms, signal) {
1180
1246
  signal?.addEventListener("abort", done, { once: true });
1181
1247
  });
1182
1248
  }
1249
+ function proposalDecisionChunkStream(decision) {
1250
+ return new ReadableStream({
1251
+ start(controller) {
1252
+ controller.enqueue({ type: "start", messageId: `decision:${crypto.randomUUID()}` });
1253
+ controller.enqueue({ type: "data-proposal-decision", data: decision, transient: true });
1254
+ if (decision.text !== void 0 && decision.text.length > 0) {
1255
+ controller.enqueue({ type: "text-start", id: "decision" });
1256
+ controller.enqueue({ type: "text-delta", id: "decision", delta: decision.text });
1257
+ controller.enqueue({ type: "text-end", id: "decision" });
1258
+ }
1259
+ controller.enqueue({ type: "finish", finishReason: "stop" });
1260
+ controller.close();
1261
+ }
1262
+ });
1263
+ }
1183
1264
 
1184
1265
  // src/attachments/files.ts
1185
1266
  function fileKind(mediaType) {
@@ -1312,6 +1393,10 @@ function toGenerativeUIItem(part) {
1312
1393
  return {
1313
1394
  id,
1314
1395
  component: source.component,
1396
+ ...isRecord(source.componentVersions) && Object.values(source.componentVersions).every(
1397
+ (version) => typeof version === "number" && Number.isSafeInteger(version) && version > 0
1398
+ ) ? { componentVersions: { ...source.componentVersions } } : {},
1399
+ ...typeof source.fallbackText === "string" ? { fallbackText: source.fallbackText } : {},
1315
1400
  props: isRecord(source.props) ? source.props : {},
1316
1401
  version: typeof source.version === "number" ? source.version : null,
1317
1402
  toolCallId: typeof source.toolCallId === "string" ? source.toolCallId : null
@@ -1417,20 +1502,29 @@ function useValidatedProps(catalog, name, props) {
1417
1502
  function useGenerativeUIState(part, options, fallbackTree) {
1418
1503
  const item = (0, import_react3.useMemo)(() => toGenerativeUIItem(part), [part]);
1419
1504
  const name = item?.component ?? "";
1505
+ const definition = options.catalog?.get?.(name);
1506
+ const incompatible = item?.fallbackText !== void 0 && item.version !== null && definition !== void 0 && item.version !== (definition.version ?? 1);
1420
1507
  const resolution = useResolvedComponent(
1421
1508
  name,
1422
1509
  item?.version ?? null,
1423
- options.registry,
1510
+ incompatible ? {} : options.registry,
1424
1511
  item === null ? void 0 : options.resolveComponent,
1425
1512
  fallbackTree
1426
1513
  );
1427
1514
  const empty = (0, import_react3.useMemo)(() => ({}), []);
1428
1515
  const validation = useValidatedProps(
1429
- item === null || name === GENUI_TREE_COMPONENT ? void 0 : options.catalog,
1516
+ item === null || name === GENUI_TREE_COMPONENT || incompatible ? void 0 : options.catalog,
1430
1517
  name,
1431
1518
  item?.props ?? empty
1432
1519
  );
1433
1520
  if (item === null) return null;
1521
+ if (name === GENUI_TREE_COMPONENT && item.fallbackText !== void 0 && (!isRecord(item.props.root) || typeof item.props.root.type !== "string"))
1522
+ return {
1523
+ status: "problem",
1524
+ reason: "invalid",
1525
+ item,
1526
+ issues: [{ path: ["root"], message: "Invalid UI tree root" }]
1527
+ };
1434
1528
  if (resolution.status === "loading") return { status: "loading", item };
1435
1529
  if (resolution.status === "unknown") return { status: "problem", reason: "unknown", item };
1436
1530
  if (resolution.status === "error") {
@@ -1448,7 +1542,8 @@ var import_jsx_runtime = require("react/jsx-runtime");
1448
1542
  var TreeScopeContext = (0, import_react4.createContext)(null);
1449
1543
  function renderFallback(fallback2, problem) {
1450
1544
  if (typeof fallback2 === "function") return fallback2(problem);
1451
- return fallback2 ?? null;
1545
+ if (fallback2 !== void 0) return fallback2;
1546
+ return problem.item.fallbackText !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { whiteSpace: "pre-wrap" }, children: problem.item.fallbackText }) : null;
1452
1547
  }
1453
1548
  var ItemBoundary = class extends import_react4.Component {
1454
1549
  state = { error: void 0, failed: false };
@@ -1480,28 +1575,42 @@ function nodeItem(node, id) {
1480
1575
  function TreeNode({ node, id }) {
1481
1576
  const scope = (0, import_react4.useContext)(TreeScopeContext);
1482
1577
  const item = (0, import_react4.useMemo)(() => nodeItem(node, id), [node, id]);
1578
+ const storedVersion = scope?.componentVersions?.[node.type];
1579
+ const definition = scope?.options.catalog?.get?.(node.type);
1580
+ const incompatible = storedVersion !== void 0 && definition !== void 0 && storedVersion !== (definition.version ?? 1);
1483
1581
  const resolution = useResolvedComponent(
1484
1582
  node.type,
1485
- null,
1486
- scope?.options.registry ?? {},
1583
+ storedVersion ?? null,
1584
+ incompatible ? {} : scope?.options.registry ?? {},
1487
1585
  scope?.options.resolveComponent
1488
1586
  );
1489
- const validation = useValidatedProps(scope?.options.catalog, node.type, item.props);
1587
+ const validation = useValidatedProps(
1588
+ incompatible ? void 0 : scope?.options.catalog,
1589
+ node.type,
1590
+ item.props
1591
+ );
1490
1592
  if (scope === null) return null;
1491
1593
  if (resolution.status === "loading" || validation.status === "pending") return scope.loading;
1492
1594
  if (resolution.status === "unknown") {
1595
+ if (scope.fallback === void 0 && scope.fallbackText !== void 0)
1596
+ throw new Error("Unknown tree component");
1493
1597
  return renderFallback(scope.fallback, { reason: "unknown", item });
1494
1598
  }
1495
1599
  if (resolution.status === "error") {
1600
+ if (scope.fallback === void 0 && scope.fallbackText !== void 0) throw resolution.error;
1496
1601
  return renderFallback(scope.fallback, { reason: "error", item, error: resolution.error });
1497
1602
  }
1498
1603
  if (validation.status === "invalid") {
1604
+ if (scope.fallback === void 0 && scope.fallbackText !== void 0)
1605
+ throw new Error("Invalid tree component");
1499
1606
  return renderFallback(scope.fallback, { reason: "invalid", item, issues: validation.issues });
1500
1607
  }
1501
1608
  const Renderer = resolution.Component;
1502
1609
  const children = Array.isArray(node.children) ? node.children : [];
1503
1610
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Renderer, { ...validation.props, children: children.length > 0 ? children.map((child, index) => {
1504
1611
  const childId = `${id}.${index}`;
1612
+ if (scope.fallback === void 0 && scope.fallbackText !== void 0)
1613
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TreeNode, { node: child, id: childId }, childId);
1505
1614
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1506
1615
  ItemBoundary,
1507
1616
  {
@@ -1523,6 +1632,8 @@ function GenerativeUIScope({
1523
1632
  catalog,
1524
1633
  resolveComponent,
1525
1634
  fallback: fallback2,
1635
+ fallbackText,
1636
+ componentVersions,
1526
1637
  loading = null,
1527
1638
  onError,
1528
1639
  children
@@ -1535,10 +1646,21 @@ function GenerativeUIScope({
1535
1646
  ...resolveComponent !== void 0 ? { resolveComponent } : {}
1536
1647
  },
1537
1648
  fallback: fallback2,
1649
+ ...componentVersions !== void 0 ? { componentVersions } : {},
1650
+ ...fallbackText !== void 0 ? { fallbackText } : {},
1538
1651
  loading,
1539
1652
  onError
1540
1653
  }),
1541
- [registry, catalog, resolveComponent, fallback2, loading, onError]
1654
+ [
1655
+ registry,
1656
+ catalog,
1657
+ resolveComponent,
1658
+ fallback2,
1659
+ fallbackText,
1660
+ componentVersions,
1661
+ loading,
1662
+ onError
1663
+ ]
1542
1664
  );
1543
1665
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TreeScopeContext.Provider, { value: scope, children });
1544
1666
  }
@@ -1598,7 +1720,7 @@ function GenerativeUI({
1598
1720
  onError: ownOnError
1599
1721
  }) {
1600
1722
  const provided = (0, import_react4.useContext)(GenuiContext);
1601
- const fallback2 = ownFallback ?? provided?.fallback;
1723
+ const fallback2 = ownFallback !== void 0 ? ownFallback : provided?.fallback;
1602
1724
  const loading = ownLoading ?? provided?.loading ?? null;
1603
1725
  const onError = ownOnError ?? provided?.onError;
1604
1726
  const options = useMergedOptions({
@@ -1623,6 +1745,8 @@ function GenerativeUI({
1623
1745
  GenerativeUIScope,
1624
1746
  {
1625
1747
  ...options,
1748
+ ...state.item.componentVersions !== void 0 ? { componentVersions: state.item.componentVersions } : {},
1749
+ ...state.item.fallbackText !== void 0 ? { fallbackText: state.item.fallbackText } : {},
1626
1750
  fallback: fallback2,
1627
1751
  loading,
1628
1752
  ...onError !== void 0 ? { onError } : {},
@@ -1638,6 +1762,7 @@ var AgentBackendContext = sharedContext(
1638
1762
  );
1639
1763
  function AgentProvider({
1640
1764
  backend,
1765
+ uiCapabilities,
1641
1766
  baseUrl,
1642
1767
  path,
1643
1768
  headers,
@@ -1669,7 +1794,7 @@ function AgentProvider({
1669
1794
  [backend, baseUrl, path, credentials, fetch, upload]
1670
1795
  );
1671
1796
  const content = genui !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GenuiProvider, { ...genui, children }) : children;
1672
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AgentBackendContext.Provider, { value, children: content });
1797
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AgentUiCapabilitiesContext.Provider, { value: uiCapabilities ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AgentBackendContext.Provider, { value, children: content }) });
1673
1798
  }
1674
1799
  var fallback;
1675
1800
  function defaultBackend() {
@@ -1680,6 +1805,12 @@ function useAgentBackend(own) {
1680
1805
  const provided = (0, import_react5.useContext)(AgentBackendContext);
1681
1806
  return own ?? provided ?? defaultBackend();
1682
1807
  }
1808
+ var AgentUiCapabilitiesContext = sharedContext(
1809
+ "@dudousxd/nestjs-agent-react:ui-capabilities"
1810
+ );
1811
+ function useAgentUiCapabilities() {
1812
+ return (0, import_react5.useContext)(AgentUiCapabilitiesContext) ?? void 0;
1813
+ }
1683
1814
 
1684
1815
  // src/config/use-agent-config.ts
1685
1816
  var shared = /* @__PURE__ */ new WeakMap();
@@ -1945,7 +2076,7 @@ async function defaultRefusal(response) {
1945
2076
  }
1946
2077
  function defaultForwardedProps(body) {
1947
2078
  const out = {};
1948
- for (const key of ["pageContext", "agent", "model"]) {
2079
+ for (const key of ["pageContext", "agent", "model", "persona", "uiCapabilities"]) {
1949
2080
  if (body[key] !== void 0 && body[key] !== null) out[key] = body[key];
1950
2081
  }
1951
2082
  return Object.keys(out).length > 0 ? out : void 0;
@@ -2979,6 +3110,15 @@ function isActionCall(part) {
2979
3110
  }
2980
3111
  function toolCallState(part) {
2981
3112
  const output = "output" in part ? part.output : void 0;
3113
+ if (output !== null && typeof output === "object" && "proposalId" in output && "executed" in output && output.executed === false)
3114
+ return {
3115
+ status: "awaiting-approval",
3116
+ isSettled: false,
3117
+ isFailed: false,
3118
+ isDenied: false,
3119
+ output,
3120
+ error: null
3121
+ };
2982
3122
  const errorText = "errorText" in part ? part.errorText : void 0;
2983
3123
  const outputError = output !== null && typeof output === "object" && "error" in output ? String(output.error) : void 0;
2984
3124
  const isDenied = part.state === "output-denied";
@@ -3023,7 +3163,11 @@ function describeToolCall(part, catalog, options = {}) {
3023
3163
  icon: presentation?.icon ?? null,
3024
3164
  tone: presentation?.tone ?? "neutral",
3025
3165
  detail: presentation?.detail ?? null,
3026
- confirm: confirm === void 0 ? null : {
3166
+ confirm: options.confirmation !== void 0 ? {
3167
+ title: options.confirmation.title,
3168
+ verb: options.confirmation.verb,
3169
+ detail: options.confirmation.detail ?? null
3170
+ } : confirm === void 0 ? null : {
3027
3171
  title: fillTemplate(confirm.title, input),
3028
3172
  verb: confirm.verb,
3029
3173
  detail: confirm.detail !== void 0 ? fillTemplate(confirm.detail, input) : null
@@ -3037,6 +3181,9 @@ function describeToolCall(part, catalog, options = {}) {
3037
3181
  }
3038
3182
  var STATUS_WEIGHT = {
3039
3183
  running: 4,
3184
+ queued: 4,
3185
+ executing: 4,
3186
+ succeeded: 0,
3040
3187
  "awaiting-approval": 3,
3041
3188
  failed: 2,
3042
3189
  denied: 1,
@@ -3056,7 +3203,7 @@ function groupToolActivity(calls, options = {}) {
3056
3203
  if (corrected.has(call.toolCallId)) continue;
3057
3204
  const presentation = options.catalog?.[call.name];
3058
3205
  const key = options.keyOf?.(call, presentation) ?? presentation?.label ?? call.name;
3059
- const status = toolCallState(call.part).status;
3206
+ const status = call.description.status;
3060
3207
  const phrase = phraseFor(
3061
3208
  presentation,
3062
3209
  call.part.input,
@@ -3298,7 +3445,7 @@ function isAncestor(call, candidate, byId) {
3298
3445
  }
3299
3446
  function buildToolCall(part, options, approval, catalog) {
3300
3447
  const toolCallId = part.toolCallId;
3301
- const awaiting = isAwaitingApproval(part);
3448
+ const awaiting = approval?.target?.kind === "proposal" ? approval.status === "pending" : isAwaitingApproval(part);
3302
3449
  const sending = awaiting ? options?.submitting(toolCallId) ?? null : null;
3303
3450
  return {
3304
3451
  part,
@@ -3308,19 +3455,30 @@ function buildToolCall(part, options, approval, catalog) {
3308
3455
  parentId: toolParentId(part),
3309
3456
  children: [],
3310
3457
  approval,
3311
- description: describeToolCall(part, catalog),
3458
+ description: proposalDescription(
3459
+ describeToolCall(
3460
+ part,
3461
+ catalog,
3462
+ approval?.confirmation === void 0 ? {} : { confirmation: approval.confirmation }
3463
+ ),
3464
+ approval
3465
+ ),
3312
3466
  isAwaitingApproval: awaiting,
3313
3467
  approve: {
3314
3468
  available: awaiting && options?.canApprove === true,
3315
3469
  isSubmitting: sending === "approve",
3316
3470
  // Read by field, not passed through: `onClick={call.approve.run}` hands this a click event,
3317
3471
  // and a host's handler must not receive that as its options.
3318
- run: (approveOptions) => approveOptions?.remember === true ? options?.approve(toolCallId, { remember: true }) : options?.approve(toolCallId)
3472
+ run: (approveOptions) => approval?.target === void 0 ? approveOptions?.remember === true ? options?.approve(toolCallId, { remember: true }) : options?.approve(toolCallId) : options?.approve(
3473
+ toolCallId,
3474
+ approveOptions?.remember === true ? { remember: true } : void 0,
3475
+ approval.target
3476
+ )
3319
3477
  },
3320
3478
  reject: {
3321
3479
  available: awaiting && options?.canReject === true,
3322
3480
  isSubmitting: sending === "reject",
3323
- run: () => options?.reject(toolCallId)
3481
+ run: () => approval?.target === void 0 ? options?.reject(toolCallId) : options?.reject(toolCallId, approval.target)
3324
3482
  },
3325
3483
  error: options?.errorOf(toolCallId) ?? null,
3326
3484
  errorCode: options?.errorCodeOf?.(toolCallId) ?? null
@@ -3470,7 +3628,7 @@ function buildElicitationBlock(key, part, request, options) {
3470
3628
  var UI_PART = "data-ui";
3471
3629
  var APPROVAL_PART = "data-approval-requested";
3472
3630
  var SETTLED_PART = "data-approval-settled";
3473
- var SETTLED_STATUSES = ["approved", "rejected", "expired"];
3631
+ var SETTLED_STATUSES = ["approved", "rejected", "expired", "superseded"];
3474
3632
  function readApprovals(parts) {
3475
3633
  const out = /* @__PURE__ */ new Map();
3476
3634
  const entry = (id) => {
@@ -3491,7 +3649,7 @@ function readApprovals(parts) {
3491
3649
  return found;
3492
3650
  };
3493
3651
  for (const part of parts) {
3494
- if (part.type !== APPROVAL_PART && part.type !== SETTLED_PART) {
3652
+ if (part.type !== APPROVAL_PART && part.type !== SETTLED_PART && part.type !== "data-action-proposal") {
3495
3653
  continue;
3496
3654
  }
3497
3655
  const data = part.data;
@@ -3499,12 +3657,35 @@ function readApprovals(parts) {
3499
3657
  continue;
3500
3658
  }
3501
3659
  const approval = entry(data.id);
3502
- if (part.type === APPROVAL_PART) {
3660
+ if (part.type === APPROVAL_PART || part.type === "data-action-proposal") {
3661
+ if (isRecord4(data.target) && data.target.kind === "proposal" && typeof data.target.proposalId === "string") {
3662
+ approval.target = {
3663
+ kind: "proposal",
3664
+ proposalId: data.target.proposalId,
3665
+ ...typeof data.target.threadId === "string" ? { threadId: data.target.threadId } : {}
3666
+ };
3667
+ }
3668
+ if (part.type === "data-action-proposal") {
3669
+ if (typeof data.status === "string" && ["pending", "approved", "rejected", "expired", "superseded"].includes(data.status))
3670
+ approval.status = data.status === "pending" ? null : data.status;
3671
+ if (data.executionStatus === null || data.executionStatus === "queued" || data.executionStatus === "executing" || data.executionStatus === "succeeded" || data.executionStatus === "failed")
3672
+ approval.executionStatus = data.executionStatus;
3673
+ approval.remember = data.remember === true;
3674
+ approval.decidedBy = typeof data.decidedBy === "string" ? data.decidedBy : null;
3675
+ approval.decidedVia = typeof data.decidedVia === "string" ? data.decidedVia : null;
3676
+ }
3503
3677
  if (typeof data.approver !== "string") {
3504
3678
  continue;
3505
3679
  }
3506
3680
  approval.approver = data.approver;
3507
3681
  approval.expiresAt = typeof data.expiresAt === "string" ? data.expiresAt : null;
3682
+ if (isRecord4(data.confirmation) && typeof data.confirmation.title === "string" && typeof data.confirmation.verb === "string" && (data.confirmation.detail === void 0 || typeof data.confirmation.detail === "string")) {
3683
+ approval.confirmation = {
3684
+ title: data.confirmation.title,
3685
+ verb: data.confirmation.verb,
3686
+ ...typeof data.confirmation.detail === "string" ? { detail: data.confirmation.detail } : {}
3687
+ };
3688
+ }
3508
3689
  approval.reason = typeof data.reason === "string" ? data.reason : null;
3509
3690
  continue;
3510
3691
  }
@@ -3528,9 +3709,12 @@ function approvalOf(parts, call) {
3528
3709
  }
3529
3710
  return {
3530
3711
  approver: parts.approver,
3712
+ ...parts.target === void 0 ? {} : { target: parts.target },
3713
+ ...parts.executionStatus === void 0 ? {} : { executionStatus: parts.executionStatus },
3714
+ ...parts.confirmation !== void 0 ? { confirmation: parts.confirmation } : {},
3531
3715
  expiresAt: parts.expiresAt,
3532
3716
  reason: parts.reason,
3533
- status: parts.status ?? statusFromPart(call),
3717
+ status: parts.status ?? (parts.target?.kind === "proposal" ? "pending" : statusFromPart(call)),
3534
3718
  remember: parts.remember,
3535
3719
  decidedBy: parts.decidedBy,
3536
3720
  decidedVia: parts.decidedVia,
@@ -3560,6 +3744,10 @@ function readUiComponent(part) {
3560
3744
  component: data.component,
3561
3745
  props: isRecord4(data.props) ? data.props : {},
3562
3746
  version: typeof data.version === "number" ? data.version : null,
3747
+ ...isRecord4(data.componentVersions) && Object.values(data.componentVersions).every(
3748
+ (version) => typeof version === "number" && Number.isSafeInteger(version) && version > 0
3749
+ ) ? { componentVersions: { ...data.componentVersions } } : {},
3750
+ ...typeof data.fallbackText === "string" ? { fallbackText: data.fallbackText } : {},
3563
3751
  toolCallId: typeof data.toolCallId === "string" ? data.toolCallId : null
3564
3752
  };
3565
3753
  }
@@ -3670,6 +3858,12 @@ function formatCostUsd(cost) {
3670
3858
  }
3671
3859
  return `$${cost.toFixed(2)}`;
3672
3860
  }
3861
+ function proposalDescription(description, approval) {
3862
+ if (approval?.target?.kind !== "proposal") return description;
3863
+ const status = approval.status === "pending" ? "awaiting-approval" : approval.status === "approved" ? approval.executionStatus ?? "queued" : "denied";
3864
+ const phrase = status === "awaiting-approval" ? "Awaiting approval" : status === "queued" ? "Queued" : status === "executing" ? "Executing" : status === "succeeded" ? "Succeeded" : status === "failed" ? "Failed" : approval.status === "expired" ? "Expired" : approval.status === "superseded" ? "Replaced" : "Rejected";
3865
+ return { ...description, status, phrase, result: null };
3866
+ }
3673
3867
 
3674
3868
  // src/transcript/use-stick-to-bottom.ts
3675
3869
  var import_react16 = require("react");
@@ -3962,23 +4156,31 @@ function useTranscriptItems({
3962
4156
  [settle]
3963
4157
  );
3964
4158
  const approve = (0, import_react17.useCallback)(
3965
- (toolCallId, options2) => {
4159
+ (toolCallId, options2, target) => {
3966
4160
  const onApprove = latest.current.handlers.onApprove;
3967
4161
  if (onApprove) {
3968
4162
  settle(
3969
4163
  toolCallId,
3970
4164
  "approve",
3971
- () => onApprove({ toolCallId, ...options2?.remember === true ? { remember: true } : {} })
4165
+ () => onApprove({
4166
+ toolCallId,
4167
+ ...target === void 0 ? {} : { target },
4168
+ ...options2?.remember === true ? { remember: true } : {}
4169
+ })
3972
4170
  );
3973
4171
  }
3974
4172
  },
3975
4173
  [settle]
3976
4174
  );
3977
4175
  const reject = (0, import_react17.useCallback)(
3978
- (toolCallId) => {
4176
+ (toolCallId, target) => {
3979
4177
  const onReject = latest.current.handlers.onReject;
3980
4178
  if (onReject) {
3981
- settle(toolCallId, "reject", () => onReject({ toolCallId }));
4179
+ settle(
4180
+ toolCallId,
4181
+ "reject",
4182
+ () => onReject({ toolCallId, ...target === void 0 ? {} : { target } })
4183
+ );
3982
4184
  }
3983
4185
  },
3984
4186
  [settle]
@@ -4176,14 +4378,36 @@ function settleHandlers(options, backend) {
4176
4378
  ),
4177
4379
  onApprove: pick(
4178
4380
  options.onApprove,
4179
- backend.approveToolCall ? async (input) => {
4180
- await backend.approveToolCall?.(input);
4381
+ backend.approveToolCall || backend.approveActionProposal ? async (input) => {
4382
+ if (input.target?.kind === "proposal") {
4383
+ if (input.target.threadId === void 0)
4384
+ throw new Error("A proposal decision requires its thread scope");
4385
+ await requireBackendMethod(
4386
+ backend,
4387
+ "approveActionProposal"
4388
+ )({
4389
+ threadId: input.target.threadId,
4390
+ proposalId: input.target.proposalId,
4391
+ ...input.remember === void 0 ? {} : { remember: input.remember }
4392
+ });
4393
+ } else await requireBackendMethod(backend, "approveToolCall")(input);
4181
4394
  } : void 0
4182
4395
  ),
4183
4396
  onReject: pick(
4184
4397
  options.onReject,
4185
- backend.rejectToolCall ? async (input) => {
4186
- await backend.rejectToolCall?.(input);
4398
+ backend.rejectToolCall || backend.rejectActionProposal ? async (input) => {
4399
+ if (input.target?.kind === "proposal") {
4400
+ if (input.target.threadId === void 0)
4401
+ throw new Error("A proposal decision requires its thread scope");
4402
+ await requireBackendMethod(
4403
+ backend,
4404
+ "rejectActionProposal"
4405
+ )({
4406
+ threadId: input.target.threadId,
4407
+ proposalId: input.target.proposalId,
4408
+ ...input.reason === void 0 ? {} : { reason: input.reason }
4409
+ });
4410
+ } else await requireBackendMethod(backend, "rejectToolCall")(input);
4187
4411
  } : void 0
4188
4412
  )
4189
4413
  };
@@ -5088,6 +5312,8 @@ function storedMessageToUiMessage(message) {
5088
5312
  id: component.id,
5089
5313
  component: component.component,
5090
5314
  props: component.props,
5315
+ ...component.componentVersions !== void 0 ? { componentVersions: component.componentVersions } : {},
5316
+ ...component.fallbackText !== void 0 ? { fallbackText: component.fallbackText } : {},
5091
5317
  ...component.version !== void 0 ? { version: component.version } : {},
5092
5318
  ...component.toolCallId !== void 0 ? { toolCallId: component.toolCallId } : {}
5093
5319
  }
@@ -5107,6 +5333,8 @@ function storedMessageToUiMessage(message) {
5107
5333
  data: {
5108
5334
  id: approval.toolCallId,
5109
5335
  approver: approval.approver,
5336
+ ...approval.target !== void 0 ? { target: approval.target } : approval.proposalId !== void 0 ? { target: { kind: "proposal", proposalId: approval.proposalId } } : {},
5337
+ ...approval.confirmation !== void 0 ? { confirmation: approval.confirmation } : {},
5110
5338
  ...approval.expiresAt !== void 0 ? { expiresAt: approval.expiresAt } : {}
5111
5339
  }
5112
5340
  });
@@ -5163,6 +5391,7 @@ function storedMessageToUiMessage(message) {
5163
5391
  const metadata = {
5164
5392
  // The host's own facts first: the library's keys win on a clash.
5165
5393
  ...message.metadata,
5394
+ ...message.actionProposalOutcome === void 0 ? {} : { actionProposalOutcomeId: message.actionProposalOutcome.id },
5166
5395
  ...message.feedback !== void 0 ? { feedback: message.feedback } : {},
5167
5396
  ...message.createdAt ? { createdAt: message.createdAt } : {},
5168
5397
  ...message.agentName !== void 0 ? { agentName: message.agentName } : {},
@@ -5198,6 +5427,8 @@ function storedThreadToUiMessages(messages) {
5198
5427
  return turns.map(mergeTurn);
5199
5428
  }
5200
5429
  function sameRun(previous, next) {
5430
+ if (previous.actionProposalOutcome !== void 0 || next.actionProposalOutcome !== void 0)
5431
+ return false;
5201
5432
  return previous.runId === void 0 || next.runId === void 0 || previous.runId === next.runId;
5202
5433
  }
5203
5434
  function mergeTurn(rows) {
@@ -5244,8 +5475,163 @@ function sumUsage(rows) {
5244
5475
  }
5245
5476
 
5246
5477
  // src/use-agent-chat.ts
5247
- var import_react22 = require("@ai-sdk/react");
5248
- var import_react23 = require("react");
5478
+ var import_react23 = require("@ai-sdk/react");
5479
+ var import_react24 = require("react");
5480
+
5481
+ // src/approvals/use-action-proposals.ts
5482
+ var import_react22 = require("react");
5483
+
5484
+ // src/approvals/proposals.ts
5485
+ function proposalNeedsPolling(proposal) {
5486
+ return proposal.decision === "pending" || proposal.execution?.status === "queued" || proposal.execution?.status === "executing" || proposal.outcomeDelivery?.status === "pending";
5487
+ }
5488
+ function reconcileProposalMessages(current, proposals, facts) {
5489
+ const messages = current.map((message) => {
5490
+ const relevant = proposals.filter(
5491
+ (proposal) => message.parts.some((part) => {
5492
+ if ("data" in part && record(part.data) && record(part.data.target) && part.data.target.kind === "proposal")
5493
+ return part.data.target.proposalId === proposal.id;
5494
+ if ("toolCallId" in part && part.toolCallId === proposal.originToolCallId) {
5495
+ if ("output" in part && record(part.output) && typeof part.output.proposalId === "string")
5496
+ return part.output.proposalId === proposal.id;
5497
+ return record(message.metadata) && message.metadata.runId === proposal.originRunId;
5498
+ }
5499
+ return false;
5500
+ })
5501
+ );
5502
+ if (relevant.length === 0) return message;
5503
+ const ids = new Set(relevant.map((proposal) => proposal.originToolCallId));
5504
+ const parts = message.parts.filter(
5505
+ (part) => !(part.type === "data-action-proposal" && "id" in part && typeof part.id === "string" && ids.has(part.id))
5506
+ );
5507
+ for (const proposal of relevant)
5508
+ parts.push({
5509
+ type: "data-action-proposal",
5510
+ id: proposal.originToolCallId,
5511
+ data: {
5512
+ id: proposal.originToolCallId,
5513
+ target: { kind: "proposal", proposalId: proposal.id, threadId: proposal.threadId },
5514
+ approver: proposal.approver,
5515
+ confirmation: proposal.confirmation,
5516
+ expiresAt: proposal.expiresAt === null ? null : Math.abs(proposal.expiresAt) <= 864e13 ? new Date(proposal.expiresAt).toISOString() : null,
5517
+ status: proposal.decision,
5518
+ executionStatus: proposal.execution?.status ?? null,
5519
+ remember: proposal.decisionAudit?.remember === true,
5520
+ decidedBy: proposal.decisionAudit?.actorRef ?? null,
5521
+ decidedVia: proposal.decisionAudit?.via ?? null,
5522
+ reason: proposal.decisionAudit?.reason ?? null
5523
+ }
5524
+ });
5525
+ return { ...message, parts };
5526
+ });
5527
+ const knownMessages = new Set(messages.map((message) => message.id));
5528
+ const knownOutcomes = new Set(
5529
+ messages.map((message) => outcomeId(message.metadata)).filter(Boolean)
5530
+ );
5531
+ for (const fact of facts) {
5532
+ const id = fact.actionProposalOutcome?.id;
5533
+ if (id === void 0 || knownMessages.has(fact.id) || knownOutcomes.has(id)) continue;
5534
+ const message = storedMessageToUiMessage(fact);
5535
+ messages.push({
5536
+ ...message,
5537
+ metadata: {
5538
+ ...record(message.metadata) ? message.metadata : {},
5539
+ actionProposalOutcomeId: id
5540
+ }
5541
+ });
5542
+ knownMessages.add(fact.id);
5543
+ knownOutcomes.add(id);
5544
+ }
5545
+ return messages;
5546
+ }
5547
+ function record(value) {
5548
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5549
+ }
5550
+ function outcomeId(value) {
5551
+ return record(value) && typeof value.actionProposalOutcomeId === "string" ? value.actionProposalOutcomeId : void 0;
5552
+ }
5553
+
5554
+ // src/approvals/use-action-proposals.ts
5555
+ function useActionProposals(backend, threadId, setMessages, refreshKey, pollMs = 1e3) {
5556
+ const [items, setItems] = (0, import_react22.useState)([]);
5557
+ const [error, setError] = (0, import_react22.useState)(null);
5558
+ const latest = (0, import_react22.useRef)({ threadId, setMessages });
5559
+ latest.current = { threadId, setMessages };
5560
+ const mounted = (0, import_react22.useRef)(true);
5561
+ const requests = (0, import_react22.useRef)(/* @__PURE__ */ new Map());
5562
+ (0, import_react22.useEffect)(() => {
5563
+ mounted.current = true;
5564
+ return () => {
5565
+ mounted.current = false;
5566
+ };
5567
+ }, []);
5568
+ const refresh = (0, import_react22.useCallback)(async () => {
5569
+ if (threadId === void 0 || backend.listActionProposals === void 0) return;
5570
+ const pending = requests.current.get(threadId);
5571
+ if (pending) return pending;
5572
+ const request = (async () => {
5573
+ try {
5574
+ const proposals = await backend.listActionProposals?.({ threadId });
5575
+ if (!mounted.current || latest.current.threadId !== threadId || !Array.isArray(proposals))
5576
+ return;
5577
+ const admitted = proposals.some(
5578
+ (proposal) => proposal.outcomeDelivery?.status === "admitted"
5579
+ );
5580
+ const facts = admitted ? (await backend.getThread(threadId)).messages.filter(
5581
+ (message) => message.actionProposalOutcome !== void 0
5582
+ ) : [];
5583
+ if (!mounted.current || latest.current.threadId !== threadId) return;
5584
+ setItems(proposals);
5585
+ setError(null);
5586
+ latest.current.setMessages(
5587
+ (current) => reconcileProposalMessages(current, proposals, facts)
5588
+ );
5589
+ } catch (cause) {
5590
+ if (mounted.current && latest.current.threadId === threadId)
5591
+ setError(cause instanceof Error ? cause : new Error(String(cause)));
5592
+ }
5593
+ })();
5594
+ requests.current.set(threadId, request);
5595
+ try {
5596
+ await request;
5597
+ } finally {
5598
+ requests.current.delete(threadId);
5599
+ }
5600
+ }, [backend, threadId]);
5601
+ (0, import_react22.useEffect)(() => {
5602
+ setItems([]);
5603
+ setError(null);
5604
+ }, [threadId]);
5605
+ (0, import_react22.useEffect)(() => {
5606
+ void refresh();
5607
+ }, [refresh, refreshKey]);
5608
+ (0, import_react22.useEffect)(() => {
5609
+ if (!items.some(proposalNeedsPolling) || pollMs <= 0) return;
5610
+ const timer = setInterval(() => {
5611
+ void refresh();
5612
+ }, pollMs);
5613
+ return () => clearInterval(timer);
5614
+ }, [items, pollMs, refresh]);
5615
+ (0, import_react22.useEffect)(() => {
5616
+ const refetch = () => {
5617
+ void refresh();
5618
+ };
5619
+ const visible = () => {
5620
+ if (document.visibilityState === "visible") refetch();
5621
+ };
5622
+ window.addEventListener("focus", refetch);
5623
+ window.addEventListener("online", refetch);
5624
+ document.addEventListener("visibilitychange", visible);
5625
+ return () => {
5626
+ window.removeEventListener("focus", refetch);
5627
+ window.removeEventListener("online", refetch);
5628
+ document.removeEventListener("visibilitychange", visible);
5629
+ };
5630
+ }, [refresh]);
5631
+ return { items, error, refresh };
5632
+ }
5633
+
5634
+ // src/use-agent-chat.ts
5249
5635
  var EMPTY_QUEUE = { items: [], paused: null };
5250
5636
  var localQueueSequence = 0;
5251
5637
  function queuedUserMessage(turn) {
@@ -5300,13 +5686,16 @@ function localChatId() {
5300
5686
  return `local-chat-${localChatSequence}`;
5301
5687
  }
5302
5688
  function useAgentChat(options = {}) {
5303
- const latest = (0, import_react23.useRef)(options);
5689
+ const providerCapabilities = useAgentUiCapabilities();
5690
+ const capabilitiesRef = (0, import_react24.useRef)(providerCapabilities);
5691
+ capabilitiesRef.current = providerCapabilities;
5692
+ const latest = (0, import_react24.useRef)(options);
5304
5693
  latest.current = options;
5305
5694
  const resolved = useAgentBackend(options.backend);
5306
- const client = (0, import_react23.useRef)(resolved).current;
5307
- const createdThreadId = (0, import_react23.useRef)(void 0);
5308
- const chatIdRef = (0, import_react23.useRef)(options.threadId ?? localChatId());
5309
- const boundThreadRef = (0, import_react23.useRef)(options.threadId);
5695
+ const client = (0, import_react24.useRef)(resolved).current;
5696
+ const createdThreadId = (0, import_react24.useRef)(void 0);
5697
+ const chatIdRef = (0, import_react24.useRef)(options.threadId ?? localChatId());
5698
+ const boundThreadRef = (0, import_react24.useRef)(options.threadId);
5310
5699
  if (options.threadId !== boundThreadRef.current) {
5311
5700
  boundThreadRef.current = options.threadId;
5312
5701
  const adopting = options.threadId !== void 0 && options.threadId === createdThreadId.current;
@@ -5316,39 +5705,41 @@ function useAgentChat(options = {}) {
5316
5705
  }
5317
5706
  }
5318
5707
  const chatId = chatIdRef.current;
5319
- const [runId, setRunId] = (0, import_react23.useState)(options.resumeRunId);
5320
- const runIdRef = (0, import_react23.useRef)(runId);
5708
+ const [runId, setRunId] = (0, import_react24.useState)(options.resumeRunId);
5709
+ const runIdRef = (0, import_react24.useRef)(runId);
5321
5710
  runIdRef.current = runId;
5322
- const settlingRunIdRef = (0, import_react23.useRef)(void 0);
5323
- const autoResumeRunIdRef = (0, import_react23.useRef)(void 0);
5324
- const [activeRunId, setActiveRunId] = (0, import_react23.useState)(null);
5325
- const [historyFor, setHistoryFor] = (0, import_react23.useState)(void 0);
5326
- const [historyError, setHistoryError] = (0, import_react23.useState)(null);
5327
- const [runError, setRunError] = (0, import_react23.useState)(null);
5328
- const [threadModel, setThreadModel] = (0, import_react23.useState)(null);
5329
- const [threadPersona, setThreadPersona] = (0, import_react23.useState)(null);
5330
- const [pickedModel, setPickedModel] = (0, import_react23.useState)(void 0);
5331
- const pickedModelRef = (0, import_react23.useRef)(pickedModel);
5711
+ const settlingRunIdRef = (0, import_react24.useRef)(void 0);
5712
+ const autoResumeRunIdRef = (0, import_react24.useRef)(void 0);
5713
+ const [activeRunId, setActiveRunId] = (0, import_react24.useState)(null);
5714
+ const [historyFor, setHistoryFor] = (0, import_react24.useState)(void 0);
5715
+ const [historyError, setHistoryError] = (0, import_react24.useState)(null);
5716
+ const [runError, setRunError] = (0, import_react24.useState)(null);
5717
+ const [threadModel, setThreadModel] = (0, import_react24.useState)(null);
5718
+ const [threadPersona, setThreadPersona] = (0, import_react24.useState)(null);
5719
+ const [pickedModel, setPickedModel] = (0, import_react24.useState)(void 0);
5720
+ const pickedModelRef = (0, import_react24.useRef)(pickedModel);
5332
5721
  pickedModelRef.current = pickedModel;
5333
- const lockedRef = (0, import_react23.useRef)(false);
5334
- const pendingPin = (0, import_react23.useRef)(void 0);
5335
- const regenerateNext = (0, import_react23.useRef)(false);
5336
- const currentThreadId = (0, import_react23.useCallback)(
5722
+ const lockedRef = (0, import_react24.useRef)(false);
5723
+ const pendingPin = (0, import_react24.useRef)(void 0);
5724
+ const regenerateNext = (0, import_react24.useRef)(false);
5725
+ const currentThreadId = (0, import_react24.useCallback)(
5337
5726
  () => latest.current.threadId ?? createdThreadId.current,
5338
5727
  []
5339
5728
  );
5340
- const [queueState, setQueueState] = (0, import_react23.useState)(EMPTY_QUEUE);
5341
- const queueStateRef = (0, import_react23.useRef)(queueState);
5342
- const applyQueue = (0, import_react23.useCallback)((next) => {
5729
+ const [queueState, setQueueState] = (0, import_react24.useState)(EMPTY_QUEUE);
5730
+ const queueStateRef = (0, import_react24.useRef)(queueState);
5731
+ const applyQueue = (0, import_react24.useCallback)((next) => {
5343
5732
  queueStateRef.current = next;
5344
5733
  setQueueState(next);
5345
5734
  }, []);
5346
- const [pendingSends, setPendingSends] = (0, import_react23.useState)([]);
5347
- const [queueError, setQueueError] = (0, import_react23.useState)(null);
5348
- const handoff = (0, import_react23.useRef)(void 0);
5349
- const queuedSend = (0, import_react23.useRef)(void 0);
5350
- const threadWaiters = (0, import_react23.useRef)([]);
5351
- const turnBody = (0, import_react23.useCallback)(() => {
5735
+ const [pendingSends, setPendingSends] = (0, import_react24.useState)([]);
5736
+ const [queueError, setQueueError] = (0, import_react24.useState)(null);
5737
+ const handoff = (0, import_react24.useRef)(void 0);
5738
+ const queuedSend = (0, import_react24.useRef)(void 0);
5739
+ const proposalRefreshRef = (0, import_react24.useRef)(async () => {
5740
+ });
5741
+ const threadWaiters = (0, import_react24.useRef)([]);
5742
+ const turnBody = (0, import_react24.useCallback)(() => {
5352
5743
  const current = latest.current;
5353
5744
  if (current.persona !== void 0) setThreadPersona(current.persona);
5354
5745
  const pageContext = current.getPageContext?.() ?? null;
@@ -5361,12 +5752,13 @@ function useAgentChat(options = {}) {
5361
5752
  ...current.persona !== void 0 ? { persona: current.persona } : {},
5362
5753
  ...threadId !== void 0 ? { threadId } : {},
5363
5754
  ...model !== void 0 ? { model } : {},
5364
- ...pageContext ? { pageContext } : {}
5755
+ ...pageContext ? { pageContext } : {},
5756
+ ...(current.uiCapabilities ?? capabilitiesRef.current) === void 0 ? {} : { uiCapabilities: current.uiCapabilities ?? capabilitiesRef.current }
5365
5757
  };
5366
5758
  }, [currentThreadId]);
5367
- const [connection, setConnection] = (0, import_react23.useState)({ status: "live" });
5368
- const resyncAfterSettle = (0, import_react23.useRef)(false);
5369
- const transport = (0, import_react23.useMemo)(() => {
5759
+ const [connection, setConnection] = (0, import_react24.useState)({ status: "live" });
5760
+ const resyncAfterSettle = (0, import_react24.useRef)(false);
5761
+ const transport = (0, import_react24.useMemo)(() => {
5370
5762
  function onMeta(meta) {
5371
5763
  settlingRunIdRef.current = meta.runId;
5372
5764
  setRunId(meta.runId);
@@ -5418,14 +5810,15 @@ function useAgentChat(options = {}) {
5418
5810
  }
5419
5811
  });
5420
5812
  }, []);
5421
- const backgroundRef = (0, import_react23.useRef)(() => Promise.resolve());
5422
- const chat = (0, import_react22.useChat)({
5813
+ const backgroundRef = (0, import_react24.useRef)(() => Promise.resolve());
5814
+ const chat = (0, import_react23.useChat)({
5423
5815
  transport,
5424
5816
  id: chatId,
5425
5817
  resume: options.resumeRunId !== void 0,
5426
5818
  ...options.initialMessages !== void 0 ? { messages: options.initialMessages } : {},
5427
5819
  onData: (part) => {
5428
5820
  latest.current.onData?.(part);
5821
+ if (part.type === "data-proposal-decision") void proposalRefreshRef.current();
5429
5822
  if (part.type === "data-queue") {
5430
5823
  onQueueData(part.data);
5431
5824
  }
@@ -5472,7 +5865,7 @@ function useAgentChat(options = {}) {
5472
5865
  }
5473
5866
  }
5474
5867
  });
5475
- const chatRef = (0, import_react23.useRef)(chat);
5868
+ const chatRef = (0, import_react24.useRef)(chat);
5476
5869
  chatRef.current = chat;
5477
5870
  function onQueueData(data) {
5478
5871
  const frame = data ?? {};
@@ -5520,8 +5913,8 @@ function useAgentChat(options = {}) {
5520
5913
  } catch {
5521
5914
  }
5522
5915
  }
5523
- const firstChatId = (0, import_react23.useRef)(chatId);
5524
- (0, import_react23.useEffect)(() => {
5916
+ const firstChatId = (0, import_react24.useRef)(chatId);
5917
+ (0, import_react24.useEffect)(() => {
5525
5918
  if (chatId === firstChatId.current) return;
5526
5919
  firstChatId.current = chatId;
5527
5920
  setRunId(void 0);
@@ -5540,7 +5933,7 @@ function useAgentChat(options = {}) {
5540
5933
  handoff.current = void 0;
5541
5934
  queuedSend.current = void 0;
5542
5935
  }, [chatId]);
5543
- (0, import_react23.useEffect)(() => {
5936
+ (0, import_react24.useEffect)(() => {
5544
5937
  const threadId = options.threadId;
5545
5938
  if (threadId === void 0) return;
5546
5939
  if (threadId === createdThreadId.current) return;
@@ -5587,8 +5980,8 @@ function useAgentChat(options = {}) {
5587
5980
  };
5588
5981
  }, [client, chatId, options.threadId]);
5589
5982
  const isLoadingHistory = options.threadId !== void 0 && options.threadId !== createdThreadId.current && options.history !== false && options.initialMessages === void 0 && historyFor !== options.threadId;
5590
- const turnInFlight = (0, import_react23.useRef)(false);
5591
- const isTurnInFlight = (0, import_react23.useCallback)(
5983
+ const turnInFlight = (0, import_react24.useRef)(false);
5984
+ const isTurnInFlight = (0, import_react24.useCallback)(
5592
5985
  () => turnInFlight.current || transport.isAttemptLive,
5593
5986
  [transport]
5594
5987
  );
@@ -5597,20 +5990,20 @@ function useAgentChat(options = {}) {
5597
5990
  enabled: options.quota !== false && typeof client.getQuota === "function"
5598
5991
  });
5599
5992
  const blocked = options.blocked !== void 0 ? options.blocked : quota.blocked;
5600
- const blockedRef = (0, import_react23.useRef)(blocked);
5993
+ const blockedRef = (0, import_react24.useRef)(blocked);
5601
5994
  blockedRef.current = blocked;
5602
5995
  const whileRunning = typeof client.enqueueMessage === "function" ? options.whileRunning ?? "queue" : "block";
5603
- const whileRunningRef = (0, import_react23.useRef)(whileRunning);
5996
+ const whileRunningRef = (0, import_react24.useRef)(whileRunning);
5604
5997
  whileRunningRef.current = whileRunning;
5605
- const canQueueRef = (0, import_react23.useRef)(false);
5998
+ const canQueueRef = (0, import_react24.useRef)(false);
5606
5999
  canQueueRef.current = typeof client.enqueueMessage === "function";
5607
- const threadForQueue = (0, import_react23.useCallback)(async () => {
6000
+ const threadForQueue = (0, import_react24.useCallback)(async () => {
5608
6001
  const known = currentThreadId();
5609
6002
  if (known !== void 0) return known;
5610
6003
  if (!isTurnInFlight()) throw new Error("queue: this chat has no thread yet");
5611
6004
  return new Promise((resolve) => threadWaiters.current.push(resolve));
5612
6005
  }, [currentThreadId, isTurnInFlight]);
5613
- const queueCall = (0, import_react23.useCallback)(async (run) => {
6006
+ const queueCall = (0, import_react24.useCallback)(async (run) => {
5614
6007
  try {
5615
6008
  const result = await run();
5616
6009
  setQueueError(null);
@@ -5620,7 +6013,7 @@ function useAgentChat(options = {}) {
5620
6013
  throw error;
5621
6014
  }
5622
6015
  }, []);
5623
- const enqueue = (0, import_react23.useCallback)(
6016
+ const enqueue = (0, import_react24.useCallback)(
5624
6017
  async (text2, {
5625
6018
  attachments = [],
5626
6019
  mode = "queue"
@@ -5668,7 +6061,7 @@ function useAgentChat(options = {}) {
5668
6061
  },
5669
6062
  [client, queueCall, threadForQueue, turnBody, applyQueue, isTurnInFlight]
5670
6063
  );
5671
- const sendMessage = (0, import_react23.useCallback)(
6064
+ const sendMessage = (0, import_react24.useCallback)(
5672
6065
  async (message, options2) => {
5673
6066
  const block = blockedRef.current;
5674
6067
  if (block != null) throw new QuotaBlockedError(block);
@@ -5692,7 +6085,7 @@ function useAgentChat(options = {}) {
5692
6085
  },
5693
6086
  [isTurnInFlight, enqueue]
5694
6087
  );
5695
- const removeQueued = (0, import_react23.useCallback)(
6088
+ const removeQueued = (0, import_react24.useCallback)(
5696
6089
  async (id) => {
5697
6090
  const previous = queueStateRef.current;
5698
6091
  applyQueue({ ...previous, items: previous.items.filter((item) => item.id !== id) });
@@ -5705,7 +6098,7 @@ function useAgentChat(options = {}) {
5705
6098
  },
5706
6099
  [client, queueCall, applyQueue]
5707
6100
  );
5708
- const interruptQueued = (0, import_react23.useCallback)(
6101
+ const interruptQueued = (0, import_react24.useCallback)(
5709
6102
  async (id) => {
5710
6103
  const previous = queueStateRef.current;
5711
6104
  const moving = previous.items.find((item) => item.id === id);
@@ -5740,7 +6133,7 @@ function useAgentChat(options = {}) {
5740
6133
  },
5741
6134
  [client, queueCall, applyQueue, isTurnInFlight]
5742
6135
  );
5743
- const editQueued = (0, import_react23.useCallback)(
6136
+ const editQueued = (0, import_react24.useCallback)(
5744
6137
  async (id, text2) => {
5745
6138
  applyQueue(
5746
6139
  await queueCall(
@@ -5750,7 +6143,7 @@ function useAgentChat(options = {}) {
5750
6143
  },
5751
6144
  [client, queueCall, applyQueue]
5752
6145
  );
5753
- const moveQueued = (0, import_react23.useCallback)(
6146
+ const moveQueued = (0, import_react24.useCallback)(
5754
6147
  async (id, index) => {
5755
6148
  const previous = queueStateRef.current;
5756
6149
  const moving = previous.items.find((item) => item.id === id);
@@ -5772,12 +6165,12 @@ function useAgentChat(options = {}) {
5772
6165
  },
5773
6166
  [client, queueCall, applyQueue]
5774
6167
  );
5775
- const clearQueue = (0, import_react23.useCallback)(async () => {
6168
+ const clearQueue = (0, import_react24.useCallback)(async () => {
5776
6169
  const threadId = currentThreadId();
5777
6170
  if (threadId === void 0) return;
5778
6171
  applyQueue(await queueCall(() => requireBackendMethod(client, "clearQueue")(threadId)));
5779
6172
  }, [client, queueCall, currentThreadId, applyQueue]);
5780
- const resumeQueue = (0, import_react23.useCallback)(async () => {
6173
+ const resumeQueue = (0, import_react24.useCallback)(async () => {
5781
6174
  const threadId = currentThreadId();
5782
6175
  if (threadId === void 0) return;
5783
6176
  const before = queueStateRef.current;
@@ -5795,7 +6188,7 @@ function useAgentChat(options = {}) {
5795
6188
  else attachTo(turn);
5796
6189
  }
5797
6190
  }, [client, queueCall, currentThreadId, applyQueue, isTurnInFlight]);
5798
- const resumeQueueRef = (0, import_react23.useRef)(resumeQueue);
6191
+ const resumeQueueRef = (0, import_react24.useRef)(resumeQueue);
5799
6192
  resumeQueueRef.current = resumeQueue;
5800
6193
  const queuedItems = [
5801
6194
  ...pendingSends.filter((item) => item.interrupt),
@@ -5825,7 +6218,7 @@ function useAgentChat(options = {}) {
5825
6218
  resume: resumeQueue,
5826
6219
  error: queueError
5827
6220
  };
5828
- const addToolResult = (0, import_react23.useCallback)(
6221
+ const addToolResult = (0, import_react24.useCallback)(
5829
6222
  ({ tool, toolCallId, output }) => chatRef.current.addToolResult({
5830
6223
  tool,
5831
6224
  toolCallId,
@@ -5833,8 +6226,8 @@ function useAgentChat(options = {}) {
5833
6226
  }),
5834
6227
  []
5835
6228
  );
5836
- const [backgroundRuns, setBackgroundRuns] = (0, import_react23.useState)([]);
5837
- const refreshBackground = (0, import_react23.useCallback)(async () => {
6229
+ const [backgroundRuns, setBackgroundRuns] = (0, import_react24.useState)([]);
6230
+ const refreshBackground = (0, import_react24.useCallback)(async () => {
5838
6231
  const threadId = currentThreadId();
5839
6232
  if (threadId === void 0) {
5840
6233
  return;
@@ -5854,13 +6247,13 @@ function useAgentChat(options = {}) {
5854
6247
  }, [client, currentThreadId]);
5855
6248
  backgroundRef.current = refreshBackground;
5856
6249
  const isWorking = backgroundRuns.some((run) => run.status === "running");
5857
- (0, import_react23.useEffect)(() => {
6250
+ (0, import_react24.useEffect)(() => {
5858
6251
  if (options.background !== true || options.threadId === void 0) {
5859
6252
  return;
5860
6253
  }
5861
6254
  void refreshBackground();
5862
6255
  }, [options.background, options.threadId, chatId, refreshBackground]);
5863
- (0, import_react23.useEffect)(() => {
6256
+ (0, import_react24.useEffect)(() => {
5864
6257
  const every = latest.current.backgroundPollMs ?? 5e3;
5865
6258
  if (latest.current.background !== true || !isWorking || every <= 0) {
5866
6259
  return;
@@ -5868,7 +6261,15 @@ function useAgentChat(options = {}) {
5868
6261
  const timer = setInterval(() => void refreshBackground(), every);
5869
6262
  return () => clearInterval(timer);
5870
6263
  }, [isWorking, refreshBackground]);
5871
- const cancel = (0, import_react23.useCallback)(async () => {
6264
+ const proposals = useActionProposals(
6265
+ client,
6266
+ options.proposals === false || options.proposals !== true && options.history === false && options.resume === false ? void 0 : currentThreadId(),
6267
+ (update) => chatRef.current.setMessages(update),
6268
+ `${chat.status}:${connection.status}`,
6269
+ options.proposalPollMs
6270
+ );
6271
+ proposalRefreshRef.current = proposals.refresh;
6272
+ const cancel = (0, import_react24.useCallback)(async () => {
5872
6273
  chatRef.current.stop();
5873
6274
  const active = runIdRef.current;
5874
6275
  if (active) {
@@ -5885,8 +6286,23 @@ function useAgentChat(options = {}) {
5885
6286
  }
5886
6287
  }
5887
6288
  }, [client, currentThreadId, applyQueue]);
5888
- const approve = (0, import_react23.useCallback)(
5889
- async ({ toolCallId, remember, via }) => {
6289
+ const approve = (0, import_react24.useCallback)(
6290
+ async ({ toolCallId, target, remember, via }) => {
6291
+ if (target?.kind === "proposal") {
6292
+ const threadId = target.threadId ?? currentThreadId();
6293
+ if (threadId === void 0)
6294
+ throw new Error("A proposal decision requires its thread scope");
6295
+ await requireBackendMethod(
6296
+ client,
6297
+ "approveActionProposal"
6298
+ )({
6299
+ threadId,
6300
+ proposalId: target.proposalId,
6301
+ ...remember === true ? { remember: true } : {}
6302
+ });
6303
+ await proposals.refresh();
6304
+ return;
6305
+ }
5890
6306
  await requireBackendMethod(
5891
6307
  client,
5892
6308
  "approveToolCall"
@@ -5896,10 +6312,25 @@ function useAgentChat(options = {}) {
5896
6312
  ...via !== void 0 ? { via } : {}
5897
6313
  });
5898
6314
  },
5899
- [client]
6315
+ [client, currentThreadId, proposals.refresh]
5900
6316
  );
5901
- const reject = (0, import_react23.useCallback)(
5902
- async ({ toolCallId, reason, via }) => {
6317
+ const reject = (0, import_react24.useCallback)(
6318
+ async ({ toolCallId, target, reason, via }) => {
6319
+ if (target?.kind === "proposal") {
6320
+ const threadId = target.threadId ?? currentThreadId();
6321
+ if (threadId === void 0)
6322
+ throw new Error("A proposal decision requires its thread scope");
6323
+ await requireBackendMethod(
6324
+ client,
6325
+ "rejectActionProposal"
6326
+ )({
6327
+ threadId,
6328
+ proposalId: target.proposalId,
6329
+ ...reason === void 0 ? {} : { reason }
6330
+ });
6331
+ await proposals.refresh();
6332
+ return;
6333
+ }
5903
6334
  await requireBackendMethod(
5904
6335
  client,
5905
6336
  "rejectToolCall"
@@ -5909,9 +6340,9 @@ function useAgentChat(options = {}) {
5909
6340
  ...via !== void 0 ? { via } : {}
5910
6341
  });
5911
6342
  },
5912
- [client]
6343
+ [client, currentThreadId, proposals.refresh]
5913
6344
  );
5914
- const answer = (0, import_react23.useCallback)(
6345
+ const answer = (0, import_react24.useCallback)(
5915
6346
  async ({ toolCallId, answers, via }) => {
5916
6347
  await requireBackendMethod(
5917
6348
  client,
@@ -5924,7 +6355,7 @@ function useAgentChat(options = {}) {
5924
6355
  },
5925
6356
  [client]
5926
6357
  );
5927
- const skip = (0, import_react23.useCallback)(
6358
+ const skip = (0, import_react24.useCallback)(
5928
6359
  async ({ toolCallId, via }) => {
5929
6360
  await requireBackendMethod(
5930
6361
  client,
@@ -5933,7 +6364,7 @@ function useAgentChat(options = {}) {
5933
6364
  },
5934
6365
  [client]
5935
6366
  );
5936
- const regenerate = (0, import_react23.useCallback)(
6367
+ const regenerate = (0, import_react24.useCallback)(
5937
6368
  (_input) => {
5938
6369
  const block = blockedRef.current;
5939
6370
  if (block != null) throw new QuotaBlockedError(block);
@@ -5946,7 +6377,7 @@ function useAgentChat(options = {}) {
5946
6377
  },
5947
6378
  [isTurnInFlight]
5948
6379
  );
5949
- const storedIdOf = (0, import_react23.useCallback)(
6380
+ const storedIdOf = (0, import_react24.useCallback)(
5950
6381
  async (messageId, threadId) => {
5951
6382
  const message = chatRef.current.messages.find((candidate) => candidate.id === messageId);
5952
6383
  const runOf = message?.metadata?.runId;
@@ -5957,7 +6388,7 @@ function useAgentChat(options = {}) {
5957
6388
  },
5958
6389
  [client]
5959
6390
  );
5960
- const fork = (0, import_react23.useCallback)(
6391
+ const fork = (0, import_react24.useCallback)(
5961
6392
  async ({
5962
6393
  messageId,
5963
6394
  threadId
@@ -5972,7 +6403,7 @@ function useAgentChat(options = {}) {
5972
6403
  },
5973
6404
  [client, currentThreadId, storedIdOf]
5974
6405
  );
5975
- const truncateFrom = (0, import_react23.useCallback)(
6406
+ const truncateFrom = (0, import_react24.useCallback)(
5976
6407
  async ({ messageId, threadId }) => {
5977
6408
  const target = threadId ?? currentThreadId();
5978
6409
  if (target === void 0) throw new Error("truncateFrom: this chat has no thread yet");
@@ -5981,7 +6412,7 @@ function useAgentChat(options = {}) {
5981
6412
  },
5982
6413
  [client, currentThreadId, storedIdOf]
5983
6414
  );
5984
- const promote = (0, import_react23.useCallback)(
6415
+ const promote = (0, import_react24.useCallback)(
5985
6416
  async ({ threadId } = {}) => {
5986
6417
  const target = threadId ?? currentThreadId();
5987
6418
  if (target === void 0) throw new Error("promote: this chat has no thread yet");
@@ -5990,24 +6421,24 @@ function useAgentChat(options = {}) {
5990
6421
  },
5991
6422
  [client, currentThreadId]
5992
6423
  );
5993
- const [modelsWanted, setModelsWanted] = (0, import_react23.useState)(false);
5994
- const modelsWantedRef = (0, import_react23.useRef)(modelsWanted);
6424
+ const [modelsWanted, setModelsWanted] = (0, import_react24.useState)(false);
6425
+ const modelsWantedRef = (0, import_react24.useRef)(modelsWanted);
5995
6426
  modelsWantedRef.current = modelsWanted;
5996
6427
  const catalog = useModels({
5997
6428
  backend: client,
5998
6429
  ...options.agent !== void 0 ? { agent: options.agent } : {},
5999
6430
  enabled: modelsWanted && typeof client.listModels === "function"
6000
6431
  });
6001
- const wantModels = (0, import_react23.useCallback)(() => {
6432
+ const wantModels = (0, import_react24.useCallback)(() => {
6002
6433
  if (modelsWantedRef.current) return;
6003
6434
  modelsWantedRef.current = true;
6004
6435
  queueMicrotask(() => setModelsWanted(true));
6005
6436
  }, []);
6006
6437
  lockedRef.current = catalog.locked !== null;
6007
- const selectModel = (0, import_react23.useCallback)((id) => {
6438
+ const selectModel = (0, import_react24.useCallback)((id) => {
6008
6439
  if (!lockedRef.current) setPickedModel(id);
6009
6440
  }, []);
6010
- const pinToThread = (0, import_react23.useCallback)(
6441
+ const pinToThread = (0, import_react24.useCallback)(
6011
6442
  async (model) => {
6012
6443
  const threadId = currentThreadId();
6013
6444
  setThreadModel(model);
@@ -6047,14 +6478,14 @@ function useAgentChat(options = {}) {
6047
6478
  };
6048
6479
  const status = connection.status === "reconnecting" ? "reconnecting" : chat.status;
6049
6480
  const isBusy = status === "submitted" || status === "streaming" || status === "reconnecting";
6050
- const isBusyRef = (0, import_react23.useRef)(isBusy);
6481
+ const isBusyRef = (0, import_react24.useRef)(isBusy);
6051
6482
  isBusyRef.current = isBusy;
6052
6483
  const files = useAttachments({ ...options.composer, backend: client });
6053
- const [text, setText] = (0, import_react23.useState)("");
6484
+ const [text, setText] = (0, import_react24.useState)("");
6054
6485
  const blockedBy = blocked != null ? "quota" : files.isUploading ? "uploading" : isBusy && whileRunning === "block" ? "busy" : text.trim().length === 0 && files.refs.length === 0 ? "empty" : null;
6055
- const composerRef = (0, import_react23.useRef)({ text, files, blockedBy });
6486
+ const composerRef = (0, import_react24.useRef)({ text, files, blockedBy });
6056
6487
  composerRef.current = { text, files, blockedBy };
6057
- const submit = (0, import_react23.useCallback)(
6488
+ const submit = (0, import_react24.useCallback)(
6058
6489
  async (options2) => {
6059
6490
  const current = composerRef.current;
6060
6491
  const asked = canQueueRef.current ? options2?.mode : void 0;
@@ -6136,6 +6567,7 @@ function useAgentChat(options = {}) {
6136
6567
  addToolResult,
6137
6568
  /** Sub-agents this conversation started and did not wait for. */
6138
6569
  background,
6570
+ proposals,
6139
6571
  runId,
6140
6572
  /** The loaded thread's running turn, or `null` once read with none. */
6141
6573
  activeRunId,
@@ -6260,8 +6692,10 @@ function isRunNotActiveError(error) {
6260
6692
  onThreadsEvent,
6261
6693
  persistSpeechLang,
6262
6694
  phraseFor,
6695
+ proposalNeedsPolling,
6263
6696
  readPath,
6264
6697
  readReasoningMs,
6698
+ reconcileProposalMessages,
6265
6699
  reframeAgUiStream,
6266
6700
  requireBackendMethod,
6267
6701
  resolveResultView,
@@ -6269,9 +6703,11 @@ function isRunNotActiveError(error) {
6269
6703
  storedThreadToUiMessages,
6270
6704
  toolCallState,
6271
6705
  toolCatalogFrom,
6706
+ useActionProposals,
6272
6707
  useAgentBackend,
6273
6708
  useAgentChat,
6274
6709
  useAgentConfig,
6710
+ useAgentUiCapabilities,
6275
6711
  useAgents,
6276
6712
  useAmbientRenderUi,
6277
6713
  useApprovalCountdown,