@dudousxd/nestjs-agent-react 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -74,11 +74,13 @@ __export(src_exports, {
74
74
  toolCallState: () => toolCallState,
75
75
  toolCatalogFrom: () => toolCatalogFrom,
76
76
  useAgentChat: () => useAgentChat,
77
+ useAgents: () => useAgents,
77
78
  useApprovalCountdown: () => useApprovalCountdown,
78
79
  useChatTranscript: () => useChatTranscript,
79
80
  useComposerAutocomplete: () => useComposerAutocomplete,
80
81
  useElapsed: () => useElapsed,
81
82
  useMessageFeedback: () => useMessageFeedback,
83
+ useModels: () => useModels,
82
84
  useSpeechRecognition: () => useSpeechRecognition,
83
85
  useStickToBottom: () => useStickToBottom,
84
86
  useThreads: () => useThreads,
@@ -235,6 +237,15 @@ var AgentClient = class {
235
237
  truncateFromMessage(threadId, messageId) {
236
238
  return this.request("DELETE", `/agent/threads/${encodeURIComponent(threadId)}/from/${encodeURIComponent(messageId)}`);
237
239
  }
240
+ /** `GET /agent/models?agent=` — the models this caller may pick, grouped by provider. */
241
+ listModels(agent) {
242
+ const query = agent === void 0 ? "" : `?agent=${encodeURIComponent(agent)}`;
243
+ return this.request("GET", `/agent/models${query}`);
244
+ }
245
+ /** `GET /agent/agents` — the registered agents, the default one flagged. */
246
+ listAgents() {
247
+ return this.request("GET", "/agent/agents");
248
+ }
238
249
  getQuotaToday() {
239
250
  return this.request("GET", "/agent/quota/today");
240
251
  }
@@ -1082,28 +1093,128 @@ function requireBackendMethod(backend, name) {
1082
1093
  }
1083
1094
  __name(requireBackendMethod, "requireBackendMethod");
1084
1095
 
1085
- // src/feedback/use-message-feedback.ts
1096
+ // src/catalog/use-agents.ts
1097
+ var import_react3 = require("react");
1098
+
1099
+ // src/catalog/use-resource.ts
1086
1100
  var import_react2 = require("react");
1101
+ function useResource(load2, key, enabled) {
1102
+ const [data, setData] = (0, import_react2.useState)(void 0);
1103
+ const [isLoading, setIsLoading] = (0, import_react2.useState)(enabled);
1104
+ const [error, setError] = (0, import_react2.useState)(null);
1105
+ const loadRef = (0, import_react2.useRef)(load2);
1106
+ loadRef.current = load2;
1107
+ const generation = (0, import_react2.useRef)(0);
1108
+ const refresh = (0, import_react2.useCallback)(async () => {
1109
+ const mine = ++generation.current;
1110
+ setIsLoading(true);
1111
+ try {
1112
+ const value = await loadRef.current();
1113
+ if (mine !== generation.current) return;
1114
+ setData(value);
1115
+ setError(null);
1116
+ } catch (caught) {
1117
+ if (mine !== generation.current) return;
1118
+ setError(caught instanceof Error ? caught : new Error(String(caught)));
1119
+ } finally {
1120
+ if (mine === generation.current) setIsLoading(false);
1121
+ }
1122
+ }, []);
1123
+ (0, import_react2.useEffect)(() => {
1124
+ if (!enabled) return;
1125
+ void refresh();
1126
+ }, [
1127
+ enabled,
1128
+ key,
1129
+ refresh
1130
+ ]);
1131
+ return {
1132
+ data,
1133
+ isLoading,
1134
+ error,
1135
+ refresh
1136
+ };
1137
+ }
1138
+ __name(useResource, "useResource");
1139
+
1140
+ // src/catalog/use-agents.ts
1141
+ function useAgents(options) {
1142
+ const { backend, enabled = true } = options;
1143
+ const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "listAgents")(), "", enabled);
1144
+ return (0, import_react3.useMemo)(() => {
1145
+ const agents = data ?? [];
1146
+ return {
1147
+ agents,
1148
+ defaultAgent: agents.find((agent) => agent.isDefault === true)?.name ?? null,
1149
+ isLoading,
1150
+ error,
1151
+ refresh
1152
+ };
1153
+ }, [
1154
+ data,
1155
+ isLoading,
1156
+ error,
1157
+ refresh
1158
+ ]);
1159
+ }
1160
+ __name(useAgents, "useAgents");
1161
+
1162
+ // src/catalog/use-models.ts
1163
+ var import_react4 = require("react");
1164
+ function useModels(options) {
1165
+ const { backend, agent, enabled = true } = options;
1166
+ const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "listModels")(agent), `${agent ?? ""}`, enabled);
1167
+ return (0, import_react4.useMemo)(() => {
1168
+ const providers = data?.providers ?? [];
1169
+ const models = providers.flatMap((provider) => provider.models.map((model) => ({
1170
+ ...model,
1171
+ providerId: provider.id,
1172
+ providerLabel: provider.label
1173
+ })));
1174
+ const byId = new Map(models.map((model) => [
1175
+ model.id,
1176
+ model
1177
+ ]));
1178
+ return {
1179
+ providers,
1180
+ models,
1181
+ defaultModel: data?.default ?? null,
1182
+ find: /* @__PURE__ */ __name((id) => id == null ? void 0 : byId.get(id), "find"),
1183
+ isLoading,
1184
+ error,
1185
+ refresh
1186
+ };
1187
+ }, [
1188
+ data,
1189
+ isLoading,
1190
+ error,
1191
+ refresh
1192
+ ]);
1193
+ }
1194
+ __name(useModels, "useModels");
1195
+
1196
+ // src/feedback/use-message-feedback.ts
1197
+ var import_react5 = require("react");
1087
1198
  function useMessageFeedback(options) {
1088
- const latest = (0, import_react2.useRef)(options);
1199
+ const latest = (0, import_react5.useRef)(options);
1089
1200
  latest.current = options;
1090
- const [local, setLocal] = (0, import_react2.useState)(/* @__PURE__ */ new Map());
1091
- const [pending, setPending] = (0, import_react2.useState)(/* @__PURE__ */ new Set());
1092
- const [error, setError] = (0, import_react2.useState)(null);
1093
- const localRef = (0, import_react2.useRef)(local);
1201
+ const [local, setLocal] = (0, import_react5.useState)(/* @__PURE__ */ new Map());
1202
+ const [pending, setPending] = (0, import_react5.useState)(/* @__PURE__ */ new Set());
1203
+ const [error, setError] = (0, import_react5.useState)(null);
1204
+ const localRef = (0, import_react5.useRef)(local);
1094
1205
  localRef.current = local;
1095
- const resolved = (0, import_react2.useRef)(/* @__PURE__ */ new Map());
1096
- const feedbackOf = (0, import_react2.useCallback)((message) => {
1206
+ const resolved = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
1207
+ const feedbackOf = (0, import_react5.useCallback)((message) => {
1097
1208
  const mine = local.get(message.id);
1098
1209
  if (mine !== void 0) return mine.feedback;
1099
1210
  return metadataOf(message).feedback ?? null;
1100
1211
  }, [
1101
1212
  local
1102
1213
  ]);
1103
- const isPending = (0, import_react2.useCallback)((message) => pending.has(message.id), [
1214
+ const isPending = (0, import_react5.useCallback)((message) => pending.has(message.id), [
1104
1215
  pending
1105
1216
  ]);
1106
- const storedIdFor = (0, import_react2.useCallback)(async (message) => {
1217
+ const storedIdFor = (0, import_react5.useCallback)(async (message) => {
1107
1218
  const runId = metadataOf(message).runId;
1108
1219
  if (runId === void 0) return message.id;
1109
1220
  const known = resolved.current.get(message.id);
@@ -1123,7 +1234,7 @@ function useMessageFeedback(options) {
1123
1234
  resolved.current.set(message.id, row.id);
1124
1235
  return row.id;
1125
1236
  }, []);
1126
- const rate = (0, import_react2.useCallback)(async (message, value, comment) => {
1237
+ const rate = (0, import_react5.useCallback)(async (message, value, comment) => {
1127
1238
  const setFeedback = requireBackendMethod(latest.current.backend, "setMessageFeedback");
1128
1239
  const had = localRef.current.get(message.id);
1129
1240
  const optimistic = value === null ? null : {
@@ -1169,7 +1280,7 @@ function useMessageFeedback(options) {
1169
1280
  }, [
1170
1281
  storedIdFor
1171
1282
  ]);
1172
- const toggle = (0, import_react2.useCallback)((message, value) => {
1283
+ const toggle = (0, import_react5.useCallback)((message, value) => {
1173
1284
  const mine = localRef.current.get(message.id);
1174
1285
  const current = mine !== void 0 ? mine.feedback : metadataOf(message).feedback ?? null;
1175
1286
  return rate(message, current?.value === value ? null : value);
@@ -1213,16 +1324,16 @@ function onThreadsEvent(backend, listener) {
1213
1324
  __name(onThreadsEvent, "onThreadsEvent");
1214
1325
 
1215
1326
  // src/threads/use-threads.ts
1216
- var import_react3 = require("react");
1327
+ var import_react6 = require("react");
1217
1328
  function useThreads(options) {
1218
1329
  const { backend, enabled = true } = options;
1219
- const [threads, setThreads] = (0, import_react3.useState)([]);
1220
- const [isLoading, setIsLoading] = (0, import_react3.useState)(enabled);
1221
- const [error, setError] = (0, import_react3.useState)(null);
1222
- const threadsRef = (0, import_react3.useRef)(threads);
1330
+ const [threads, setThreads] = (0, import_react6.useState)([]);
1331
+ const [isLoading, setIsLoading] = (0, import_react6.useState)(enabled);
1332
+ const [error, setError] = (0, import_react6.useState)(null);
1333
+ const threadsRef = (0, import_react6.useRef)(threads);
1223
1334
  threadsRef.current = threads;
1224
- const generation = (0, import_react3.useRef)(0);
1225
- const refresh = (0, import_react3.useCallback)(async () => {
1335
+ const generation = (0, import_react6.useRef)(0);
1336
+ const refresh = (0, import_react6.useCallback)(async () => {
1226
1337
  const mine = ++generation.current;
1227
1338
  setIsLoading(true);
1228
1339
  try {
@@ -1239,7 +1350,7 @@ function useThreads(options) {
1239
1350
  }, [
1240
1351
  backend
1241
1352
  ]);
1242
- (0, import_react3.useEffect)(() => {
1353
+ (0, import_react6.useEffect)(() => {
1243
1354
  if (!enabled) return;
1244
1355
  void refresh();
1245
1356
  return onThreadsEvent(backend, (event) => {
@@ -1259,7 +1370,7 @@ function useThreads(options) {
1259
1370
  enabled,
1260
1371
  refresh
1261
1372
  ]);
1262
- const rename = (0, import_react3.useCallback)(async (id, title) => {
1373
+ const rename = (0, import_react6.useCallback)(async (id, title) => {
1263
1374
  const before = threadsRef.current;
1264
1375
  setThreads((current) => current.map((thread) => thread.id === id ? {
1265
1376
  ...thread,
@@ -1281,7 +1392,7 @@ function useThreads(options) {
1281
1392
  }, [
1282
1393
  backend
1283
1394
  ]);
1284
- const remove = (0, import_react3.useCallback)(async (id) => {
1395
+ const remove = (0, import_react6.useCallback)(async (id) => {
1285
1396
  const before = threadsRef.current;
1286
1397
  setThreads((current) => current.filter((thread) => thread.id !== id));
1287
1398
  try {
@@ -1356,10 +1467,10 @@ function backgroundRunsFromThread(messages) {
1356
1467
  __name(backgroundRunsFromThread, "backgroundRunsFromThread");
1357
1468
 
1358
1469
  // src/components/chat-input.tsx
1359
- var import_react5 = __toESM(require("react"), 1);
1470
+ var import_react8 = __toESM(require("react"), 1);
1360
1471
 
1361
1472
  // src/components/use-speech-recognition.ts
1362
- var import_react4 = require("react");
1473
+ var import_react7 = require("react");
1363
1474
  function getRecognitionCtor() {
1364
1475
  if (typeof window === "undefined") return null;
1365
1476
  const scope = window;
@@ -1367,15 +1478,15 @@ function getRecognitionCtor() {
1367
1478
  }
1368
1479
  __name(getRecognitionCtor, "getRecognitionCtor");
1369
1480
  function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTranscript }) {
1370
- const recognitionRef = (0, import_react4.useRef)(null);
1371
- const [isListening, setIsListening] = (0, import_react4.useState)(false);
1372
- const ctor = (0, import_react4.useMemo)(() => getRecognitionCtor(), []);
1481
+ const recognitionRef = (0, import_react7.useRef)(null);
1482
+ const [isListening, setIsListening] = (0, import_react7.useState)(false);
1483
+ const ctor = (0, import_react7.useMemo)(() => getRecognitionCtor(), []);
1373
1484
  const isSupported = ctor !== null;
1374
- const finalRef = (0, import_react4.useRef)(onFinalTranscript);
1375
- const interimRef = (0, import_react4.useRef)(onInterimTranscript);
1485
+ const finalRef = (0, import_react7.useRef)(onFinalTranscript);
1486
+ const interimRef = (0, import_react7.useRef)(onInterimTranscript);
1376
1487
  finalRef.current = onFinalTranscript;
1377
1488
  interimRef.current = onInterimTranscript;
1378
- (0, import_react4.useEffect)(() => {
1489
+ (0, import_react7.useEffect)(() => {
1379
1490
  if (!ctor) return;
1380
1491
  const recognition = new ctor();
1381
1492
  recognition.lang = lang;
@@ -1414,7 +1525,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
1414
1525
  ctor,
1415
1526
  lang
1416
1527
  ]);
1417
- const start = (0, import_react4.useCallback)(() => {
1528
+ const start = (0, import_react7.useCallback)(() => {
1418
1529
  const recognition = recognitionRef.current;
1419
1530
  if (!recognition) return;
1420
1531
  try {
@@ -1424,7 +1535,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
1424
1535
  console.warn("SpeechRecognition start failed", error);
1425
1536
  }
1426
1537
  }, []);
1427
- const stop = (0, import_react4.useCallback)(() => {
1538
+ const stop = (0, import_react7.useCallback)(() => {
1428
1539
  const recognition = recognitionRef.current;
1429
1540
  if (!recognition) return;
1430
1541
  try {
@@ -1443,8 +1554,8 @@ __name(useSpeechRecognition, "useSpeechRecognition");
1443
1554
 
1444
1555
  // src/components/chat-input.tsx
1445
1556
  function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = true, speechLang = "en-US", sendLabel = "Send", onStop, isStreaming = false, stopLabel = "Stop generating", className, textareaClassName, sendButtonClassName, micButtonClassName, stopButtonClassName, renderMic }) {
1446
- const [value, setValue] = (0, import_react5.useState)("");
1447
- const [interim, setInterim] = (0, import_react5.useState)("");
1557
+ const [value, setValue] = (0, import_react8.useState)("");
1558
+ const [interim, setInterim] = (0, import_react8.useState)("");
1448
1559
  const speech = useSpeechRecognition({
1449
1560
  lang: speechLang,
1450
1561
  onFinalTranscript: /* @__PURE__ */ __name((text) => {
@@ -1455,7 +1566,7 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
1455
1566
  }, "onFinalTranscript"),
1456
1567
  onInterimTranscript: /* @__PURE__ */ __name((text) => setInterim(text), "onInterimTranscript")
1457
1568
  });
1458
- (0, import_react5.useEffect)(() => {
1569
+ (0, import_react8.useEffect)(() => {
1459
1570
  if (!speech.isListening) setInterim("");
1460
1571
  }, [
1461
1572
  speech.isListening
@@ -1483,9 +1594,9 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
1483
1594
  const displayValue = speech.isListening && interim ? `${value}${value && !value.endsWith(" ") ? " " : ""}${interim}` : value;
1484
1595
  const showMic = enableSpeech && speech.isSupported;
1485
1596
  const showStop = isStreaming && onStop !== void 0;
1486
- return /* @__PURE__ */ import_react5.default.createElement("div", {
1597
+ return /* @__PURE__ */ import_react8.default.createElement("div", {
1487
1598
  className
1488
- }, /* @__PURE__ */ import_react5.default.createElement("textarea", {
1599
+ }, /* @__PURE__ */ import_react8.default.createElement("textarea", {
1489
1600
  className: textareaClassName,
1490
1601
  rows,
1491
1602
  value: displayValue,
@@ -1496,17 +1607,17 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
1496
1607
  }, "onChange"),
1497
1608
  onKeyDown: handleKeyDown,
1498
1609
  placeholder: placeholder ?? "Ask something (Enter to send, Shift+Enter for newline)"
1499
- }), /* @__PURE__ */ import_react5.default.createElement("button", {
1610
+ }), /* @__PURE__ */ import_react8.default.createElement("button", {
1500
1611
  type: "button",
1501
1612
  className: sendButtonClassName,
1502
1613
  onClick: submit,
1503
1614
  disabled: disabled || !value.trim()
1504
- }, sendLabel), showStop ? /* @__PURE__ */ import_react5.default.createElement("button", {
1615
+ }, sendLabel), showStop ? /* @__PURE__ */ import_react8.default.createElement("button", {
1505
1616
  type: "button",
1506
1617
  className: stopButtonClassName,
1507
1618
  onClick: /* @__PURE__ */ __name(() => void onStop(), "onClick"),
1508
1619
  "aria-label": "Stop generating"
1509
- }, stopLabel) : null, showMic ? /* @__PURE__ */ import_react5.default.createElement("button", {
1620
+ }, stopLabel) : null, showMic ? /* @__PURE__ */ import_react8.default.createElement("button", {
1510
1621
  type: "button",
1511
1622
  className: micButtonClassName,
1512
1623
  onClick: toggleMic,
@@ -1519,10 +1630,10 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
1519
1630
  __name(ChatInput, "ChatInput");
1520
1631
 
1521
1632
  // src/components/message-item.tsx
1522
- var import_react8 = __toESM(require("react"), 1);
1633
+ var import_react11 = __toESM(require("react"), 1);
1523
1634
 
1524
1635
  // src/transcript/use-chat-transcript.ts
1525
- var import_react7 = require("react");
1636
+ var import_react10 = require("react");
1526
1637
 
1527
1638
  // src/transcript/model.ts
1528
1639
  var import_nestjs_agent_core2 = require("@dudousxd/nestjs-agent-core");
@@ -2499,11 +2610,11 @@ function formatCostUsd(cost) {
2499
2610
  __name(formatCostUsd, "formatCostUsd");
2500
2611
 
2501
2612
  // src/transcript/use-stick-to-bottom.ts
2502
- var import_react6 = require("react");
2613
+ var import_react9 = require("react");
2503
2614
  function useStickToBottom({ contentKey, threshold = 32 }) {
2504
- const containerRef = (0, import_react6.useRef)(null);
2505
- const [isAtBottom, setIsAtBottom] = (0, import_react6.useState)(true);
2506
- const measure = (0, import_react6.useCallback)(() => {
2615
+ const containerRef = (0, import_react9.useRef)(null);
2616
+ const [isAtBottom, setIsAtBottom] = (0, import_react9.useState)(true);
2617
+ const measure = (0, import_react9.useCallback)(() => {
2507
2618
  const element = containerRef.current;
2508
2619
  if (!element) {
2509
2620
  return;
@@ -2513,7 +2624,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
2513
2624
  }, [
2514
2625
  threshold
2515
2626
  ]);
2516
- const scrollToBottom = (0, import_react6.useCallback)(() => {
2627
+ const scrollToBottom = (0, import_react9.useCallback)(() => {
2517
2628
  const element = containerRef.current;
2518
2629
  if (!element) {
2519
2630
  return;
@@ -2521,7 +2632,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
2521
2632
  element.scrollTop = element.scrollHeight;
2522
2633
  setIsAtBottom(true);
2523
2634
  }, []);
2524
- const setContainer = (0, import_react6.useCallback)((element) => {
2635
+ const setContainer = (0, import_react9.useCallback)((element) => {
2525
2636
  containerRef.current = element;
2526
2637
  if (element) {
2527
2638
  measure();
@@ -2529,7 +2640,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
2529
2640
  }, [
2530
2641
  measure
2531
2642
  ]);
2532
- (0, import_react6.useEffect)(() => {
2643
+ (0, import_react9.useEffect)(() => {
2533
2644
  if (isAtBottom) {
2534
2645
  scrollToBottom();
2535
2646
  }
@@ -2538,7 +2649,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
2538
2649
  isAtBottom,
2539
2650
  scrollToBottom
2540
2651
  ]);
2541
- const getContainerProps = (0, import_react6.useCallback)(() => ({
2652
+ const getContainerProps = (0, import_react9.useCallback)(() => ({
2542
2653
  ref: setContainer,
2543
2654
  onScroll: measure
2544
2655
  }), [
@@ -2560,14 +2671,14 @@ var DEFAULT_LOAD_EARLIER_STEP = 50;
2560
2671
  var DEFAULT_COPY_RESET_MS = 1500;
2561
2672
  function useChatTranscript(options) {
2562
2673
  const { messages, status, initialVisibleCount = DEFAULT_VISIBLE_COUNT, loadEarlierStep = DEFAULT_LOAD_EARLIER_STEP, followUps, stickToBottomThreshold } = options;
2563
- const latest = (0, import_react7.useRef)(options);
2674
+ const latest = (0, import_react10.useRef)(options);
2564
2675
  latest.current = options;
2565
- const [visibleCount, setVisibleCount] = (0, import_react7.useState)(initialVisibleCount);
2566
- const [stopRequested, setStopRequested] = (0, import_react7.useState)(false);
2676
+ const [visibleCount, setVisibleCount] = (0, import_react10.useState)(initialVisibleCount);
2677
+ const [stopRequested, setStopRequested] = (0, import_react10.useState)(false);
2567
2678
  const isStreaming = status === "streaming" || status === "reconnecting";
2568
2679
  const isBusy = status === "submitted" || isStreaming;
2569
2680
  const isEmpty = messages.length === 0;
2570
- (0, import_react7.useEffect)(() => {
2681
+ (0, import_react10.useEffect)(() => {
2571
2682
  if (!isBusy) {
2572
2683
  setStopRequested(false);
2573
2684
  }
@@ -2584,7 +2695,7 @@ function useChatTranscript(options) {
2584
2695
  streamingMessageId,
2585
2696
  options
2586
2697
  });
2587
- const stop = (0, import_react7.useCallback)(() => {
2698
+ const stop = (0, import_react10.useCallback)(() => {
2588
2699
  const current = latest.current;
2589
2700
  if (current.status !== "submitted" && current.status !== "streaming" && current.status !== "reconnecting") {
2590
2701
  return;
@@ -2592,8 +2703,8 @@ function useChatTranscript(options) {
2592
2703
  setStopRequested(true);
2593
2704
  void current.onStop?.();
2594
2705
  }, []);
2595
- const loadEarlier = (0, import_react7.useCallback)(() => setVisibleCount((count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP)), []);
2596
- const showAll = (0, import_react7.useCallback)(() => setVisibleCount(latest.current.messages.length), []);
2706
+ const loadEarlier = (0, import_react10.useCallback)(() => setVisibleCount((count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP)), []);
2707
+ const showAll = (0, import_react10.useCallback)(() => setVisibleCount(latest.current.messages.length), []);
2597
2708
  const scroll = useStickToBottom({
2598
2709
  contentKey: contentSignature(messages),
2599
2710
  ...stickToBottomThreshold !== void 0 ? {
@@ -2629,7 +2740,7 @@ function useChatTranscript(options) {
2629
2740
  __name(useChatTranscript, "useChatTranscript");
2630
2741
  function useTranscriptItem(options) {
2631
2742
  const { message, isStreaming = false } = options;
2632
- const messagesRef = (0, import_react7.useRef)([
2743
+ const messagesRef = (0, import_react10.useRef)([
2633
2744
  message
2634
2745
  ]);
2635
2746
  if (messagesRef.current[0] !== message) {
@@ -2647,13 +2758,13 @@ function useTranscriptItem(options) {
2647
2758
  }
2648
2759
  __name(useTranscriptItem, "useTranscriptItem");
2649
2760
  function useTranscriptItems({ messages, visibleStart, streamingMessageId, options }) {
2650
- const [drafts, setDrafts] = (0, import_react7.useState)(() => /* @__PURE__ */ new Map());
2651
- const [copied, setCopied] = (0, import_react7.useState)(() => /* @__PURE__ */ new Set());
2652
- const [openReasoning, setOpenReasoning] = (0, import_react7.useState)(() => /* @__PURE__ */ new Map());
2653
- const [picks, setPicks] = (0, import_react7.useState)(() => /* @__PURE__ */ new Map());
2654
- const [settling, setSettling] = (0, import_react7.useState)(() => /* @__PURE__ */ new Map());
2655
- const [settleErrors, setSettleErrors] = (0, import_react7.useState)(() => /* @__PURE__ */ new Map());
2656
- const latest = (0, import_react7.useRef)({
2761
+ const [drafts, setDrafts] = (0, import_react10.useState)(() => /* @__PURE__ */ new Map());
2762
+ const [copied, setCopied] = (0, import_react10.useState)(() => /* @__PURE__ */ new Set());
2763
+ const [openReasoning, setOpenReasoning] = (0, import_react10.useState)(() => /* @__PURE__ */ new Map());
2764
+ const [picks, setPicks] = (0, import_react10.useState)(() => /* @__PURE__ */ new Map());
2765
+ const [settling, setSettling] = (0, import_react10.useState)(() => /* @__PURE__ */ new Map());
2766
+ const [settleErrors, setSettleErrors] = (0, import_react10.useState)(() => /* @__PURE__ */ new Map());
2767
+ const latest = (0, import_react10.useRef)({
2657
2768
  options,
2658
2769
  drafts,
2659
2770
  picks,
@@ -2665,23 +2776,23 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
2665
2776
  picks,
2666
2777
  messages
2667
2778
  };
2668
- const copyTimers = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
2669
- (0, import_react7.useEffect)(() => () => {
2779
+ const copyTimers = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
2780
+ (0, import_react10.useEffect)(() => () => {
2670
2781
  for (const timer of copyTimers.current.values()) {
2671
2782
  clearTimeout(timer);
2672
2783
  }
2673
2784
  copyTimers.current.clear();
2674
2785
  }, []);
2675
- const callbackCache = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
2676
- const reasoningToggleCache = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
2677
- const toggleReasoning = (0, import_react7.useCallback)((key, open) => {
2786
+ const callbackCache = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
2787
+ const reasoningToggleCache = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
2788
+ const toggleReasoning = (0, import_react10.useCallback)((key, open) => {
2678
2789
  setOpenReasoning((current) => {
2679
2790
  const next = new Map(current);
2680
2791
  next.set(key, open ?? !(current.get(key) ?? false));
2681
2792
  return next;
2682
2793
  });
2683
2794
  }, []);
2684
- const stableToggle = (0, import_react7.useCallback)((key) => {
2795
+ const stableToggle = (0, import_react10.useCallback)((key) => {
2685
2796
  let cached = reasoningToggleCache.current.get(key);
2686
2797
  if (!cached) {
2687
2798
  cached = /* @__PURE__ */ __name((open) => toggleReasoning(key, open), "cached");
@@ -2691,10 +2802,10 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
2691
2802
  }, [
2692
2803
  toggleReasoning
2693
2804
  ]);
2694
- const pick = (0, import_react7.useCallback)((toolCallId, questionId, values) => {
2805
+ const pick = (0, import_react10.useCallback)((toolCallId, questionId, values) => {
2695
2806
  setPicks((current) => new Map(current).set(pickKey(toolCallId, questionId), values));
2696
2807
  }, []);
2697
- const settle = (0, import_react7.useCallback)((toolCallId, action, send) => {
2808
+ const settle = (0, import_react10.useCallback)((toolCallId, action, send) => {
2698
2809
  setSettleErrors((current) => {
2699
2810
  if (!current.has(toolCallId)) {
2700
2811
  return current;
@@ -2718,7 +2829,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
2718
2829
  failed(error);
2719
2830
  }
2720
2831
  }, []);
2721
- const answer = (0, import_react7.useCallback)((toolCallId) => {
2832
+ const answer = (0, import_react10.useCallback)((toolCallId) => {
2722
2833
  const current = latest.current;
2723
2834
  const onAnswer = current.options.onAnswer;
2724
2835
  if (!onAnswer) {
@@ -2728,7 +2839,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
2728
2839
  }, [
2729
2840
  settle
2730
2841
  ]);
2731
- const skip = (0, import_react7.useCallback)((toolCallId) => {
2842
+ const skip = (0, import_react10.useCallback)((toolCallId) => {
2732
2843
  const onSkip = latest.current.options.onSkip;
2733
2844
  if (onSkip) {
2734
2845
  settle(toolCallId, "skip", () => onSkip(toolCallId));
@@ -2736,7 +2847,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
2736
2847
  }, [
2737
2848
  settle
2738
2849
  ]);
2739
- const approve = (0, import_react7.useCallback)((toolCallId, options2) => {
2850
+ const approve = (0, import_react10.useCallback)((toolCallId, options2) => {
2740
2851
  const onApprove = latest.current.options.onApprove;
2741
2852
  if (onApprove) {
2742
2853
  settle(toolCallId, "approve", () => options2 === void 0 ? onApprove(toolCallId) : onApprove(toolCallId, options2));
@@ -2744,7 +2855,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
2744
2855
  }, [
2745
2856
  settle
2746
2857
  ]);
2747
- const reject = (0, import_react7.useCallback)((toolCallId) => {
2858
+ const reject = (0, import_react10.useCallback)((toolCallId) => {
2748
2859
  const onReject = latest.current.options.onReject;
2749
2860
  if (onReject) {
2750
2861
  settle(toolCallId, "reject", () => onReject(toolCallId));
@@ -2752,7 +2863,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
2752
2863
  }, [
2753
2864
  settle
2754
2865
  ]);
2755
- const callbacksFor = (0, import_react7.useCallback)((id) => {
2866
+ const callbacksFor = (0, import_react10.useCallback)((id) => {
2756
2867
  const cached = callbackCache.current.get(id);
2757
2868
  if (cached) {
2758
2869
  return cached;
@@ -2994,7 +3105,7 @@ function MessageItem({ message, isStreaming = false, editable, onEditSubmit, reg
2994
3105
  getCreatedAt: /* @__PURE__ */ __name(() => createdAt, "getCreatedAt")
2995
3106
  } : {}
2996
3107
  });
2997
- return /* @__PURE__ */ import_react8.default.createElement(MessageItemView, {
3108
+ return /* @__PURE__ */ import_react11.default.createElement(MessageItemView, {
2998
3109
  item,
2999
3110
  ...slots
3000
3111
  });
@@ -3002,51 +3113,51 @@ function MessageItem({ message, isStreaming = false, editable, onEditSubmit, reg
3002
3113
  __name(MessageItem, "MessageItem");
3003
3114
  function MessageItemView({ item, ...slots }) {
3004
3115
  const { classNames } = slots;
3005
- const actionRow = /* @__PURE__ */ import_react8.default.createElement("div", {
3116
+ const actionRow = /* @__PURE__ */ import_react11.default.createElement("div", {
3006
3117
  className: classNames?.actions,
3007
3118
  "data-actions-for": item.role
3008
- }, item.copy.available ? /* @__PURE__ */ import_react8.default.createElement("button", {
3119
+ }, item.copy.available ? /* @__PURE__ */ import_react11.default.createElement("button", {
3009
3120
  type: "button",
3010
3121
  onClick: item.copy.copy,
3011
3122
  className: classNames?.actionButton,
3012
3123
  title: item.copy.copied ? "Copied!" : "Copy message text"
3013
- }, item.copy.copied ? "Copied" : "Copy") : null, item.fork.available ? /* @__PURE__ */ import_react8.default.createElement("button", {
3124
+ }, item.copy.copied ? "Copied" : "Copy") : null, item.fork.available ? /* @__PURE__ */ import_react11.default.createElement("button", {
3014
3125
  type: "button",
3015
3126
  onClick: item.fork.run,
3016
3127
  className: classNames?.actionButton,
3017
3128
  title: "Fork thread from this message"
3018
- }, "Fork") : null, item.regenerate.available ? /* @__PURE__ */ import_react8.default.createElement("button", {
3129
+ }, "Fork") : null, item.regenerate.available ? /* @__PURE__ */ import_react11.default.createElement("button", {
3019
3130
  type: "button",
3020
3131
  onClick: item.regenerate.run,
3021
3132
  className: classNames?.actionButton,
3022
3133
  title: "Regenerate response"
3023
- }, "Regenerate") : null, slots.meta, !item.isUser && item.usage ? /* @__PURE__ */ import_react8.default.createElement("span", {
3134
+ }, "Regenerate") : null, slots.meta, !item.isUser && item.usage ? /* @__PURE__ */ import_react11.default.createElement("span", {
3024
3135
  className: classNames?.usage,
3025
3136
  title: `Input ${item.usage.inputTokens.toLocaleString()} \xB7 Output ${item.usage.outputTokens.toLocaleString()} tokens`
3026
- }, item.usage.costLabel, " \xB7 ", item.usage.tokensLabel) : null, item.timestamp ? /* @__PURE__ */ import_react8.default.createElement("span", {
3137
+ }, item.usage.costLabel, " \xB7 ", item.usage.tokensLabel) : null, item.timestamp ? /* @__PURE__ */ import_react11.default.createElement("span", {
3027
3138
  className: classNames?.timestamp,
3028
3139
  title: item.timestamp.absolute
3029
3140
  }, item.timestamp.relative) : null);
3030
3141
  if (item.edit.available) {
3031
- return /* @__PURE__ */ import_react8.default.createElement(EditableUserBubble, {
3142
+ return /* @__PURE__ */ import_react11.default.createElement(EditableUserBubble, {
3032
3143
  item,
3033
3144
  slots,
3034
3145
  actions: actionRow
3035
3146
  });
3036
3147
  }
3037
3148
  const className = joinClasses(classNames?.root, classNames?.byRole?.[item.role]);
3038
- return /* @__PURE__ */ import_react8.default.createElement("div", {
3149
+ return /* @__PURE__ */ import_react11.default.createElement("div", {
3039
3150
  className,
3040
3151
  "data-role": item.role,
3041
3152
  "data-streaming": item.isStreaming ? "true" : void 0
3042
- }, /* @__PURE__ */ import_react8.default.createElement("div", null, renderBlocks(item, slots)), actionRow);
3153
+ }, /* @__PURE__ */ import_react11.default.createElement("div", null, renderBlocks(item, slots)), actionRow);
3043
3154
  }
3044
3155
  __name(MessageItemView, "MessageItemView");
3045
3156
  function renderBlocks(item, slots) {
3046
3157
  const nodes = [];
3047
3158
  for (const block of item.blocks) {
3048
3159
  if (block.kind === "text") {
3049
- nodes.push(/* @__PURE__ */ import_react8.default.createElement("div", {
3160
+ nodes.push(/* @__PURE__ */ import_react11.default.createElement("div", {
3050
3161
  key: block.key,
3051
3162
  className: slots.classNames?.text
3052
3163
  }, slots.renderText ? slots.renderText(block.text, {
@@ -3067,7 +3178,7 @@ function renderBlocks(item, slots) {
3067
3178
  continue;
3068
3179
  }
3069
3180
  if (block.kind === "ui" && slots.renderUi) {
3070
- nodes.push(/* @__PURE__ */ import_react8.default.createElement("div", {
3181
+ nodes.push(/* @__PURE__ */ import_react11.default.createElement("div", {
3071
3182
  key: block.key,
3072
3183
  "data-slot": "ui",
3073
3184
  "data-component": block.component
@@ -3078,18 +3189,18 @@ function renderBlocks(item, slots) {
3078
3189
  }
3079
3190
  __name(renderBlocks, "renderBlocks");
3080
3191
  function renderFilesBlock(block, slots) {
3081
- return /* @__PURE__ */ import_react8.default.createElement("div", {
3192
+ return /* @__PURE__ */ import_react11.default.createElement("div", {
3082
3193
  key: block.key,
3083
3194
  className: slots.classNames?.files,
3084
3195
  "data-files": "true"
3085
- }, slots.renderFiles ? slots.renderFiles(block.files) : block.files.map((file) => /* @__PURE__ */ import_react8.default.createElement("a", {
3196
+ }, slots.renderFiles ? slots.renderFiles(block.files) : block.files.map((file) => /* @__PURE__ */ import_react11.default.createElement("a", {
3086
3197
  key: file.url,
3087
3198
  href: file.url,
3088
3199
  target: "_blank",
3089
3200
  rel: "noreferrer",
3090
3201
  className: slots.classNames?.file,
3091
3202
  title: file.filename ?? file.mediaType
3092
- }, file.isImage ? /* @__PURE__ */ import_react8.default.createElement("img", {
3203
+ }, file.isImage ? /* @__PURE__ */ import_react11.default.createElement("img", {
3093
3204
  src: file.url,
3094
3205
  alt: file.filename ?? "image",
3095
3206
  className: slots.classNames?.fileImage
@@ -3097,17 +3208,17 @@ function renderFilesBlock(block, slots) {
3097
3208
  }
3098
3209
  __name(renderFilesBlock, "renderFilesBlock");
3099
3210
  function renderReasoningBlock(block, slots) {
3100
- return /* @__PURE__ */ import_react8.default.createElement("div", {
3211
+ return /* @__PURE__ */ import_react11.default.createElement("div", {
3101
3212
  key: block.key,
3102
3213
  className: slots.classNames?.reasoning,
3103
3214
  "data-reasoning": "true",
3104
3215
  "data-streaming": block.isStreaming ? "true" : void 0
3105
- }, /* @__PURE__ */ import_react8.default.createElement("button", {
3216
+ }, /* @__PURE__ */ import_react11.default.createElement("button", {
3106
3217
  type: "button",
3107
3218
  className: slots.classNames?.reasoningToggle,
3108
3219
  onClick: /* @__PURE__ */ __name(() => block.toggle(), "onClick"),
3109
3220
  "aria-expanded": block.isOpen
3110
- }, slots.reasoningLabel ?? "Reasoning"), block.isOpen ? /* @__PURE__ */ import_react8.default.createElement("div", {
3221
+ }, slots.reasoningLabel ?? "Reasoning"), block.isOpen ? /* @__PURE__ */ import_react11.default.createElement("div", {
3111
3222
  className: slots.classNames?.reasoningText
3112
3223
  }, slots.renderReasoning ? slots.renderReasoning(block.text, {
3113
3224
  isStreaming: block.isStreaming,
@@ -3118,7 +3229,7 @@ __name(renderReasoningBlock, "renderReasoningBlock");
3118
3229
  function renderToolBlock(item, block, slots) {
3119
3230
  if (slots.renderToolGroup) {
3120
3231
  return [
3121
- /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, {
3232
+ /* @__PURE__ */ import_react11.default.createElement(import_react11.default.Fragment, {
3122
3233
  key: block.key
3123
3234
  }, slots.renderToolGroup(block.parts, block.key))
3124
3235
  ];
@@ -3129,7 +3240,7 @@ function renderToolBlock(item, block, slots) {
3129
3240
  const renderToolPart = slots.renderToolPart;
3130
3241
  return block.parts.map((part) => {
3131
3242
  const partKey = `${item.id}-${part.toolCallId}`;
3132
- return /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, {
3243
+ return /* @__PURE__ */ import_react11.default.createElement(import_react11.default.Fragment, {
3133
3244
  key: partKey
3134
3245
  }, renderToolPart(part, partKey));
3135
3246
  });
@@ -3139,14 +3250,14 @@ function EditableUserBubble({ item, slots, actions }) {
3139
3250
  const { classNames } = slots;
3140
3251
  const { edit } = item;
3141
3252
  if (!edit.isEditing) {
3142
- return /* @__PURE__ */ import_react8.default.createElement("div", {
3253
+ return /* @__PURE__ */ import_react11.default.createElement("div", {
3143
3254
  className: joinClasses(classNames?.root, classNames?.byRole?.user),
3144
3255
  "data-role": "user"
3145
- }, /* @__PURE__ */ import_react8.default.createElement("div", {
3256
+ }, /* @__PURE__ */ import_react11.default.createElement("div", {
3146
3257
  className: classNames?.text
3147
3258
  }, slots.renderText ? slots.renderText(item.text, {
3148
3259
  isStreaming: false
3149
- }) : item.text), /* @__PURE__ */ import_react8.default.createElement("button", {
3260
+ }) : item.text), /* @__PURE__ */ import_react11.default.createElement("button", {
3150
3261
  type: "button",
3151
3262
  onClick: edit.start,
3152
3263
  className: classNames?.actionButton,
@@ -3154,18 +3265,18 @@ function EditableUserBubble({ item, slots, actions }) {
3154
3265
  }, "Edit"), actions);
3155
3266
  }
3156
3267
  const textareaProps = edit.getTextareaProps();
3157
- return /* @__PURE__ */ import_react8.default.createElement("div", {
3268
+ return /* @__PURE__ */ import_react11.default.createElement("div", {
3158
3269
  "data-editing": "true"
3159
- }, /* @__PURE__ */ import_react8.default.createElement("textarea", {
3270
+ }, /* @__PURE__ */ import_react11.default.createElement("textarea", {
3160
3271
  ...textareaProps,
3161
3272
  rows: Math.min(8, edit.draft.split("\n").length + 1),
3162
3273
  className: classNames?.editTextarea
3163
- }), /* @__PURE__ */ import_react8.default.createElement("div", {
3274
+ }), /* @__PURE__ */ import_react11.default.createElement("div", {
3164
3275
  className: classNames?.editActions
3165
- }, /* @__PURE__ */ import_react8.default.createElement("button", {
3276
+ }, /* @__PURE__ */ import_react11.default.createElement("button", {
3166
3277
  type: "button",
3167
3278
  onClick: edit.cancel
3168
- }, "Cancel"), /* @__PURE__ */ import_react8.default.createElement("button", {
3279
+ }, "Cancel"), /* @__PURE__ */ import_react11.default.createElement("button", {
3169
3280
  type: "button",
3170
3281
  onClick: edit.save,
3171
3282
  disabled: !edit.canSave
@@ -3409,35 +3520,35 @@ function toItem(entry) {
3409
3520
  __name(toItem, "toItem");
3410
3521
 
3411
3522
  // src/composer/use-composer-autocomplete.ts
3412
- var import_react9 = require("react");
3523
+ var import_react12 = require("react");
3413
3524
  function useComposerAutocomplete(options) {
3414
3525
  const { value, sources, acceptOnTab = true } = options;
3415
- const latest = (0, import_react9.useRef)(options);
3526
+ const latest = (0, import_react12.useRef)(options);
3416
3527
  latest.current = options;
3417
- const inputRef = (0, import_react9.useRef)(null);
3418
- const [caret, setCaret] = (0, import_react9.useState)(value.length);
3419
- const [items, setItems] = (0, import_react9.useState)([]);
3420
- const [isLoading, setLoading] = (0, import_react9.useState)(false);
3421
- const [error, setError] = (0, import_react9.useState)(null);
3422
- const [activeIndex, setActiveIndex] = (0, import_react9.useState)(0);
3423
- const [dismissedIndex, setDismissedIndex] = (0, import_react9.useState)(null);
3528
+ const inputRef = (0, import_react12.useRef)(null);
3529
+ const [caret, setCaret] = (0, import_react12.useState)(value.length);
3530
+ const [items, setItems] = (0, import_react12.useState)([]);
3531
+ const [isLoading, setLoading] = (0, import_react12.useState)(false);
3532
+ const [error, setError] = (0, import_react12.useState)(null);
3533
+ const [activeIndex, setActiveIndex] = (0, import_react12.useState)(0);
3534
+ const [dismissedIndex, setDismissedIndex] = (0, import_react12.useState)(null);
3424
3535
  const safeCaret = Math.min(caret, value.length);
3425
- const match = (0, import_react9.useMemo)(() => findActiveTrigger(value, safeCaret, sources), [
3536
+ const match = (0, import_react12.useMemo)(() => findActiveTrigger(value, safeCaret, sources), [
3426
3537
  value,
3427
3538
  safeCaret,
3428
3539
  sources
3429
3540
  ]);
3430
3541
  const isActive = match !== null && dismissedIndex !== match.index;
3431
- const matchRef = (0, import_react9.useRef)(match);
3542
+ const matchRef = (0, import_react12.useRef)(match);
3432
3543
  matchRef.current = match;
3433
- const caretRef = (0, import_react9.useRef)(safeCaret);
3544
+ const caretRef = (0, import_react12.useRef)(safeCaret);
3434
3545
  caretRef.current = safeCaret;
3435
- const itemsRef = (0, import_react9.useRef)(items);
3546
+ const itemsRef = (0, import_react12.useRef)(items);
3436
3547
  itemsRef.current = items;
3437
- const activeIndexRef = (0, import_react9.useRef)(activeIndex);
3548
+ const activeIndexRef = (0, import_react12.useRef)(activeIndex);
3438
3549
  activeIndexRef.current = activeIndex;
3439
3550
  const requestKey = isActive && match ? `${match.source.id}\0${match.query}` : null;
3440
- (0, import_react9.useEffect)(() => {
3551
+ (0, import_react12.useEffect)(() => {
3441
3552
  const current = matchRef.current;
3442
3553
  if (requestKey === null || current === null) {
3443
3554
  setItems([]);
@@ -3485,25 +3596,25 @@ function useComposerAutocomplete(options) {
3485
3596
  ]);
3486
3597
  const isOpen = isActive;
3487
3598
  const activeItem = isOpen ? items[activeIndex] ?? null : null;
3488
- const reactId = (0, import_react9.useId)();
3599
+ const reactId = (0, import_react12.useId)();
3489
3600
  const listboxId = options.id ?? `agent-autocomplete-${reactId}`;
3490
- const optionId = (0, import_react9.useCallback)((index) => `${listboxId}-option-${index}`, [
3601
+ const optionId = (0, import_react12.useCallback)((index) => `${listboxId}-option-${index}`, [
3491
3602
  listboxId
3492
3603
  ]);
3493
- const highlight = (0, import_react9.useCallback)((index) => {
3604
+ const highlight = (0, import_react12.useCallback)((index) => {
3494
3605
  const total = itemsRef.current.length;
3495
3606
  if (total === 0) return;
3496
3607
  setActiveIndex((index % total + total) % total);
3497
3608
  }, []);
3498
- const moveHighlight = (0, import_react9.useCallback)((delta) => highlight(activeIndexRef.current + delta), [
3609
+ const moveHighlight = (0, import_react12.useCallback)((delta) => highlight(activeIndexRef.current + delta), [
3499
3610
  highlight
3500
3611
  ]);
3501
- const dismiss = (0, import_react9.useCallback)(() => {
3612
+ const dismiss = (0, import_react12.useCallback)(() => {
3502
3613
  const current = matchRef.current;
3503
3614
  if (current) setDismissedIndex(current.index);
3504
3615
  }, []);
3505
- const pendingCaret = (0, import_react9.useRef)(null);
3506
- const accept = (0, import_react9.useCallback)((item) => {
3616
+ const pendingCaret = (0, import_react12.useRef)(null);
3617
+ const accept = (0, import_react12.useCallback)((item) => {
3507
3618
  const current = matchRef.current;
3508
3619
  if (!current) return;
3509
3620
  const chosen = item ?? itemsRef.current[activeIndexRef.current];
@@ -3514,16 +3625,16 @@ function useComposerAutocomplete(options) {
3514
3625
  setDismissedIndex(null);
3515
3626
  pendingCaret.current = edit.caret;
3516
3627
  }, []);
3517
- (0, import_react9.useLayoutEffect)(() => {
3628
+ (0, import_react12.useLayoutEffect)(() => {
3518
3629
  const position = pendingCaret.current;
3519
3630
  if (position === null) return;
3520
3631
  pendingCaret.current = null;
3521
3632
  inputRef.current?.setSelectionRange(position, position);
3522
3633
  });
3523
- const readCaret = (0, import_react9.useCallback)((element) => {
3634
+ const readCaret = (0, import_react12.useCallback)((element) => {
3524
3635
  setCaret(element.selectionStart ?? element.value.length);
3525
3636
  }, []);
3526
- const onKeyDown = (0, import_react9.useCallback)((event) => {
3637
+ const onKeyDown = (0, import_react12.useCallback)((event) => {
3527
3638
  if (!isOpen) return;
3528
3639
  const hasItems = itemsRef.current.length > 0;
3529
3640
  switch (event.key) {
@@ -3561,23 +3672,23 @@ function useComposerAutocomplete(options) {
3561
3672
  dismiss,
3562
3673
  moveHighlight
3563
3674
  ]);
3564
- const onChange = (0, import_react9.useCallback)((event) => {
3675
+ const onChange = (0, import_react12.useCallback)((event) => {
3565
3676
  readCaret(event.target);
3566
3677
  const next = findActiveTrigger(event.target.value, event.target.selectionStart ?? event.target.value.length, latest.current.sources);
3567
3678
  setDismissedIndex((current) => current !== null && next?.index === current ? current : null);
3568
3679
  }, [
3569
3680
  readCaret
3570
3681
  ]);
3571
- const onSelect = (0, import_react9.useCallback)((event) => readCaret(event.currentTarget), [
3682
+ const onSelect = (0, import_react12.useCallback)((event) => readCaret(event.currentTarget), [
3572
3683
  readCaret
3573
3684
  ]);
3574
- const onClick = (0, import_react9.useCallback)((event) => readCaret(event.currentTarget), [
3685
+ const onClick = (0, import_react12.useCallback)((event) => readCaret(event.currentTarget), [
3575
3686
  readCaret
3576
3687
  ]);
3577
- const setInput = (0, import_react9.useCallback)((element) => {
3688
+ const setInput = (0, import_react12.useCallback)((element) => {
3578
3689
  inputRef.current = element;
3579
3690
  }, []);
3580
- const getInputProps = (0, import_react9.useCallback)(() => ({
3691
+ const getInputProps = (0, import_react12.useCallback)(() => ({
3581
3692
  ref: setInput,
3582
3693
  onChange,
3583
3694
  onKeyDown,
@@ -3605,7 +3716,7 @@ function useComposerAutocomplete(options) {
3605
3716
  activeIndex,
3606
3717
  optionId
3607
3718
  ]);
3608
- const getListboxProps = (0, import_react9.useCallback)(() => ({
3719
+ const getListboxProps = (0, import_react12.useCallback)(() => ({
3609
3720
  id: listboxId,
3610
3721
  role: "listbox",
3611
3722
  "aria-label": match?.source.label ?? match?.source.id ?? "Suggestions"
@@ -3613,7 +3724,7 @@ function useComposerAutocomplete(options) {
3613
3724
  listboxId,
3614
3725
  match
3615
3726
  ]);
3616
- const getOptionProps = (0, import_react9.useCallback)((index) => ({
3727
+ const getOptionProps = (0, import_react12.useCallback)((index) => ({
3617
3728
  id: optionId(index),
3618
3729
  role: "option",
3619
3730
  "aria-selected": index === activeIndex
@@ -3647,7 +3758,7 @@ function isPromise(value) {
3647
3758
  __name(isPromise, "isPromise");
3648
3759
 
3649
3760
  // src/presentation/use-tool-catalog.ts
3650
- var import_react10 = require("react");
3761
+ var import_react13 = require("react");
3651
3762
  var shared = /* @__PURE__ */ new WeakMap();
3652
3763
  function load(client, agent) {
3653
3764
  let byAgent = shared.get(client);
@@ -3671,11 +3782,11 @@ function load(client, agent) {
3671
3782
  __name(load, "load");
3672
3783
  function useToolCatalog(options) {
3673
3784
  const { client, agent, enabled = true } = options;
3674
- const [entries, setEntries] = (0, import_react10.useState)([]);
3675
- const [isLoading, setLoading] = (0, import_react10.useState)(enabled);
3676
- const [error, setError] = (0, import_react10.useState)(null);
3677
- const [generation, setGeneration] = (0, import_react10.useState)(0);
3678
- (0, import_react10.useEffect)(() => {
3785
+ const [entries, setEntries] = (0, import_react13.useState)([]);
3786
+ const [isLoading, setLoading] = (0, import_react13.useState)(enabled);
3787
+ const [error, setError] = (0, import_react13.useState)(null);
3788
+ const [generation, setGeneration] = (0, import_react13.useState)(0);
3789
+ (0, import_react13.useEffect)(() => {
3679
3790
  if (!enabled) {
3680
3791
  setLoading(false);
3681
3792
  return;
@@ -3701,14 +3812,14 @@ function useToolCatalog(options) {
3701
3812
  enabled,
3702
3813
  generation
3703
3814
  ]);
3704
- const refresh = (0, import_react10.useCallback)(() => {
3815
+ const refresh = (0, import_react13.useCallback)(() => {
3705
3816
  shared.get(client)?.delete(agent ?? "");
3706
3817
  setGeneration((current) => current + 1);
3707
3818
  }, [
3708
3819
  client,
3709
3820
  agent
3710
3821
  ]);
3711
- const catalog = (0, import_react10.useMemo)(() => toolCatalogFrom(entries), [
3822
+ const catalog = (0, import_react13.useMemo)(() => toolCatalogFrom(entries), [
3712
3823
  entries
3713
3824
  ]);
3714
3825
  return {
@@ -3722,7 +3833,7 @@ function useToolCatalog(options) {
3722
3833
  __name(useToolCatalog, "useToolCatalog");
3723
3834
 
3724
3835
  // src/approvals/countdown.ts
3725
- var import_react11 = require("react");
3836
+ var import_react14 = require("react");
3726
3837
  function approvalCountdown(expiresAt, now = Date.now()) {
3727
3838
  const deadline = expiresAt == null ? Number.NaN : Date.parse(expiresAt);
3728
3839
  if (!Number.isFinite(deadline)) {
@@ -3740,10 +3851,10 @@ function approvalCountdown(expiresAt, now = Date.now()) {
3740
3851
  __name(approvalCountdown, "approvalCountdown");
3741
3852
  function useApprovalCountdown(expiresAt, options = {}) {
3742
3853
  const { intervalMs = 1e3 } = options;
3743
- const nowRef = (0, import_react11.useRef)(options.now ?? Date.now);
3854
+ const nowRef = (0, import_react14.useRef)(options.now ?? Date.now);
3744
3855
  nowRef.current = options.now ?? Date.now;
3745
- const [state, setState] = (0, import_react11.useState)(() => approvalCountdown(expiresAt, nowRef.current()));
3746
- (0, import_react11.useEffect)(() => {
3856
+ const [state, setState] = (0, import_react14.useState)(() => approvalCountdown(expiresAt, nowRef.current()));
3857
+ (0, import_react14.useEffect)(() => {
3747
3858
  const read = /* @__PURE__ */ __name(() => approvalCountdown(expiresAt, nowRef.current()), "read");
3748
3859
  const first = read();
3749
3860
  setState(first);
@@ -3984,21 +4095,21 @@ function sumUsage(rows) {
3984
4095
  __name(sumUsage, "sumUsage");
3985
4096
 
3986
4097
  // src/use-agent-chat.ts
3987
- var import_react12 = require("@ai-sdk/react");
3988
- var import_react13 = require("react");
4098
+ var import_react15 = require("@ai-sdk/react");
4099
+ var import_react16 = require("react");
3989
4100
  function useAgentChat(options) {
3990
- const latest = (0, import_react13.useRef)(options);
4101
+ const latest = (0, import_react16.useRef)(options);
3991
4102
  latest.current = options;
3992
- const [runId, setRunId] = (0, import_react13.useState)(options.resumeRunId);
3993
- const runIdRef = (0, import_react13.useRef)(runId);
4103
+ const [runId, setRunId] = (0, import_react16.useState)(options.resumeRunId);
4104
+ const runIdRef = (0, import_react16.useRef)(runId);
3994
4105
  runIdRef.current = runId;
3995
- const settlingRunIdRef = (0, import_react13.useRef)(void 0);
3996
- const autoResumeRunIdRef = (0, import_react13.useRef)(void 0);
3997
- const [autoResume, setAutoResume] = (0, import_react13.useState)(false);
3998
- const [activeRunId, setActiveRunId] = (0, import_react13.useState)(null);
3999
- const regenerateNext = (0, import_react13.useRef)(false);
4000
- const createdThreadId = (0, import_react13.useRef)(void 0);
4001
- const client = (0, import_react13.useMemo)(() => {
4106
+ const settlingRunIdRef = (0, import_react16.useRef)(void 0);
4107
+ const autoResumeRunIdRef = (0, import_react16.useRef)(void 0);
4108
+ const [autoResume, setAutoResume] = (0, import_react16.useState)(false);
4109
+ const [activeRunId, setActiveRunId] = (0, import_react16.useState)(null);
4110
+ const regenerateNext = (0, import_react16.useRef)(false);
4111
+ const createdThreadId = (0, import_react16.useRef)(void 0);
4112
+ const client = (0, import_react16.useMemo)(() => {
4002
4113
  if (options.backend) return options.backend;
4003
4114
  if (options.client) return options.client;
4004
4115
  return new AgentClient({
@@ -4014,11 +4125,11 @@ function useAgentChat(options) {
4014
4125
  getHeaders: /* @__PURE__ */ __name(async () => mergeHeaders(latest.current), "getHeaders")
4015
4126
  });
4016
4127
  }, []);
4017
- const [connection, setConnection] = (0, import_react13.useState)({
4128
+ const [connection, setConnection] = (0, import_react16.useState)({
4018
4129
  status: "live"
4019
4130
  });
4020
- const resyncAfterSettle = (0, import_react13.useRef)(false);
4021
- (0, import_react13.useEffect)(() => {
4131
+ const resyncAfterSettle = (0, import_react16.useRef)(false);
4132
+ (0, import_react16.useEffect)(() => {
4022
4133
  if (!options.resume || options.threadId === void 0) return;
4023
4134
  let cancelled = false;
4024
4135
  const threadId = options.threadId;
@@ -4038,7 +4149,7 @@ function useAgentChat(options) {
4038
4149
  options.resume,
4039
4150
  options.threadId
4040
4151
  ]);
4041
- const transport = (0, import_react13.useMemo)(() => {
4152
+ const transport = (0, import_react16.useMemo)(() => {
4042
4153
  function onMeta(meta) {
4043
4154
  settlingRunIdRef.current = meta.runId;
4044
4155
  setRunId(meta.runId);
@@ -4075,6 +4186,9 @@ function useAgentChat(options) {
4075
4186
  ...threadId !== void 0 ? {
4076
4187
  threadId
4077
4188
  } : {},
4189
+ ...current.model !== void 0 ? {
4190
+ model: current.model
4191
+ } : {},
4078
4192
  ...pageContext ? {
4079
4193
  pageContext
4080
4194
  } : {},
@@ -4090,8 +4204,8 @@ function useAgentChat(options) {
4090
4204
  }, "onAttemptStart")
4091
4205
  });
4092
4206
  }, []);
4093
- const backgroundRef = (0, import_react13.useRef)(() => Promise.resolve());
4094
- const chat = (0, import_react12.useChat)({
4207
+ const backgroundRef = (0, import_react16.useRef)(() => Promise.resolve());
4208
+ const chat = (0, import_react15.useChat)({
4095
4209
  transport,
4096
4210
  resume: options.resumeRunId !== void 0 || autoResume,
4097
4211
  ...options.threadId !== void 0 ? {
@@ -4139,7 +4253,7 @@ function useAgentChat(options) {
4139
4253
  }
4140
4254
  }, "onFinish")
4141
4255
  });
4142
- const chatRef = (0, import_react13.useRef)(chat);
4256
+ const chatRef = (0, import_react16.useRef)(chat);
4143
4257
  chatRef.current = chat;
4144
4258
  async function resyncFromThread() {
4145
4259
  const threadId = latest.current.threadId ?? createdThreadId.current;
@@ -4151,11 +4265,11 @@ function useAgentChat(options) {
4151
4265
  }
4152
4266
  }
4153
4267
  __name(resyncFromThread, "resyncFromThread");
4154
- const turnInFlight = (0, import_react13.useRef)(false);
4155
- const isTurnInFlight = (0, import_react13.useCallback)(() => turnInFlight.current || transport.isAttemptLive, [
4268
+ const turnInFlight = (0, import_react16.useRef)(false);
4269
+ const isTurnInFlight = (0, import_react16.useCallback)(() => turnInFlight.current || transport.isAttemptLive, [
4156
4270
  transport
4157
4271
  ]);
4158
- const sendMessage = (0, import_react13.useCallback)(async (...args) => {
4272
+ const sendMessage = (0, import_react16.useCallback)(async (...args) => {
4159
4273
  if (isTurnInFlight()) return;
4160
4274
  turnInFlight.current = true;
4161
4275
  try {
@@ -4166,15 +4280,15 @@ function useAgentChat(options) {
4166
4280
  }, [
4167
4281
  isTurnInFlight
4168
4282
  ]);
4169
- const addToolResult = (0, import_react13.useCallback)(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
4283
+ const addToolResult = (0, import_react16.useCallback)(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
4170
4284
  tool,
4171
4285
  toolCallId,
4172
4286
  output
4173
4287
  }), []);
4174
- const [threads, setThreads] = (0, import_react13.useState)([]);
4175
- const [quota, setQuota] = (0, import_react13.useState)(null);
4176
- const [backgroundRuns, setBackgroundRuns] = (0, import_react13.useState)([]);
4177
- const refreshBackground = (0, import_react13.useCallback)(async () => {
4288
+ const [threads, setThreads] = (0, import_react16.useState)([]);
4289
+ const [quota, setQuota] = (0, import_react16.useState)(null);
4290
+ const [backgroundRuns, setBackgroundRuns] = (0, import_react16.useState)([]);
4291
+ const refreshBackground = (0, import_react16.useCallback)(async () => {
4178
4292
  const threadId = latest.current.threadId ?? createdThreadId.current;
4179
4293
  if (threadId === void 0) {
4180
4294
  return;
@@ -4199,7 +4313,7 @@ function useAgentChat(options) {
4199
4313
  ]);
4200
4314
  backgroundRef.current = refreshBackground;
4201
4315
  const isWorking = backgroundRuns.some((run) => run.status === "running");
4202
- (0, import_react13.useEffect)(() => {
4316
+ (0, import_react16.useEffect)(() => {
4203
4317
  if (options.background !== true || options.threadId === void 0) {
4204
4318
  return;
4205
4319
  }
@@ -4209,7 +4323,7 @@ function useAgentChat(options) {
4209
4323
  options.threadId,
4210
4324
  refreshBackground
4211
4325
  ]);
4212
- (0, import_react13.useEffect)(() => {
4326
+ (0, import_react16.useEffect)(() => {
4213
4327
  const every = latest.current.backgroundPollMs ?? 5e3;
4214
4328
  if (latest.current.background !== true || !isWorking || every <= 0) {
4215
4329
  return;
@@ -4220,26 +4334,26 @@ function useAgentChat(options) {
4220
4334
  isWorking,
4221
4335
  refreshBackground
4222
4336
  ]);
4223
- const loadThreads = (0, import_react13.useCallback)(async () => {
4337
+ const loadThreads = (0, import_react16.useCallback)(async () => {
4224
4338
  const list = await client.listThreads();
4225
4339
  setThreads(list);
4226
4340
  return list;
4227
4341
  }, [
4228
4342
  client
4229
4343
  ]);
4230
- const loadThread = (0, import_react13.useCallback)((id) => client.getThread(id), [
4344
+ const loadThread = (0, import_react16.useCallback)((id) => client.getThread(id), [
4231
4345
  client
4232
4346
  ]);
4233
- const deleteThread = (0, import_react13.useCallback)(async (id) => {
4347
+ const deleteThread = (0, import_react16.useCallback)(async (id) => {
4234
4348
  await client.deleteThread(id);
4235
4349
  setThreads((current) => current.filter((thread) => thread.id !== id));
4236
4350
  }, [
4237
4351
  client
4238
4352
  ]);
4239
- const forkThread = (0, import_react13.useCallback)((threadId, messageId) => requireBackendMethod(client, "forkFromMessage")(threadId, messageId), [
4353
+ const forkThread = (0, import_react16.useCallback)((threadId, messageId) => requireBackendMethod(client, "forkFromMessage")(threadId, messageId), [
4240
4354
  client
4241
4355
  ]);
4242
- const renameThread = (0, import_react13.useCallback)(async (id, title) => {
4356
+ const renameThread = (0, import_react16.useCallback)(async (id, title) => {
4243
4357
  await client.updateThread(id, {
4244
4358
  title
4245
4359
  });
@@ -4250,24 +4364,24 @@ function useAgentChat(options) {
4250
4364
  }, [
4251
4365
  client
4252
4366
  ]);
4253
- const promoteThread = (0, import_react13.useCallback)(async (id) => {
4367
+ const promoteThread = (0, import_react16.useCallback)(async (id) => {
4254
4368
  await requireBackendMethod(client, "promoteThread")(id);
4255
4369
  await loadThreads();
4256
4370
  }, [
4257
4371
  client,
4258
4372
  loadThreads
4259
4373
  ]);
4260
- const truncateFromMessage = (0, import_react13.useCallback)((threadId, messageId) => requireBackendMethod(client, "truncateFromMessage")(threadId, messageId).then(() => void 0), [
4374
+ const truncateFromMessage = (0, import_react16.useCallback)((threadId, messageId) => requireBackendMethod(client, "truncateFromMessage")(threadId, messageId).then(() => void 0), [
4261
4375
  client
4262
4376
  ]);
4263
- const loadQuota = (0, import_react13.useCallback)(async () => {
4377
+ const loadQuota = (0, import_react16.useCallback)(async () => {
4264
4378
  const today = await requireBackendMethod(client, "getQuotaToday")();
4265
4379
  setQuota(today);
4266
4380
  return today;
4267
4381
  }, [
4268
4382
  client
4269
4383
  ]);
4270
- const cancel = (0, import_react13.useCallback)(async () => {
4384
+ const cancel = (0, import_react16.useCallback)(async () => {
4271
4385
  chatRef.current.stop();
4272
4386
  const activeRunId2 = runIdRef.current;
4273
4387
  if (activeRunId2) {
@@ -4279,7 +4393,7 @@ function useAgentChat(options) {
4279
4393
  }, [
4280
4394
  client
4281
4395
  ]);
4282
- const approve = (0, import_react13.useCallback)(async ({ toolCallId, remember, via }) => {
4396
+ const approve = (0, import_react16.useCallback)(async ({ toolCallId, remember, via }) => {
4283
4397
  await requireBackendMethod(client, "approveToolCall")({
4284
4398
  toolCallId,
4285
4399
  ...remember === true ? {
@@ -4292,7 +4406,7 @@ function useAgentChat(options) {
4292
4406
  }, [
4293
4407
  client
4294
4408
  ]);
4295
- const reject = (0, import_react13.useCallback)(async ({ toolCallId, reason, via }) => {
4409
+ const reject = (0, import_react16.useCallback)(async ({ toolCallId, reason, via }) => {
4296
4410
  await requireBackendMethod(client, "rejectToolCall")({
4297
4411
  toolCallId,
4298
4412
  ...reason !== void 0 ? {
@@ -4305,7 +4419,7 @@ function useAgentChat(options) {
4305
4419
  }, [
4306
4420
  client
4307
4421
  ]);
4308
- const answer = (0, import_react13.useCallback)(async ({ toolCallId, answers }) => {
4422
+ const answer = (0, import_react16.useCallback)(async ({ toolCallId, answers }) => {
4309
4423
  await requireBackendMethod(client, "answerToolCall")({
4310
4424
  toolCallId,
4311
4425
  ...answers !== void 0 ? {
@@ -4315,14 +4429,14 @@ function useAgentChat(options) {
4315
4429
  }, [
4316
4430
  client
4317
4431
  ]);
4318
- const skip = (0, import_react13.useCallback)(async ({ toolCallId }) => {
4432
+ const skip = (0, import_react16.useCallback)(async ({ toolCallId }) => {
4319
4433
  await requireBackendMethod(client, "skipToolCall")({
4320
4434
  toolCallId
4321
4435
  });
4322
4436
  }, [
4323
4437
  client
4324
4438
  ]);
4325
- const regenerate = (0, import_react13.useCallback)(() => {
4439
+ const regenerate = (0, import_react16.useCallback)(() => {
4326
4440
  if (isTurnInFlight()) return;
4327
4441
  regenerateNext.current = true;
4328
4442
  turnInFlight.current = true;
@@ -4337,7 +4451,21 @@ function useAgentChat(options) {
4337
4451
  isWorking,
4338
4452
  refresh: refreshBackground
4339
4453
  };
4340
- const getThreadId = (0, import_react13.useCallback)(() => latest.current.threadId ?? createdThreadId.current, []);
4454
+ const setThreadModel = (0, import_react16.useCallback)(async (model) => {
4455
+ const threadId = latest.current.threadId ?? createdThreadId.current;
4456
+ if (threadId === void 0) {
4457
+ throw new Error("setThreadModel: this chat has no thread yet");
4458
+ }
4459
+ await client.updateThread(threadId, {
4460
+ model
4461
+ });
4462
+ notifyThreads(client, {
4463
+ type: "changed"
4464
+ });
4465
+ }, [
4466
+ client
4467
+ ]);
4468
+ const getThreadId = (0, import_react16.useCallback)(() => latest.current.threadId ?? createdThreadId.current, []);
4341
4469
  const status = connection.status === "reconnecting" ? "reconnecting" : chat.status;
4342
4470
  return {
4343
4471
  ...chat,
@@ -4356,6 +4484,7 @@ function useAgentChat(options) {
4356
4484
  * on the first send. A getter, because the created id is learned mid-stream.
4357
4485
  */
4358
4486
  getThreadId,
4487
+ setThreadModel,
4359
4488
  /** The backend this chat talks to — pass it to `useThreads`, `useMessageFeedback`, … */
4360
4489
  backend: client,
4361
4490
  /** Same object as {@link backend}; kept for callers that read it under its old name. */
@@ -4432,11 +4561,13 @@ __name(mergeHeaders, "mergeHeaders");
4432
4561
  toolCallState,
4433
4562
  toolCatalogFrom,
4434
4563
  useAgentChat,
4564
+ useAgents,
4435
4565
  useApprovalCountdown,
4436
4566
  useChatTranscript,
4437
4567
  useComposerAutocomplete,
4438
4568
  useElapsed,
4439
4569
  useMessageFeedback,
4570
+ useModels,
4440
4571
  useSpeechRecognition,
4441
4572
  useStickToBottom,
4442
4573
  useThreads,