@dudousxd/nestjs-agent-react 0.22.1 → 0.24.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
@@ -83,6 +83,7 @@ __export(src_exports, {
83
83
  toolCatalogFrom: () => toolCatalogFrom,
84
84
  useAgentBackend: () => useAgentBackend,
85
85
  useAgentChat: () => useAgentChat,
86
+ useAgentConfig: () => useAgentConfig,
86
87
  useAgents: () => useAgents,
87
88
  useAmbientRenderUi: () => useAmbientRenderUi,
88
89
  useApprovalCountdown: () => useApprovalCountdown,
@@ -305,6 +306,10 @@ var AgentClient = class {
305
306
  listAgents() {
306
307
  return this.request("GET", "/agents");
307
308
  }
309
+ /** `GET <path>/config` — attachment limits and upload mode, and which features are on. */
310
+ getConfig() {
311
+ return this.request("GET", "/config");
312
+ }
308
313
  /** `GET <path>/quota` — the caller's budget windows and the one blocking sends, if any. */
309
314
  getQuota() {
310
315
  return this.request("GET", "/quota");
@@ -962,6 +967,13 @@ var AgentChatTransport = class {
962
967
  }
963
968
  });
964
969
  break;
970
+ case "message-metadata":
971
+ ensureStarted();
972
+ controller.enqueue({
973
+ type: "message-metadata",
974
+ messageMetadata: event.metadata
975
+ });
976
+ break;
965
977
  case "title":
966
978
  case "cancelled":
967
979
  forwardAsData(event, true);
@@ -1215,7 +1227,7 @@ function dragHasFiles(data) {
1215
1227
  __name(dragHasFiles, "dragHasFiles");
1216
1228
 
1217
1229
  // src/attachments/use-attachments.ts
1218
- var import_react6 = require("react");
1230
+ var import_react7 = require("react");
1219
1231
 
1220
1232
  // src/backend.ts
1221
1233
  var AgentBackendUnsupportedError = class extends Error {
@@ -1237,6 +1249,9 @@ function requireBackendMethod(backend, name) {
1237
1249
  }
1238
1250
  __name(requireBackendMethod, "requireBackendMethod");
1239
1251
 
1252
+ // src/config/use-agent-config.ts
1253
+ var import_react6 = require("react");
1254
+
1240
1255
  // src/provider.tsx
1241
1256
  var import_react5 = require("react");
1242
1257
 
@@ -1801,6 +1816,59 @@ function useAgentBackend(own) {
1801
1816
  }
1802
1817
  __name(useAgentBackend, "useAgentBackend");
1803
1818
 
1819
+ // src/config/use-agent-config.ts
1820
+ var shared = /* @__PURE__ */ new WeakMap();
1821
+ function load(backend) {
1822
+ const getConfig = backend.getConfig;
1823
+ if (typeof getConfig !== "function") return void 0;
1824
+ let pending = shared.get(backend);
1825
+ if (pending === void 0) {
1826
+ pending = getConfig.call(backend).catch((error) => {
1827
+ shared.delete(backend);
1828
+ throw error;
1829
+ });
1830
+ shared.set(backend, pending);
1831
+ }
1832
+ return pending;
1833
+ }
1834
+ __name(load, "load");
1835
+ function useAgentConfig(options = {}) {
1836
+ const backend = useAgentBackend(options.backend);
1837
+ const enabled = options.enabled !== false;
1838
+ const [config, setConfig] = (0, import_react6.useState)(void 0);
1839
+ const [isLoading, setLoading] = (0, import_react6.useState)(false);
1840
+ const [error, setError] = (0, import_react6.useState)(null);
1841
+ (0, import_react6.useEffect)(() => {
1842
+ if (!enabled) return;
1843
+ const pending = load(backend);
1844
+ if (pending === void 0) return;
1845
+ let cancelled = false;
1846
+ setLoading(true);
1847
+ pending.then((loaded) => {
1848
+ if (cancelled) return;
1849
+ setConfig(loaded !== null && typeof loaded === "object" ? loaded : void 0);
1850
+ setError(null);
1851
+ setLoading(false);
1852
+ }, (failure) => {
1853
+ if (cancelled) return;
1854
+ setError(failure instanceof Error ? failure : new Error(String(failure)));
1855
+ setLoading(false);
1856
+ });
1857
+ return () => {
1858
+ cancelled = true;
1859
+ };
1860
+ }, [
1861
+ backend,
1862
+ enabled
1863
+ ]);
1864
+ return {
1865
+ config,
1866
+ isLoading,
1867
+ error
1868
+ };
1869
+ }
1870
+ __name(useAgentConfig, "useAgentConfig");
1871
+
1804
1872
  // src/attachments/use-attachments.ts
1805
1873
  var DEFAULT_REJECTION = {
1806
1874
  type: /* @__PURE__ */ __name((file) => `${file.name} is not a supported file type`, "type"),
@@ -1810,26 +1878,40 @@ var DEFAULT_REJECTION = {
1810
1878
  var sequence = 0;
1811
1879
  function useAttachments(options = {}) {
1812
1880
  const backend = useAgentBackend(options.backend);
1813
- const latest = (0, import_react6.useRef)({
1814
- ...options,
1881
+ const { config } = useAgentConfig({
1815
1882
  backend
1816
1883
  });
1817
- latest.current = {
1884
+ const limits = config?.attachments;
1885
+ const accept = options.accept ?? limits?.allowedContentTypes;
1886
+ const maxBytes = options.maxBytes ?? limits?.maxBytes;
1887
+ const maxFiles = options.maxFiles ?? limits?.maxPerMessage;
1888
+ const effective = {
1818
1889
  ...options,
1819
- backend
1890
+ backend,
1891
+ ...accept !== void 0 ? {
1892
+ accept
1893
+ } : {},
1894
+ ...maxBytes !== void 0 ? {
1895
+ maxBytes
1896
+ } : {},
1897
+ ...maxFiles !== void 0 ? {
1898
+ maxFiles
1899
+ } : {}
1820
1900
  };
1821
- const [items, setItems] = (0, import_react6.useState)([]);
1822
- const itemsRef = (0, import_react6.useRef)(items);
1901
+ const latest = (0, import_react7.useRef)(effective);
1902
+ latest.current = effective;
1903
+ const [items, setItems] = (0, import_react7.useState)([]);
1904
+ const itemsRef = (0, import_react7.useRef)(items);
1823
1905
  itemsRef.current = items;
1824
- const controllers = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
1825
- const [dragDepth, setDragDepth] = (0, import_react6.useState)(0);
1826
- const patch = (0, import_react6.useCallback)((id, change) => {
1906
+ const controllers = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
1907
+ const [dragDepth, setDragDepth] = (0, import_react7.useState)(0);
1908
+ const patch = (0, import_react7.useCallback)((id, change) => {
1827
1909
  setItems((current) => current.map((item) => item.id === id ? {
1828
1910
  ...item,
1829
1911
  ...change
1830
1912
  } : item));
1831
1913
  }, []);
1832
- const start = (0, import_react6.useCallback)((item) => {
1914
+ const start = (0, import_react7.useCallback)((item) => {
1833
1915
  const { upload, backend: backend2 } = latest.current;
1834
1916
  const run = upload ?? (backend2.uploadAttachment !== void 0 ? backend2.uploadAttachment.bind(backend2) : void 0);
1835
1917
  if (run === void 0) {
@@ -1865,11 +1947,11 @@ function useAttachments(options = {}) {
1865
1947
  }, [
1866
1948
  patch
1867
1949
  ]);
1868
- const add = (0, import_react6.useCallback)((files) => {
1950
+ const add = (0, import_react7.useCallback)((files) => {
1869
1951
  if (files == null) return;
1870
- const { accept: accept2, maxBytes, maxFiles, describeRejection } = latest.current;
1952
+ const { accept: accept2, maxBytes: maxBytes2, maxFiles: maxFiles2, describeRejection } = latest.current;
1871
1953
  const describe = /* @__PURE__ */ __name((reason, file) => describeRejection?.(reason, file) ?? DEFAULT_REJECTION[reason](file), "describe");
1872
- let room = maxFiles === void 0 ? Number.POSITIVE_INFINITY : maxFiles - itemsRef.current.filter((item) => item.status !== "rejected").length;
1954
+ let room = maxFiles2 === void 0 ? Number.POSITIVE_INFINITY : maxFiles2 - itemsRef.current.filter((item) => item.status !== "rejected").length;
1873
1955
  const staged = [];
1874
1956
  for (const file of Array.from(files)) {
1875
1957
  sequence += 1;
@@ -1881,7 +1963,7 @@ function useAttachments(options = {}) {
1881
1963
  type: file.type,
1882
1964
  progress: 0
1883
1965
  };
1884
- const reason = !acceptsFile(accept2, file) ? "type" : maxBytes !== void 0 && file.size > maxBytes ? "size" : room <= 0 ? "count" : void 0;
1966
+ const reason = !acceptsFile(accept2, file) ? "type" : maxBytes2 !== void 0 && file.size > maxBytes2 ? "size" : room <= 0 ? "count" : void 0;
1885
1967
  if (reason !== void 0) {
1886
1968
  staged.push({
1887
1969
  ...base,
@@ -1911,7 +1993,7 @@ function useAttachments(options = {}) {
1911
1993
  }, [
1912
1994
  start
1913
1995
  ]);
1914
- const release = (0, import_react6.useCallback)((item) => {
1996
+ const release = (0, import_react7.useCallback)((item) => {
1915
1997
  if (item === void 0) return;
1916
1998
  controllers.current.get(item.id)?.abort();
1917
1999
  controllers.current.delete(item.id);
@@ -1919,19 +2001,19 @@ function useAttachments(options = {}) {
1919
2001
  URL.revokeObjectURL(item.previewUrl);
1920
2002
  }
1921
2003
  }, []);
1922
- const remove = (0, import_react6.useCallback)((id) => {
2004
+ const remove = (0, import_react7.useCallback)((id) => {
1923
2005
  release(itemsRef.current.find((item) => item.id === id));
1924
2006
  setItems((current) => current.filter((item) => item.id !== id));
1925
2007
  }, [
1926
2008
  release
1927
2009
  ]);
1928
- const clear = (0, import_react6.useCallback)(() => {
2010
+ const clear = (0, import_react7.useCallback)(() => {
1929
2011
  for (const item of itemsRef.current) release(item);
1930
2012
  setItems([]);
1931
2013
  }, [
1932
2014
  release
1933
2015
  ]);
1934
- const retry = (0, import_react6.useCallback)((id) => {
2016
+ const retry = (0, import_react7.useCallback)((id) => {
1935
2017
  const item = itemsRef.current.find((candidate) => candidate.id === id);
1936
2018
  if (item === void 0 || item.status !== "error") return;
1937
2019
  const { error: _previous, ...rest } = item;
@@ -1945,12 +2027,12 @@ function useAttachments(options = {}) {
1945
2027
  }, [
1946
2028
  start
1947
2029
  ]);
1948
- (0, import_react6.useEffect)(() => () => {
2030
+ (0, import_react7.useEffect)(() => () => {
1949
2031
  for (const item of itemsRef.current) release(item);
1950
2032
  }, [
1951
2033
  release
1952
2034
  ]);
1953
- const onPaste = (0, import_react6.useCallback)((event) => {
2035
+ const onPaste = (0, import_react7.useCallback)((event) => {
1954
2036
  const files = filesFromClipboard(event.clipboardData);
1955
2037
  if (files.length === 0) return;
1956
2038
  event.preventDefault();
@@ -1958,7 +2040,7 @@ function useAttachments(options = {}) {
1958
2040
  }, [
1959
2041
  add
1960
2042
  ]);
1961
- const dropZoneProps = (0, import_react6.useMemo)(() => ({
2043
+ const dropZoneProps = (0, import_react7.useMemo)(() => ({
1962
2044
  onDragEnter: /* @__PURE__ */ __name((event) => {
1963
2045
  if (!dragHasFiles(event.dataTransfer)) return;
1964
2046
  event.preventDefault();
@@ -1980,11 +2062,10 @@ function useAttachments(options = {}) {
1980
2062
  }), [
1981
2063
  add
1982
2064
  ]);
1983
- const accept = options.accept;
1984
- const inputProps = (0, import_react6.useMemo)(() => ({
2065
+ const inputProps = (0, import_react7.useMemo)(() => ({
1985
2066
  type: "file",
1986
2067
  accept: typeof accept === "string" ? accept : accept?.join(","),
1987
- multiple: options.maxFiles === void 0 || options.maxFiles > 1,
2068
+ multiple: maxFiles === void 0 || maxFiles > 1,
1988
2069
  onChange: /* @__PURE__ */ __name((event) => {
1989
2070
  const input = event.currentTarget;
1990
2071
  add(input.files);
@@ -1992,12 +2073,11 @@ function useAttachments(options = {}) {
1992
2073
  }, "onChange")
1993
2074
  }), [
1994
2075
  accept,
1995
- options.maxFiles,
2076
+ maxFiles,
1996
2077
  add
1997
2078
  ]);
1998
- return (0, import_react6.useMemo)(() => {
2079
+ return (0, import_react7.useMemo)(() => {
1999
2080
  const ready = items.filter((item) => item.status === "ready" && item.attachment !== void 0);
2000
- const attachments = ready.map((item) => item.attachment);
2001
2081
  return {
2002
2082
  items,
2003
2083
  add,
@@ -2005,9 +2085,8 @@ function useAttachments(options = {}) {
2005
2085
  retry,
2006
2086
  clear,
2007
2087
  isUploading: items.some((item) => item.status === "uploading"),
2008
- attachments,
2009
- refs: attachments.map((attachment) => ({
2010
- mediaId: attachment.mediaId
2088
+ refs: ready.map((item) => ({
2089
+ mediaId: item.attachment.mediaId
2011
2090
  })),
2012
2091
  inputProps,
2013
2092
  dropZoneProps,
@@ -2029,18 +2108,18 @@ function useAttachments(options = {}) {
2029
2108
  __name(useAttachments, "useAttachments");
2030
2109
 
2031
2110
  // src/catalog/use-agents.ts
2032
- var import_react8 = require("react");
2111
+ var import_react9 = require("react");
2033
2112
 
2034
2113
  // src/catalog/use-resource.ts
2035
- var import_react7 = require("react");
2036
- function useResource(load2, key, enabled) {
2037
- const [data, setData] = (0, import_react7.useState)(void 0);
2038
- const [isLoading, setIsLoading] = (0, import_react7.useState)(enabled);
2039
- const [error, setError] = (0, import_react7.useState)(null);
2040
- const loadRef = (0, import_react7.useRef)(load2);
2041
- loadRef.current = load2;
2042
- const generation = (0, import_react7.useRef)(0);
2043
- const refresh = (0, import_react7.useCallback)(async () => {
2114
+ var import_react8 = require("react");
2115
+ function useResource(load3, key, enabled) {
2116
+ const [data, setData] = (0, import_react8.useState)(void 0);
2117
+ const [isLoading, setIsLoading] = (0, import_react8.useState)(enabled);
2118
+ const [error, setError] = (0, import_react8.useState)(null);
2119
+ const loadRef = (0, import_react8.useRef)(load3);
2120
+ loadRef.current = load3;
2121
+ const generation = (0, import_react8.useRef)(0);
2122
+ const refresh = (0, import_react8.useCallback)(async () => {
2044
2123
  const mine = ++generation.current;
2045
2124
  setIsLoading(true);
2046
2125
  try {
@@ -2055,7 +2134,7 @@ function useResource(load2, key, enabled) {
2055
2134
  if (mine === generation.current) setIsLoading(false);
2056
2135
  }
2057
2136
  }, []);
2058
- (0, import_react7.useEffect)(() => {
2137
+ (0, import_react8.useEffect)(() => {
2059
2138
  if (!enabled) return;
2060
2139
  void refresh();
2061
2140
  }, [
@@ -2077,7 +2156,7 @@ function useAgents(options = {}) {
2077
2156
  const { enabled = true } = options;
2078
2157
  const backend = useAgentBackend(options.backend);
2079
2158
  const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "listAgents")(), "", enabled);
2080
- return (0, import_react8.useMemo)(() => {
2159
+ return (0, import_react9.useMemo)(() => {
2081
2160
  const agents = data ?? [];
2082
2161
  return {
2083
2162
  agents,
@@ -2096,12 +2175,12 @@ function useAgents(options = {}) {
2096
2175
  __name(useAgents, "useAgents");
2097
2176
 
2098
2177
  // src/catalog/use-models.ts
2099
- var import_react9 = require("react");
2178
+ var import_react10 = require("react");
2100
2179
  function useModels(options = {}) {
2101
2180
  const { agent, enabled = true } = options;
2102
2181
  const backend = useAgentBackend(options.backend);
2103
2182
  const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "listModels")(agent), `${agent ?? ""}`, enabled);
2104
- return (0, import_react9.useMemo)(() => {
2183
+ return (0, import_react10.useMemo)(() => {
2105
2184
  const providers = data?.providers ?? [];
2106
2185
  const models = providers.flatMap((provider) => provider.models.map((model) => ({
2107
2186
  ...model,
@@ -2131,7 +2210,7 @@ function useModels(options = {}) {
2131
2210
  __name(useModels, "useModels");
2132
2211
 
2133
2212
  // src/quota/use-quota.ts
2134
- var import_react10 = require("react");
2213
+ var import_react11 = require("react");
2135
2214
 
2136
2215
  // src/threads/threads-events.ts
2137
2216
  var listeners = /* @__PURE__ */ new WeakMap();
@@ -2159,7 +2238,7 @@ function useQuota(options = {}) {
2159
2238
  const { enabled = true, pollMs } = options;
2160
2239
  const backend = useAgentBackend(options.backend);
2161
2240
  const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "getQuota")(), "", enabled);
2162
- (0, import_react10.useEffect)(() => {
2241
+ (0, import_react11.useEffect)(() => {
2163
2242
  if (!enabled) return;
2164
2243
  return onThreadsEvent(backend, (event) => {
2165
2244
  if (event.type === "changed") void refresh();
@@ -2169,7 +2248,7 @@ function useQuota(options = {}) {
2169
2248
  enabled,
2170
2249
  refresh
2171
2250
  ]);
2172
- (0, import_react10.useEffect)(() => {
2251
+ (0, import_react11.useEffect)(() => {
2173
2252
  if (!enabled || pollMs === void 0 || pollMs <= 0) return;
2174
2253
  const timer = setInterval(() => void refresh(), pollMs);
2175
2254
  return () => clearInterval(timer);
@@ -2178,7 +2257,7 @@ function useQuota(options = {}) {
2178
2257
  pollMs,
2179
2258
  refresh
2180
2259
  ]);
2181
- return (0, import_react10.useMemo)(() => {
2260
+ return (0, import_react11.useMemo)(() => {
2182
2261
  const windows = data?.windows ?? [];
2183
2262
  return {
2184
2263
  report: data,
@@ -2200,10 +2279,10 @@ function useQuota(options = {}) {
2200
2279
  __name(useQuota, "useQuota");
2201
2280
 
2202
2281
  // src/feedback/use-message-feedback.ts
2203
- var import_react11 = require("react");
2282
+ var import_react12 = require("react");
2204
2283
  function useMessageFeedback(options = {}) {
2205
2284
  const backend = useAgentBackend(options.backend);
2206
- const latest = (0, import_react11.useRef)({
2285
+ const latest = (0, import_react12.useRef)({
2207
2286
  ...options,
2208
2287
  backend
2209
2288
  });
@@ -2211,23 +2290,23 @@ function useMessageFeedback(options = {}) {
2211
2290
  ...options,
2212
2291
  backend
2213
2292
  };
2214
- const [local, setLocal] = (0, import_react11.useState)(/* @__PURE__ */ new Map());
2215
- const [pending, setPending] = (0, import_react11.useState)(/* @__PURE__ */ new Set());
2216
- const [error, setError] = (0, import_react11.useState)(null);
2217
- const localRef = (0, import_react11.useRef)(local);
2293
+ const [local, setLocal] = (0, import_react12.useState)(/* @__PURE__ */ new Map());
2294
+ const [pending, setPending] = (0, import_react12.useState)(/* @__PURE__ */ new Set());
2295
+ const [error, setError] = (0, import_react12.useState)(null);
2296
+ const localRef = (0, import_react12.useRef)(local);
2218
2297
  localRef.current = local;
2219
- const resolved = (0, import_react11.useRef)(/* @__PURE__ */ new Map());
2220
- const feedbackOf = (0, import_react11.useCallback)((message) => {
2298
+ const resolved = (0, import_react12.useRef)(/* @__PURE__ */ new Map());
2299
+ const feedbackOf = (0, import_react12.useCallback)((message) => {
2221
2300
  const mine = local.get(message.id);
2222
2301
  if (mine !== void 0) return mine.feedback;
2223
2302
  return metadataOf(message).feedback ?? null;
2224
2303
  }, [
2225
2304
  local
2226
2305
  ]);
2227
- const isPending = (0, import_react11.useCallback)((message) => pending.has(message.id), [
2306
+ const isPending = (0, import_react12.useCallback)((message) => pending.has(message.id), [
2228
2307
  pending
2229
2308
  ]);
2230
- const storedIdFor = (0, import_react11.useCallback)(async (message) => {
2309
+ const storedIdFor = (0, import_react12.useCallback)(async (message) => {
2231
2310
  const runId = metadataOf(message).runId;
2232
2311
  if (runId === void 0) return message.id;
2233
2312
  const known = resolved.current.get(message.id);
@@ -2247,7 +2326,7 @@ function useMessageFeedback(options = {}) {
2247
2326
  resolved.current.set(message.id, row.id);
2248
2327
  return row.id;
2249
2328
  }, []);
2250
- const rate = (0, import_react11.useCallback)(async (message, value, comment) => {
2329
+ const rate = (0, import_react12.useCallback)(async (message, value, comment) => {
2251
2330
  const setFeedback = requireBackendMethod(latest.current.backend, "setMessageFeedback");
2252
2331
  const had = localRef.current.get(message.id);
2253
2332
  const optimistic = value === null ? null : {
@@ -2293,7 +2372,7 @@ function useMessageFeedback(options = {}) {
2293
2372
  }, [
2294
2373
  storedIdFor
2295
2374
  ]);
2296
- const toggle = (0, import_react11.useCallback)((message, value) => {
2375
+ const toggle = (0, import_react12.useCallback)((message, value) => {
2297
2376
  const mine = localRef.current.get(message.id);
2298
2377
  const current = mine !== void 0 ? mine.feedback : metadataOf(message).feedback ?? null;
2299
2378
  return rate(message, current?.value === value ? null : value);
@@ -2316,17 +2395,17 @@ function metadataOf(message) {
2316
2395
  __name(metadataOf, "metadataOf");
2317
2396
 
2318
2397
  // src/threads/use-threads.ts
2319
- var import_react12 = require("react");
2398
+ var import_react13 = require("react");
2320
2399
  function useThreads(options = {}) {
2321
2400
  const { enabled = true } = options;
2322
2401
  const backend = useAgentBackend(options.backend);
2323
- const [threads, setThreads] = (0, import_react12.useState)([]);
2324
- const [isLoading, setIsLoading] = (0, import_react12.useState)(enabled);
2325
- const [error, setError] = (0, import_react12.useState)(null);
2326
- const threadsRef = (0, import_react12.useRef)(threads);
2402
+ const [threads, setThreads] = (0, import_react13.useState)([]);
2403
+ const [isLoading, setIsLoading] = (0, import_react13.useState)(enabled);
2404
+ const [error, setError] = (0, import_react13.useState)(null);
2405
+ const threadsRef = (0, import_react13.useRef)(threads);
2327
2406
  threadsRef.current = threads;
2328
- const generation = (0, import_react12.useRef)(0);
2329
- const refresh = (0, import_react12.useCallback)(async () => {
2407
+ const generation = (0, import_react13.useRef)(0);
2408
+ const refresh = (0, import_react13.useCallback)(async () => {
2330
2409
  const mine = ++generation.current;
2331
2410
  setIsLoading(true);
2332
2411
  try {
@@ -2343,7 +2422,7 @@ function useThreads(options = {}) {
2343
2422
  }, [
2344
2423
  backend
2345
2424
  ]);
2346
- (0, import_react12.useEffect)(() => {
2425
+ (0, import_react13.useEffect)(() => {
2347
2426
  if (!enabled) return;
2348
2427
  void refresh();
2349
2428
  return onThreadsEvent(backend, (event) => {
@@ -2363,7 +2442,7 @@ function useThreads(options = {}) {
2363
2442
  enabled,
2364
2443
  refresh
2365
2444
  ]);
2366
- const rename = (0, import_react12.useCallback)(async (id, title) => {
2445
+ const rename = (0, import_react13.useCallback)(async (id, title) => {
2367
2446
  const before = threadsRef.current;
2368
2447
  setThreads((current) => current.map((thread) => thread.id === id ? {
2369
2448
  ...thread,
@@ -2385,7 +2464,7 @@ function useThreads(options = {}) {
2385
2464
  }, [
2386
2465
  backend
2387
2466
  ]);
2388
- const remove = (0, import_react12.useCallback)(async (id) => {
2467
+ const remove = (0, import_react13.useCallback)(async (id) => {
2389
2468
  const before = threadsRef.current;
2390
2469
  setThreads((current) => current.filter((thread) => thread.id !== id));
2391
2470
  try {
@@ -2460,10 +2539,10 @@ function backgroundRunsFromThread(messages) {
2460
2539
  __name(backgroundRunsFromThread, "backgroundRunsFromThread");
2461
2540
 
2462
2541
  // src/components/chat-input.tsx
2463
- var import_react14 = __toESM(require("react"), 1);
2542
+ var import_react15 = __toESM(require("react"), 1);
2464
2543
 
2465
2544
  // src/components/use-speech-recognition.ts
2466
- var import_react13 = require("react");
2545
+ var import_react14 = require("react");
2467
2546
  function getRecognitionCtor() {
2468
2547
  if (typeof window === "undefined") return null;
2469
2548
  const scope = window;
@@ -2471,15 +2550,15 @@ function getRecognitionCtor() {
2471
2550
  }
2472
2551
  __name(getRecognitionCtor, "getRecognitionCtor");
2473
2552
  function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTranscript }) {
2474
- const recognitionRef = (0, import_react13.useRef)(null);
2475
- const [isListening, setIsListening] = (0, import_react13.useState)(false);
2476
- const ctor = (0, import_react13.useMemo)(() => getRecognitionCtor(), []);
2553
+ const recognitionRef = (0, import_react14.useRef)(null);
2554
+ const [isListening, setIsListening] = (0, import_react14.useState)(false);
2555
+ const ctor = (0, import_react14.useMemo)(() => getRecognitionCtor(), []);
2477
2556
  const isSupported = ctor !== null;
2478
- const finalRef = (0, import_react13.useRef)(onFinalTranscript);
2479
- const interimRef = (0, import_react13.useRef)(onInterimTranscript);
2557
+ const finalRef = (0, import_react14.useRef)(onFinalTranscript);
2558
+ const interimRef = (0, import_react14.useRef)(onInterimTranscript);
2480
2559
  finalRef.current = onFinalTranscript;
2481
2560
  interimRef.current = onInterimTranscript;
2482
- (0, import_react13.useEffect)(() => {
2561
+ (0, import_react14.useEffect)(() => {
2483
2562
  if (!ctor) return;
2484
2563
  const recognition = new ctor();
2485
2564
  recognition.lang = lang;
@@ -2518,7 +2597,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
2518
2597
  ctor,
2519
2598
  lang
2520
2599
  ]);
2521
- const start = (0, import_react13.useCallback)(() => {
2600
+ const start = (0, import_react14.useCallback)(() => {
2522
2601
  const recognition = recognitionRef.current;
2523
2602
  if (!recognition) return;
2524
2603
  try {
@@ -2528,7 +2607,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
2528
2607
  console.warn("SpeechRecognition start failed", error);
2529
2608
  }
2530
2609
  }, []);
2531
- const stop = (0, import_react13.useCallback)(() => {
2610
+ const stop = (0, import_react14.useCallback)(() => {
2532
2611
  const recognition = recognitionRef.current;
2533
2612
  if (!recognition) return;
2534
2613
  try {
@@ -2547,8 +2626,8 @@ __name(useSpeechRecognition, "useSpeechRecognition");
2547
2626
 
2548
2627
  // src/components/chat-input.tsx
2549
2628
  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 }) {
2550
- const [value, setValue] = (0, import_react14.useState)("");
2551
- const [interim, setInterim] = (0, import_react14.useState)("");
2629
+ const [value, setValue] = (0, import_react15.useState)("");
2630
+ const [interim, setInterim] = (0, import_react15.useState)("");
2552
2631
  const speech = useSpeechRecognition({
2553
2632
  lang: speechLang,
2554
2633
  onFinalTranscript: /* @__PURE__ */ __name((text) => {
@@ -2559,7 +2638,7 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
2559
2638
  }, "onFinalTranscript"),
2560
2639
  onInterimTranscript: /* @__PURE__ */ __name((text) => setInterim(text), "onInterimTranscript")
2561
2640
  });
2562
- (0, import_react14.useEffect)(() => {
2641
+ (0, import_react15.useEffect)(() => {
2563
2642
  if (!speech.isListening) setInterim("");
2564
2643
  }, [
2565
2644
  speech.isListening
@@ -2587,9 +2666,9 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
2587
2666
  const displayValue = speech.isListening && interim ? `${value}${value && !value.endsWith(" ") ? " " : ""}${interim}` : value;
2588
2667
  const showMic = enableSpeech && speech.isSupported;
2589
2668
  const showStop = isStreaming && onStop !== void 0;
2590
- return /* @__PURE__ */ import_react14.default.createElement("div", {
2669
+ return /* @__PURE__ */ import_react15.default.createElement("div", {
2591
2670
  className
2592
- }, /* @__PURE__ */ import_react14.default.createElement("textarea", {
2671
+ }, /* @__PURE__ */ import_react15.default.createElement("textarea", {
2593
2672
  className: textareaClassName,
2594
2673
  rows,
2595
2674
  value: displayValue,
@@ -2600,17 +2679,17 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
2600
2679
  }, "onChange"),
2601
2680
  onKeyDown: handleKeyDown,
2602
2681
  placeholder: placeholder ?? "Ask something (Enter to send, Shift+Enter for newline)"
2603
- }), /* @__PURE__ */ import_react14.default.createElement("button", {
2682
+ }), /* @__PURE__ */ import_react15.default.createElement("button", {
2604
2683
  type: "button",
2605
2684
  className: sendButtonClassName,
2606
2685
  onClick: submit,
2607
2686
  disabled: disabled || !value.trim()
2608
- }, sendLabel), showStop ? /* @__PURE__ */ import_react14.default.createElement("button", {
2687
+ }, sendLabel), showStop ? /* @__PURE__ */ import_react15.default.createElement("button", {
2609
2688
  type: "button",
2610
2689
  className: stopButtonClassName,
2611
2690
  onClick: /* @__PURE__ */ __name(() => void onStop(), "onClick"),
2612
2691
  "aria-label": "Stop generating"
2613
- }, stopLabel) : null, showMic ? /* @__PURE__ */ import_react14.default.createElement("button", {
2692
+ }, stopLabel) : null, showMic ? /* @__PURE__ */ import_react15.default.createElement("button", {
2614
2693
  type: "button",
2615
2694
  className: micButtonClassName,
2616
2695
  onClick: toggleMic,
@@ -2623,10 +2702,10 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
2623
2702
  __name(ChatInput, "ChatInput");
2624
2703
 
2625
2704
  // src/components/message-item.tsx
2626
- var import_react17 = __toESM(require("react"), 1);
2705
+ var import_react18 = __toESM(require("react"), 1);
2627
2706
 
2628
2707
  // src/transcript/use-chat-transcript.ts
2629
- var import_react16 = require("react");
2708
+ var import_react17 = require("react");
2630
2709
 
2631
2710
  // src/transcript/model.ts
2632
2711
  var import_nestjs_agent_core2 = require("@dudousxd/nestjs-agent-core");
@@ -3603,11 +3682,11 @@ function formatCostUsd(cost) {
3603
3682
  __name(formatCostUsd, "formatCostUsd");
3604
3683
 
3605
3684
  // src/transcript/use-stick-to-bottom.ts
3606
- var import_react15 = require("react");
3685
+ var import_react16 = require("react");
3607
3686
  function useStickToBottom({ contentKey, threshold = 32 }) {
3608
- const containerRef = (0, import_react15.useRef)(null);
3609
- const [isAtBottom, setIsAtBottom] = (0, import_react15.useState)(true);
3610
- const measure = (0, import_react15.useCallback)(() => {
3687
+ const containerRef = (0, import_react16.useRef)(null);
3688
+ const [isAtBottom, setIsAtBottom] = (0, import_react16.useState)(true);
3689
+ const measure = (0, import_react16.useCallback)(() => {
3611
3690
  const element = containerRef.current;
3612
3691
  if (!element) {
3613
3692
  return;
@@ -3617,7 +3696,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
3617
3696
  }, [
3618
3697
  threshold
3619
3698
  ]);
3620
- const scrollToBottom = (0, import_react15.useCallback)(() => {
3699
+ const scrollToBottom = (0, import_react16.useCallback)(() => {
3621
3700
  const element = containerRef.current;
3622
3701
  if (!element) {
3623
3702
  return;
@@ -3625,7 +3704,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
3625
3704
  element.scrollTop = element.scrollHeight;
3626
3705
  setIsAtBottom(true);
3627
3706
  }, []);
3628
- const setContainer = (0, import_react15.useCallback)((element) => {
3707
+ const setContainer = (0, import_react16.useCallback)((element) => {
3629
3708
  containerRef.current = element;
3630
3709
  if (element) {
3631
3710
  measure();
@@ -3633,7 +3712,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
3633
3712
  }, [
3634
3713
  measure
3635
3714
  ]);
3636
- (0, import_react15.useEffect)(() => {
3715
+ (0, import_react16.useEffect)(() => {
3637
3716
  if (isAtBottom) {
3638
3717
  scrollToBottom();
3639
3718
  }
@@ -3642,7 +3721,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
3642
3721
  isAtBottom,
3643
3722
  scrollToBottom
3644
3723
  ]);
3645
- const getContainerProps = (0, import_react15.useCallback)(() => ({
3724
+ const getContainerProps = (0, import_react16.useCallback)(() => ({
3646
3725
  ref: setContainer,
3647
3726
  onScroll: measure
3648
3727
  }), [
@@ -3664,14 +3743,14 @@ var DEFAULT_LOAD_EARLIER_STEP = 50;
3664
3743
  var DEFAULT_COPY_RESET_MS = 1500;
3665
3744
  function useChatTranscript(options) {
3666
3745
  const { messages, status, initialVisibleCount = DEFAULT_VISIBLE_COUNT, loadEarlierStep = DEFAULT_LOAD_EARLIER_STEP, followUps, stickToBottomThreshold } = options;
3667
- const latest = (0, import_react16.useRef)(options);
3746
+ const latest = (0, import_react17.useRef)(options);
3668
3747
  latest.current = options;
3669
- const [visibleCount, setVisibleCount] = (0, import_react16.useState)(initialVisibleCount);
3670
- const [stopRequested, setStopRequested] = (0, import_react16.useState)(false);
3748
+ const [visibleCount, setVisibleCount] = (0, import_react17.useState)(initialVisibleCount);
3749
+ const [stopRequested, setStopRequested] = (0, import_react17.useState)(false);
3671
3750
  const isStreaming = status === "streaming" || status === "reconnecting";
3672
3751
  const isBusy = status === "submitted" || isStreaming;
3673
3752
  const isEmpty = messages.length === 0;
3674
- (0, import_react16.useEffect)(() => {
3753
+ (0, import_react17.useEffect)(() => {
3675
3754
  if (!isBusy) {
3676
3755
  setStopRequested(false);
3677
3756
  }
@@ -3688,7 +3767,7 @@ function useChatTranscript(options) {
3688
3767
  streamingMessageId,
3689
3768
  options
3690
3769
  });
3691
- const stop = (0, import_react16.useCallback)(() => {
3770
+ const stop = (0, import_react17.useCallback)(() => {
3692
3771
  const current = latest.current;
3693
3772
  if (current.status !== "submitted" && current.status !== "streaming" && current.status !== "reconnecting") {
3694
3773
  return;
@@ -3696,8 +3775,8 @@ function useChatTranscript(options) {
3696
3775
  setStopRequested(true);
3697
3776
  void current.onStop?.();
3698
3777
  }, []);
3699
- const loadEarlier = (0, import_react16.useCallback)(() => setVisibleCount((count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP)), []);
3700
- const showAll = (0, import_react16.useCallback)(() => setVisibleCount(latest.current.messages.length), []);
3778
+ const loadEarlier = (0, import_react17.useCallback)(() => setVisibleCount((count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP)), []);
3779
+ const showAll = (0, import_react17.useCallback)(() => setVisibleCount(latest.current.messages.length), []);
3701
3780
  const scroll = useStickToBottom({
3702
3781
  contentKey: contentSignature(messages),
3703
3782
  ...stickToBottomThreshold !== void 0 ? {
@@ -3733,7 +3812,7 @@ function useChatTranscript(options) {
3733
3812
  __name(useChatTranscript, "useChatTranscript");
3734
3813
  function useTranscriptItem(options) {
3735
3814
  const { message, isStreaming = false } = options;
3736
- const messagesRef = (0, import_react16.useRef)([
3815
+ const messagesRef = (0, import_react17.useRef)([
3737
3816
  message
3738
3817
  ]);
3739
3818
  if (messagesRef.current[0] !== message) {
@@ -3751,15 +3830,15 @@ function useTranscriptItem(options) {
3751
3830
  }
3752
3831
  __name(useTranscriptItem, "useTranscriptItem");
3753
3832
  function useTranscriptItems({ messages, visibleStart, streamingMessageId, options }) {
3754
- const [drafts, setDrafts] = (0, import_react16.useState)(() => /* @__PURE__ */ new Map());
3755
- const [copied, setCopied] = (0, import_react16.useState)(() => /* @__PURE__ */ new Set());
3756
- const [openReasoning, setOpenReasoning] = (0, import_react16.useState)(() => /* @__PURE__ */ new Map());
3757
- const [picks, setPicks] = (0, import_react16.useState)(() => /* @__PURE__ */ new Map());
3758
- const [settling, setSettling] = (0, import_react16.useState)(() => /* @__PURE__ */ new Map());
3759
- const [settleErrors, setSettleErrors] = (0, import_react16.useState)(() => /* @__PURE__ */ new Map());
3833
+ const [drafts, setDrafts] = (0, import_react17.useState)(() => /* @__PURE__ */ new Map());
3834
+ const [copied, setCopied] = (0, import_react17.useState)(() => /* @__PURE__ */ new Set());
3835
+ const [openReasoning, setOpenReasoning] = (0, import_react17.useState)(() => /* @__PURE__ */ new Map());
3836
+ const [picks, setPicks] = (0, import_react17.useState)(() => /* @__PURE__ */ new Map());
3837
+ const [settling, setSettling] = (0, import_react17.useState)(() => /* @__PURE__ */ new Map());
3838
+ const [settleErrors, setSettleErrors] = (0, import_react17.useState)(() => /* @__PURE__ */ new Map());
3760
3839
  const backend = useAgentBackend();
3761
3840
  const handlers = settleHandlers(options, backend);
3762
- const latest = (0, import_react16.useRef)({
3841
+ const latest = (0, import_react17.useRef)({
3763
3842
  options,
3764
3843
  handlers,
3765
3844
  drafts,
@@ -3773,23 +3852,23 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3773
3852
  picks,
3774
3853
  messages
3775
3854
  };
3776
- const copyTimers = (0, import_react16.useRef)(/* @__PURE__ */ new Map());
3777
- (0, import_react16.useEffect)(() => () => {
3855
+ const copyTimers = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
3856
+ (0, import_react17.useEffect)(() => () => {
3778
3857
  for (const timer of copyTimers.current.values()) {
3779
3858
  clearTimeout(timer);
3780
3859
  }
3781
3860
  copyTimers.current.clear();
3782
3861
  }, []);
3783
- const callbackCache = (0, import_react16.useRef)(/* @__PURE__ */ new Map());
3784
- const reasoningToggleCache = (0, import_react16.useRef)(/* @__PURE__ */ new Map());
3785
- const toggleReasoning = (0, import_react16.useCallback)((key, open) => {
3862
+ const callbackCache = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
3863
+ const reasoningToggleCache = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
3864
+ const toggleReasoning = (0, import_react17.useCallback)((key, open) => {
3786
3865
  setOpenReasoning((current) => {
3787
3866
  const next = new Map(current);
3788
3867
  next.set(key, open ?? !(current.get(key) ?? false));
3789
3868
  return next;
3790
3869
  });
3791
3870
  }, []);
3792
- const stableToggle = (0, import_react16.useCallback)((key) => {
3871
+ const stableToggle = (0, import_react17.useCallback)((key) => {
3793
3872
  let cached = reasoningToggleCache.current.get(key);
3794
3873
  if (!cached) {
3795
3874
  cached = /* @__PURE__ */ __name((open) => toggleReasoning(key, open), "cached");
@@ -3799,10 +3878,10 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3799
3878
  }, [
3800
3879
  toggleReasoning
3801
3880
  ]);
3802
- const pick = (0, import_react16.useCallback)((toolCallId, questionId, values) => {
3881
+ const pick = (0, import_react17.useCallback)((toolCallId, questionId, values) => {
3803
3882
  setPicks((current) => new Map(current).set(pickKey(toolCallId, questionId), values));
3804
3883
  }, []);
3805
- const settle = (0, import_react16.useCallback)((toolCallId, action, send) => {
3884
+ const settle = (0, import_react17.useCallback)((toolCallId, action, send) => {
3806
3885
  setSettleErrors((current) => {
3807
3886
  if (!current.has(toolCallId)) {
3808
3887
  return current;
@@ -3826,7 +3905,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3826
3905
  failed(error);
3827
3906
  }
3828
3907
  }, []);
3829
- const answer = (0, import_react16.useCallback)((toolCallId) => {
3908
+ const answer = (0, import_react17.useCallback)((toolCallId) => {
3830
3909
  const current = latest.current;
3831
3910
  const onAnswer = current.handlers.onAnswer;
3832
3911
  if (!onAnswer) {
@@ -3839,7 +3918,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3839
3918
  }, [
3840
3919
  settle
3841
3920
  ]);
3842
- const skip = (0, import_react16.useCallback)((toolCallId) => {
3921
+ const skip = (0, import_react17.useCallback)((toolCallId) => {
3843
3922
  const onSkip = latest.current.handlers.onSkip;
3844
3923
  if (onSkip) {
3845
3924
  settle(toolCallId, "skip", () => onSkip({
@@ -3849,7 +3928,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3849
3928
  }, [
3850
3929
  settle
3851
3930
  ]);
3852
- const approve = (0, import_react16.useCallback)((toolCallId, options2) => {
3931
+ const approve = (0, import_react17.useCallback)((toolCallId, options2) => {
3853
3932
  const onApprove = latest.current.handlers.onApprove;
3854
3933
  if (onApprove) {
3855
3934
  settle(toolCallId, "approve", () => onApprove({
@@ -3862,7 +3941,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3862
3941
  }, [
3863
3942
  settle
3864
3943
  ]);
3865
- const reject = (0, import_react16.useCallback)((toolCallId) => {
3944
+ const reject = (0, import_react17.useCallback)((toolCallId) => {
3866
3945
  const onReject = latest.current.handlers.onReject;
3867
3946
  if (onReject) {
3868
3947
  settle(toolCallId, "reject", () => onReject({
@@ -3872,7 +3951,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3872
3951
  }, [
3873
3952
  settle
3874
3953
  ]);
3875
- const callbacksFor = (0, import_react16.useCallback)((id) => {
3954
+ const callbacksFor = (0, import_react17.useCallback)((id) => {
3876
3955
  const cached = callbackCache.current.get(id);
3877
3956
  if (cached) {
3878
3957
  return cached;
@@ -4158,7 +4237,7 @@ function MessageItem({ message, isStreaming = false, editable, onEditSubmit, reg
4158
4237
  getCreatedAt: /* @__PURE__ */ __name(() => createdAt, "getCreatedAt")
4159
4238
  } : {}
4160
4239
  });
4161
- return /* @__PURE__ */ import_react17.default.createElement(MessageItemView, {
4240
+ return /* @__PURE__ */ import_react18.default.createElement(MessageItemView, {
4162
4241
  item,
4163
4242
  ...slots
4164
4243
  });
@@ -4171,51 +4250,51 @@ function MessageItemView({ item, ...given }) {
4171
4250
  renderUi: ambientRenderUi
4172
4251
  } : given;
4173
4252
  const { classNames } = slots;
4174
- const actionRow = /* @__PURE__ */ import_react17.default.createElement("div", {
4253
+ const actionRow = /* @__PURE__ */ import_react18.default.createElement("div", {
4175
4254
  className: classNames?.actions,
4176
4255
  "data-actions-for": item.role
4177
- }, item.copy.available ? /* @__PURE__ */ import_react17.default.createElement("button", {
4256
+ }, item.copy.available ? /* @__PURE__ */ import_react18.default.createElement("button", {
4178
4257
  type: "button",
4179
4258
  onClick: item.copy.copy,
4180
4259
  className: classNames?.actionButton,
4181
4260
  title: item.copy.copied ? "Copied!" : "Copy message text"
4182
- }, item.copy.copied ? "Copied" : "Copy") : null, item.fork.available ? /* @__PURE__ */ import_react17.default.createElement("button", {
4261
+ }, item.copy.copied ? "Copied" : "Copy") : null, item.fork.available ? /* @__PURE__ */ import_react18.default.createElement("button", {
4183
4262
  type: "button",
4184
4263
  onClick: item.fork.run,
4185
4264
  className: classNames?.actionButton,
4186
4265
  title: "Fork thread from this message"
4187
- }, "Fork") : null, item.regenerate.available ? /* @__PURE__ */ import_react17.default.createElement("button", {
4266
+ }, "Fork") : null, item.regenerate.available ? /* @__PURE__ */ import_react18.default.createElement("button", {
4188
4267
  type: "button",
4189
4268
  onClick: item.regenerate.run,
4190
4269
  className: classNames?.actionButton,
4191
4270
  title: "Regenerate response"
4192
- }, "Regenerate") : null, slots.meta, !item.isUser && item.usage ? /* @__PURE__ */ import_react17.default.createElement("span", {
4271
+ }, "Regenerate") : null, slots.meta, !item.isUser && item.usage ? /* @__PURE__ */ import_react18.default.createElement("span", {
4193
4272
  className: classNames?.usage,
4194
4273
  title: `Input ${item.usage.inputTokens.toLocaleString()} \xB7 Output ${item.usage.outputTokens.toLocaleString()} tokens`
4195
- }, item.usage.costLabel, " \xB7 ", item.usage.tokensLabel) : null, item.timestamp ? /* @__PURE__ */ import_react17.default.createElement("span", {
4274
+ }, item.usage.costLabel, " \xB7 ", item.usage.tokensLabel) : null, item.timestamp ? /* @__PURE__ */ import_react18.default.createElement("span", {
4196
4275
  className: classNames?.timestamp,
4197
4276
  title: item.timestamp.absolute
4198
4277
  }, item.timestamp.relative) : null);
4199
4278
  if (item.edit.available) {
4200
- return /* @__PURE__ */ import_react17.default.createElement(EditableUserBubble, {
4279
+ return /* @__PURE__ */ import_react18.default.createElement(EditableUserBubble, {
4201
4280
  item,
4202
4281
  slots,
4203
4282
  actions: actionRow
4204
4283
  });
4205
4284
  }
4206
4285
  const className = joinClasses(classNames?.root, classNames?.byRole?.[item.role]);
4207
- return /* @__PURE__ */ import_react17.default.createElement("div", {
4286
+ return /* @__PURE__ */ import_react18.default.createElement("div", {
4208
4287
  className,
4209
4288
  "data-role": item.role,
4210
4289
  "data-streaming": item.isStreaming ? "true" : void 0
4211
- }, /* @__PURE__ */ import_react17.default.createElement("div", null, renderBlocks(item, slots)), actionRow);
4290
+ }, /* @__PURE__ */ import_react18.default.createElement("div", null, renderBlocks(item, slots)), actionRow);
4212
4291
  }
4213
4292
  __name(MessageItemView, "MessageItemView");
4214
4293
  function renderBlocks(item, slots) {
4215
4294
  const nodes = [];
4216
4295
  for (const block of item.blocks) {
4217
4296
  if (block.kind === "text") {
4218
- nodes.push(/* @__PURE__ */ import_react17.default.createElement("div", {
4297
+ nodes.push(/* @__PURE__ */ import_react18.default.createElement("div", {
4219
4298
  key: block.key,
4220
4299
  className: slots.classNames?.text
4221
4300
  }, slots.renderText ? slots.renderText(block.text, {
@@ -4236,7 +4315,7 @@ function renderBlocks(item, slots) {
4236
4315
  continue;
4237
4316
  }
4238
4317
  if (block.kind === "ui" && slots.renderUi) {
4239
- nodes.push(/* @__PURE__ */ import_react17.default.createElement("div", {
4318
+ nodes.push(/* @__PURE__ */ import_react18.default.createElement("div", {
4240
4319
  key: block.key,
4241
4320
  "data-slot": "ui",
4242
4321
  "data-component": block.component
@@ -4247,18 +4326,18 @@ function renderBlocks(item, slots) {
4247
4326
  }
4248
4327
  __name(renderBlocks, "renderBlocks");
4249
4328
  function renderFilesBlock(block, slots) {
4250
- return /* @__PURE__ */ import_react17.default.createElement("div", {
4329
+ return /* @__PURE__ */ import_react18.default.createElement("div", {
4251
4330
  key: block.key,
4252
4331
  className: slots.classNames?.files,
4253
4332
  "data-files": "true"
4254
- }, slots.renderFiles ? slots.renderFiles(block.files) : block.files.map((file) => /* @__PURE__ */ import_react17.default.createElement("a", {
4333
+ }, slots.renderFiles ? slots.renderFiles(block.files) : block.files.map((file) => /* @__PURE__ */ import_react18.default.createElement("a", {
4255
4334
  key: file.url,
4256
4335
  href: file.url,
4257
4336
  target: "_blank",
4258
4337
  rel: "noreferrer",
4259
4338
  className: slots.classNames?.file,
4260
4339
  title: file.filename ?? file.mediaType
4261
- }, file.isImage ? /* @__PURE__ */ import_react17.default.createElement("img", {
4340
+ }, file.isImage ? /* @__PURE__ */ import_react18.default.createElement("img", {
4262
4341
  src: file.url,
4263
4342
  alt: file.filename ?? "image",
4264
4343
  className: slots.classNames?.fileImage
@@ -4266,17 +4345,17 @@ function renderFilesBlock(block, slots) {
4266
4345
  }
4267
4346
  __name(renderFilesBlock, "renderFilesBlock");
4268
4347
  function renderReasoningBlock(block, slots) {
4269
- return /* @__PURE__ */ import_react17.default.createElement("div", {
4348
+ return /* @__PURE__ */ import_react18.default.createElement("div", {
4270
4349
  key: block.key,
4271
4350
  className: slots.classNames?.reasoning,
4272
4351
  "data-reasoning": "true",
4273
4352
  "data-streaming": block.isStreaming ? "true" : void 0
4274
- }, /* @__PURE__ */ import_react17.default.createElement("button", {
4353
+ }, /* @__PURE__ */ import_react18.default.createElement("button", {
4275
4354
  type: "button",
4276
4355
  className: slots.classNames?.reasoningToggle,
4277
4356
  onClick: /* @__PURE__ */ __name(() => block.toggle(), "onClick"),
4278
4357
  "aria-expanded": block.isOpen
4279
- }, slots.reasoningLabel ?? "Reasoning"), block.isOpen ? /* @__PURE__ */ import_react17.default.createElement("div", {
4358
+ }, slots.reasoningLabel ?? "Reasoning"), block.isOpen ? /* @__PURE__ */ import_react18.default.createElement("div", {
4280
4359
  className: slots.classNames?.reasoningText
4281
4360
  }, slots.renderReasoning ? slots.renderReasoning(block.text, {
4282
4361
  isStreaming: block.isStreaming,
@@ -4287,7 +4366,7 @@ __name(renderReasoningBlock, "renderReasoningBlock");
4287
4366
  function renderToolBlock(item, block, slots) {
4288
4367
  if (slots.renderToolGroup) {
4289
4368
  return [
4290
- /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, {
4369
+ /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, {
4291
4370
  key: block.key
4292
4371
  }, slots.renderToolGroup(block.parts, block.key))
4293
4372
  ];
@@ -4298,7 +4377,7 @@ function renderToolBlock(item, block, slots) {
4298
4377
  const renderToolPart = slots.renderToolPart;
4299
4378
  return block.parts.map((part) => {
4300
4379
  const partKey = `${item.id}-${part.toolCallId}`;
4301
- return /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, {
4380
+ return /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, {
4302
4381
  key: partKey
4303
4382
  }, renderToolPart(part, partKey));
4304
4383
  });
@@ -4308,14 +4387,14 @@ function EditableUserBubble({ item, slots, actions }) {
4308
4387
  const { classNames } = slots;
4309
4388
  const { edit } = item;
4310
4389
  if (!edit.isEditing) {
4311
- return /* @__PURE__ */ import_react17.default.createElement("div", {
4390
+ return /* @__PURE__ */ import_react18.default.createElement("div", {
4312
4391
  className: joinClasses(classNames?.root, classNames?.byRole?.user),
4313
4392
  "data-role": "user"
4314
- }, /* @__PURE__ */ import_react17.default.createElement("div", {
4393
+ }, /* @__PURE__ */ import_react18.default.createElement("div", {
4315
4394
  className: classNames?.text
4316
4395
  }, slots.renderText ? slots.renderText(item.text, {
4317
4396
  isStreaming: false
4318
- }) : item.text), /* @__PURE__ */ import_react17.default.createElement("button", {
4397
+ }) : item.text), /* @__PURE__ */ import_react18.default.createElement("button", {
4319
4398
  type: "button",
4320
4399
  onClick: edit.start,
4321
4400
  className: classNames?.actionButton,
@@ -4323,18 +4402,18 @@ function EditableUserBubble({ item, slots, actions }) {
4323
4402
  }, "Edit"), actions);
4324
4403
  }
4325
4404
  const textareaProps = edit.getTextareaProps();
4326
- return /* @__PURE__ */ import_react17.default.createElement("div", {
4405
+ return /* @__PURE__ */ import_react18.default.createElement("div", {
4327
4406
  "data-editing": "true"
4328
- }, /* @__PURE__ */ import_react17.default.createElement("textarea", {
4407
+ }, /* @__PURE__ */ import_react18.default.createElement("textarea", {
4329
4408
  ...textareaProps,
4330
4409
  rows: Math.min(8, edit.draft.split("\n").length + 1),
4331
4410
  className: classNames?.editTextarea
4332
- }), /* @__PURE__ */ import_react17.default.createElement("div", {
4411
+ }), /* @__PURE__ */ import_react18.default.createElement("div", {
4333
4412
  className: classNames?.editActions
4334
- }, /* @__PURE__ */ import_react17.default.createElement("button", {
4413
+ }, /* @__PURE__ */ import_react18.default.createElement("button", {
4335
4414
  type: "button",
4336
4415
  onClick: edit.cancel
4337
- }, "Cancel"), /* @__PURE__ */ import_react17.default.createElement("button", {
4416
+ }, "Cancel"), /* @__PURE__ */ import_react18.default.createElement("button", {
4338
4417
  type: "button",
4339
4418
  onClick: edit.save,
4340
4419
  disabled: !edit.canSave
@@ -4578,35 +4657,35 @@ function toItem(entry) {
4578
4657
  __name(toItem, "toItem");
4579
4658
 
4580
4659
  // src/composer/use-composer-autocomplete.ts
4581
- var import_react18 = require("react");
4660
+ var import_react19 = require("react");
4582
4661
  function useComposerAutocomplete(options) {
4583
4662
  const { value, sources, acceptOnTab = true } = options;
4584
- const latest = (0, import_react18.useRef)(options);
4663
+ const latest = (0, import_react19.useRef)(options);
4585
4664
  latest.current = options;
4586
- const inputRef = (0, import_react18.useRef)(null);
4587
- const [caret, setCaret] = (0, import_react18.useState)(value.length);
4588
- const [items, setItems] = (0, import_react18.useState)([]);
4589
- const [isLoading, setLoading] = (0, import_react18.useState)(false);
4590
- const [error, setError] = (0, import_react18.useState)(null);
4591
- const [activeIndex, setActiveIndex] = (0, import_react18.useState)(0);
4592
- const [dismissedIndex, setDismissedIndex] = (0, import_react18.useState)(null);
4665
+ const inputRef = (0, import_react19.useRef)(null);
4666
+ const [caret, setCaret] = (0, import_react19.useState)(value.length);
4667
+ const [items, setItems] = (0, import_react19.useState)([]);
4668
+ const [isLoading, setLoading] = (0, import_react19.useState)(false);
4669
+ const [error, setError] = (0, import_react19.useState)(null);
4670
+ const [activeIndex, setActiveIndex] = (0, import_react19.useState)(0);
4671
+ const [dismissedIndex, setDismissedIndex] = (0, import_react19.useState)(null);
4593
4672
  const safeCaret = Math.min(caret, value.length);
4594
- const match = (0, import_react18.useMemo)(() => findActiveTrigger(value, safeCaret, sources), [
4673
+ const match = (0, import_react19.useMemo)(() => findActiveTrigger(value, safeCaret, sources), [
4595
4674
  value,
4596
4675
  safeCaret,
4597
4676
  sources
4598
4677
  ]);
4599
4678
  const isActive = match !== null && dismissedIndex !== match.index;
4600
- const matchRef = (0, import_react18.useRef)(match);
4679
+ const matchRef = (0, import_react19.useRef)(match);
4601
4680
  matchRef.current = match;
4602
- const caretRef = (0, import_react18.useRef)(safeCaret);
4681
+ const caretRef = (0, import_react19.useRef)(safeCaret);
4603
4682
  caretRef.current = safeCaret;
4604
- const itemsRef = (0, import_react18.useRef)(items);
4683
+ const itemsRef = (0, import_react19.useRef)(items);
4605
4684
  itemsRef.current = items;
4606
- const activeIndexRef = (0, import_react18.useRef)(activeIndex);
4685
+ const activeIndexRef = (0, import_react19.useRef)(activeIndex);
4607
4686
  activeIndexRef.current = activeIndex;
4608
4687
  const requestKey = isActive && match ? `${match.source.id}\0${match.query}` : null;
4609
- (0, import_react18.useEffect)(() => {
4688
+ (0, import_react19.useEffect)(() => {
4610
4689
  const current = matchRef.current;
4611
4690
  if (requestKey === null || current === null) {
4612
4691
  setItems([]);
@@ -4654,25 +4733,25 @@ function useComposerAutocomplete(options) {
4654
4733
  ]);
4655
4734
  const isOpen = isActive;
4656
4735
  const activeItem = isOpen ? items[activeIndex] ?? null : null;
4657
- const reactId = (0, import_react18.useId)();
4736
+ const reactId = (0, import_react19.useId)();
4658
4737
  const listboxId = options.id ?? `agent-autocomplete-${reactId}`;
4659
- const optionId = (0, import_react18.useCallback)((index) => `${listboxId}-option-${index}`, [
4738
+ const optionId = (0, import_react19.useCallback)((index) => `${listboxId}-option-${index}`, [
4660
4739
  listboxId
4661
4740
  ]);
4662
- const highlight = (0, import_react18.useCallback)((index) => {
4741
+ const highlight = (0, import_react19.useCallback)((index) => {
4663
4742
  const total = itemsRef.current.length;
4664
4743
  if (total === 0) return;
4665
4744
  setActiveIndex((index % total + total) % total);
4666
4745
  }, []);
4667
- const moveHighlight = (0, import_react18.useCallback)((delta) => highlight(activeIndexRef.current + delta), [
4746
+ const moveHighlight = (0, import_react19.useCallback)((delta) => highlight(activeIndexRef.current + delta), [
4668
4747
  highlight
4669
4748
  ]);
4670
- const dismiss = (0, import_react18.useCallback)(() => {
4749
+ const dismiss = (0, import_react19.useCallback)(() => {
4671
4750
  const current = matchRef.current;
4672
4751
  if (current) setDismissedIndex(current.index);
4673
4752
  }, []);
4674
- const pendingCaret = (0, import_react18.useRef)(null);
4675
- const accept = (0, import_react18.useCallback)((item) => {
4753
+ const pendingCaret = (0, import_react19.useRef)(null);
4754
+ const accept = (0, import_react19.useCallback)((item) => {
4676
4755
  const current = matchRef.current;
4677
4756
  if (!current) return;
4678
4757
  const chosen = item ?? itemsRef.current[activeIndexRef.current];
@@ -4683,16 +4762,16 @@ function useComposerAutocomplete(options) {
4683
4762
  setDismissedIndex(null);
4684
4763
  pendingCaret.current = edit.caret;
4685
4764
  }, []);
4686
- (0, import_react18.useLayoutEffect)(() => {
4765
+ (0, import_react19.useLayoutEffect)(() => {
4687
4766
  const position = pendingCaret.current;
4688
4767
  if (position === null) return;
4689
4768
  pendingCaret.current = null;
4690
4769
  inputRef.current?.setSelectionRange(position, position);
4691
4770
  });
4692
- const readCaret = (0, import_react18.useCallback)((element) => {
4771
+ const readCaret = (0, import_react19.useCallback)((element) => {
4693
4772
  setCaret(element.selectionStart ?? element.value.length);
4694
4773
  }, []);
4695
- const onKeyDown = (0, import_react18.useCallback)((event) => {
4774
+ const onKeyDown = (0, import_react19.useCallback)((event) => {
4696
4775
  if (!isOpen) return;
4697
4776
  const hasItems = itemsRef.current.length > 0;
4698
4777
  switch (event.key) {
@@ -4730,23 +4809,23 @@ function useComposerAutocomplete(options) {
4730
4809
  dismiss,
4731
4810
  moveHighlight
4732
4811
  ]);
4733
- const onChange = (0, import_react18.useCallback)((event) => {
4812
+ const onChange = (0, import_react19.useCallback)((event) => {
4734
4813
  readCaret(event.target);
4735
4814
  const next = findActiveTrigger(event.target.value, event.target.selectionStart ?? event.target.value.length, latest.current.sources);
4736
4815
  setDismissedIndex((current) => current !== null && next?.index === current ? current : null);
4737
4816
  }, [
4738
4817
  readCaret
4739
4818
  ]);
4740
- const onSelect = (0, import_react18.useCallback)((event) => readCaret(event.currentTarget), [
4819
+ const onSelect = (0, import_react19.useCallback)((event) => readCaret(event.currentTarget), [
4741
4820
  readCaret
4742
4821
  ]);
4743
- const onClick = (0, import_react18.useCallback)((event) => readCaret(event.currentTarget), [
4822
+ const onClick = (0, import_react19.useCallback)((event) => readCaret(event.currentTarget), [
4744
4823
  readCaret
4745
4824
  ]);
4746
- const setInput = (0, import_react18.useCallback)((element) => {
4825
+ const setInput = (0, import_react19.useCallback)((element) => {
4747
4826
  inputRef.current = element;
4748
4827
  }, []);
4749
- const getInputProps = (0, import_react18.useCallback)(() => ({
4828
+ const getInputProps = (0, import_react19.useCallback)(() => ({
4750
4829
  ref: setInput,
4751
4830
  onChange,
4752
4831
  onKeyDown,
@@ -4774,7 +4853,7 @@ function useComposerAutocomplete(options) {
4774
4853
  activeIndex,
4775
4854
  optionId
4776
4855
  ]);
4777
- const getListboxProps = (0, import_react18.useCallback)(() => ({
4856
+ const getListboxProps = (0, import_react19.useCallback)(() => ({
4778
4857
  id: listboxId,
4779
4858
  role: "listbox",
4780
4859
  "aria-label": match?.source.label ?? match?.source.id ?? "Suggestions"
@@ -4782,7 +4861,7 @@ function useComposerAutocomplete(options) {
4782
4861
  listboxId,
4783
4862
  match
4784
4863
  ]);
4785
- const getOptionProps = (0, import_react18.useCallback)((index) => ({
4864
+ const getOptionProps = (0, import_react19.useCallback)((index) => ({
4786
4865
  id: optionId(index),
4787
4866
  role: "option",
4788
4867
  "aria-selected": index === activeIndex
@@ -4816,13 +4895,13 @@ function isPromise(value) {
4816
4895
  __name(isPromise, "isPromise");
4817
4896
 
4818
4897
  // src/presentation/use-tool-catalog.ts
4819
- var import_react19 = require("react");
4820
- var shared = /* @__PURE__ */ new WeakMap();
4821
- function load(client, agent) {
4822
- let byAgent = shared.get(client);
4898
+ var import_react20 = require("react");
4899
+ var shared2 = /* @__PURE__ */ new WeakMap();
4900
+ function load2(client, agent) {
4901
+ let byAgent = shared2.get(client);
4823
4902
  if (byAgent === void 0) {
4824
4903
  byAgent = /* @__PURE__ */ new Map();
4825
- shared.set(client, byAgent);
4904
+ shared2.set(client, byAgent);
4826
4905
  }
4827
4906
  const key = agent ?? "";
4828
4907
  const cached = byAgent.get(key);
@@ -4837,22 +4916,22 @@ function load(client, agent) {
4837
4916
  byAgent.set(key, request);
4838
4917
  return request;
4839
4918
  }
4840
- __name(load, "load");
4919
+ __name(load2, "load");
4841
4920
  function useToolCatalog(options = {}) {
4842
4921
  const { agent, enabled = true } = options;
4843
4922
  const client = useAgentBackend(options.backend);
4844
- const [entries, setEntries] = (0, import_react19.useState)([]);
4845
- const [isLoading, setLoading] = (0, import_react19.useState)(enabled);
4846
- const [error, setError] = (0, import_react19.useState)(null);
4847
- const [generation, setGeneration] = (0, import_react19.useState)(0);
4848
- (0, import_react19.useEffect)(() => {
4923
+ const [entries, setEntries] = (0, import_react20.useState)([]);
4924
+ const [isLoading, setLoading] = (0, import_react20.useState)(enabled);
4925
+ const [error, setError] = (0, import_react20.useState)(null);
4926
+ const [generation, setGeneration] = (0, import_react20.useState)(0);
4927
+ (0, import_react20.useEffect)(() => {
4849
4928
  if (!enabled) {
4850
4929
  setLoading(false);
4851
4930
  return;
4852
4931
  }
4853
4932
  let cancelled = false;
4854
4933
  setLoading(true);
4855
- load(client, agent).then((loaded) => {
4934
+ load2(client, agent).then((loaded) => {
4856
4935
  if (cancelled) return;
4857
4936
  setEntries(Array.isArray(loaded) ? loaded : []);
4858
4937
  setError(null);
@@ -4871,14 +4950,14 @@ function useToolCatalog(options = {}) {
4871
4950
  enabled,
4872
4951
  generation
4873
4952
  ]);
4874
- const refresh = (0, import_react19.useCallback)(() => {
4875
- shared.get(client)?.delete(agent ?? "");
4953
+ const refresh = (0, import_react20.useCallback)(() => {
4954
+ shared2.get(client)?.delete(agent ?? "");
4876
4955
  setGeneration((current) => current + 1);
4877
4956
  }, [
4878
4957
  client,
4879
4958
  agent
4880
4959
  ]);
4881
- const catalog = (0, import_react19.useMemo)(() => toolCatalogFrom(entries), [
4960
+ const catalog = (0, import_react20.useMemo)(() => toolCatalogFrom(entries), [
4882
4961
  entries
4883
4962
  ]);
4884
4963
  return {
@@ -4892,7 +4971,7 @@ function useToolCatalog(options = {}) {
4892
4971
  __name(useToolCatalog, "useToolCatalog");
4893
4972
 
4894
4973
  // src/approvals/countdown.ts
4895
- var import_react20 = require("react");
4974
+ var import_react21 = require("react");
4896
4975
  function approvalCountdown(expiresAt, now = Date.now()) {
4897
4976
  const deadline = expiresAt == null ? Number.NaN : Date.parse(expiresAt);
4898
4977
  if (!Number.isFinite(deadline)) {
@@ -4910,10 +4989,10 @@ function approvalCountdown(expiresAt, now = Date.now()) {
4910
4989
  __name(approvalCountdown, "approvalCountdown");
4911
4990
  function useApprovalCountdown(expiresAt, options = {}) {
4912
4991
  const { intervalMs = 1e3 } = options;
4913
- const nowRef = (0, import_react20.useRef)(options.now ?? Date.now);
4992
+ const nowRef = (0, import_react21.useRef)(options.now ?? Date.now);
4914
4993
  nowRef.current = options.now ?? Date.now;
4915
- const [state, setState] = (0, import_react20.useState)(() => approvalCountdown(expiresAt, nowRef.current()));
4916
- (0, import_react20.useEffect)(() => {
4994
+ const [state, setState] = (0, import_react21.useState)(() => approvalCountdown(expiresAt, nowRef.current()));
4995
+ (0, import_react21.useEffect)(() => {
4917
4996
  const read = /* @__PURE__ */ __name(() => approvalCountdown(expiresAt, nowRef.current()), "read");
4918
4997
  const first = read();
4919
4998
  setState(first);
@@ -5049,13 +5128,19 @@ function storedMessageToUiMessage(message) {
5049
5128
  for (const call of message.toolCalls ?? []) {
5050
5129
  const result = message.toolResults?.find((candidate) => candidate.id === call.id);
5051
5130
  const toolKind2 = call.kind;
5131
+ const toolMetadata = {
5132
+ ...toolKind2 !== void 0 ? {
5133
+ toolKind: toolKind2
5134
+ } : {},
5135
+ ...call.parentId !== void 0 ? {
5136
+ parentId: call.parentId
5137
+ } : {}
5138
+ };
5052
5139
  parts.push({
5053
5140
  type: `tool-${call.name}`,
5054
5141
  toolCallId: call.id,
5055
- ...toolKind2 !== void 0 ? {
5056
- toolMetadata: {
5057
- toolKind: toolKind2
5058
- }
5142
+ ...Object.keys(toolMetadata).length > 0 ? {
5143
+ toolMetadata
5059
5144
  } : {},
5060
5145
  ...result !== void 0 ? isRefusal(result) ? {
5061
5146
  // A declined action is NOT an available output. Reloading a thread used to bring one
@@ -5083,6 +5168,8 @@ function storedMessageToUiMessage(message) {
5083
5168
  parts.push(...pushedByCall.get(call.id) ?? []);
5084
5169
  }
5085
5170
  const metadata = {
5171
+ // The host's own facts first: the library's keys win on a clash.
5172
+ ...message.metadata,
5086
5173
  ...message.feedback !== void 0 ? {
5087
5174
  feedback: message.feedback
5088
5175
  } : {},
@@ -5142,6 +5229,8 @@ function mergeTurn(rows) {
5142
5229
  const feedback = lastRow.feedback;
5143
5230
  const createdAt = rows[0]?.createdAt;
5144
5231
  const metadata = {
5232
+ // Host facts of every row, a later row's winning (the turn's final state), under the library's.
5233
+ ...Object.assign({}, ...rows.map((row) => row.metadata ?? {})),
5145
5234
  ...usage !== void 0 ? {
5146
5235
  usage
5147
5236
  } : {},
@@ -5177,8 +5266,8 @@ function sumUsage(rows) {
5177
5266
  __name(sumUsage, "sumUsage");
5178
5267
 
5179
5268
  // src/use-agent-chat.ts
5180
- var import_react21 = require("@ai-sdk/react");
5181
- var import_react22 = require("react");
5269
+ var import_react22 = require("@ai-sdk/react");
5270
+ var import_react23 = require("react");
5182
5271
  var localChatSequence = 0;
5183
5272
  function localChatId() {
5184
5273
  localChatSequence += 1;
@@ -5186,13 +5275,13 @@ function localChatId() {
5186
5275
  }
5187
5276
  __name(localChatId, "localChatId");
5188
5277
  function useAgentChat(options = {}) {
5189
- const latest = (0, import_react22.useRef)(options);
5278
+ const latest = (0, import_react23.useRef)(options);
5190
5279
  latest.current = options;
5191
5280
  const resolved = useAgentBackend(options.backend);
5192
- const client = (0, import_react22.useRef)(resolved).current;
5193
- const createdThreadId = (0, import_react22.useRef)(void 0);
5194
- const chatIdRef = (0, import_react22.useRef)(options.threadId ?? localChatId());
5195
- const boundThreadRef = (0, import_react22.useRef)(options.threadId);
5281
+ const client = (0, import_react23.useRef)(resolved).current;
5282
+ const createdThreadId = (0, import_react23.useRef)(void 0);
5283
+ const chatIdRef = (0, import_react23.useRef)(options.threadId ?? localChatId());
5284
+ const boundThreadRef = (0, import_react23.useRef)(options.threadId);
5196
5285
  if (options.threadId !== boundThreadRef.current) {
5197
5286
  boundThreadRef.current = options.threadId;
5198
5287
  const adopting = options.threadId !== void 0 && options.threadId === createdThreadId.current;
@@ -5202,26 +5291,26 @@ function useAgentChat(options = {}) {
5202
5291
  }
5203
5292
  }
5204
5293
  const chatId = chatIdRef.current;
5205
- const [runId, setRunId] = (0, import_react22.useState)(options.resumeRunId);
5206
- const runIdRef = (0, import_react22.useRef)(runId);
5294
+ const [runId, setRunId] = (0, import_react23.useState)(options.resumeRunId);
5295
+ const runIdRef = (0, import_react23.useRef)(runId);
5207
5296
  runIdRef.current = runId;
5208
- const settlingRunIdRef = (0, import_react22.useRef)(void 0);
5209
- const autoResumeRunIdRef = (0, import_react22.useRef)(void 0);
5210
- const [activeRunId, setActiveRunId] = (0, import_react22.useState)(null);
5211
- const [isLoadingHistory, setIsLoadingHistory] = (0, import_react22.useState)(false);
5212
- const [historyError, setHistoryError] = (0, import_react22.useState)(null);
5213
- const [threadModel, setThreadModel] = (0, import_react22.useState)(null);
5214
- const [pickedModel, setPickedModel] = (0, import_react22.useState)(void 0);
5215
- const pickedModelRef = (0, import_react22.useRef)(pickedModel);
5297
+ const settlingRunIdRef = (0, import_react23.useRef)(void 0);
5298
+ const autoResumeRunIdRef = (0, import_react23.useRef)(void 0);
5299
+ const [activeRunId, setActiveRunId] = (0, import_react23.useState)(null);
5300
+ const [isLoadingHistory, setIsLoadingHistory] = (0, import_react23.useState)(false);
5301
+ const [historyError, setHistoryError] = (0, import_react23.useState)(null);
5302
+ const [threadModel, setThreadModel] = (0, import_react23.useState)(null);
5303
+ const [pickedModel, setPickedModel] = (0, import_react23.useState)(void 0);
5304
+ const pickedModelRef = (0, import_react23.useRef)(pickedModel);
5216
5305
  pickedModelRef.current = pickedModel;
5217
- const pendingPin = (0, import_react22.useRef)(void 0);
5218
- const regenerateNext = (0, import_react22.useRef)(false);
5219
- const currentThreadId = (0, import_react22.useCallback)(() => latest.current.threadId ?? createdThreadId.current, []);
5220
- const [connection, setConnection] = (0, import_react22.useState)({
5306
+ const pendingPin = (0, import_react23.useRef)(void 0);
5307
+ const regenerateNext = (0, import_react23.useRef)(false);
5308
+ const currentThreadId = (0, import_react23.useCallback)(() => latest.current.threadId ?? createdThreadId.current, []);
5309
+ const [connection, setConnection] = (0, import_react23.useState)({
5221
5310
  status: "live"
5222
5311
  });
5223
- const resyncAfterSettle = (0, import_react22.useRef)(false);
5224
- const transport = (0, import_react22.useMemo)(() => {
5312
+ const resyncAfterSettle = (0, import_react23.useRef)(false);
5313
+ const transport = (0, import_react23.useMemo)(() => {
5225
5314
  function onMeta(meta) {
5226
5315
  settlingRunIdRef.current = meta.runId;
5227
5316
  setRunId(meta.runId);
@@ -5263,6 +5352,11 @@ function useAgentChat(options = {}) {
5263
5352
  const threadId = currentThreadId();
5264
5353
  const model = current.model ?? pickedModelRef.current;
5265
5354
  return {
5355
+ // Read per send: a host that switches agents before the first message (a picker on a
5356
+ // new chat) sends the one picked now, not the one this chat mounted with.
5357
+ ...current.agent !== void 0 ? {
5358
+ agent: current.agent
5359
+ } : {},
5266
5360
  ...threadId !== void 0 ? {
5267
5361
  threadId
5268
5362
  } : {},
@@ -5284,8 +5378,8 @@ function useAgentChat(options = {}) {
5284
5378
  }, "onAttemptStart")
5285
5379
  });
5286
5380
  }, []);
5287
- const backgroundRef = (0, import_react22.useRef)(() => Promise.resolve());
5288
- const chat = (0, import_react21.useChat)({
5381
+ const backgroundRef = (0, import_react23.useRef)(() => Promise.resolve());
5382
+ const chat = (0, import_react22.useChat)({
5289
5383
  transport,
5290
5384
  id: chatId,
5291
5385
  resume: options.resumeRunId !== void 0,
@@ -5331,7 +5425,7 @@ function useAgentChat(options = {}) {
5331
5425
  }
5332
5426
  }, "onFinish")
5333
5427
  });
5334
- const chatRef = (0, import_react22.useRef)(chat);
5428
+ const chatRef = (0, import_react23.useRef)(chat);
5335
5429
  chatRef.current = chat;
5336
5430
  async function resyncFromThread() {
5337
5431
  const threadId = currentThreadId();
@@ -5343,8 +5437,8 @@ function useAgentChat(options = {}) {
5343
5437
  }
5344
5438
  }
5345
5439
  __name(resyncFromThread, "resyncFromThread");
5346
- const firstChatId = (0, import_react22.useRef)(chatId);
5347
- (0, import_react22.useEffect)(() => {
5440
+ const firstChatId = (0, import_react23.useRef)(chatId);
5441
+ (0, import_react23.useEffect)(() => {
5348
5442
  if (chatId === firstChatId.current) return;
5349
5443
  firstChatId.current = chatId;
5350
5444
  setRunId(void 0);
@@ -5357,7 +5451,7 @@ function useAgentChat(options = {}) {
5357
5451
  }, [
5358
5452
  chatId
5359
5453
  ]);
5360
- (0, import_react22.useEffect)(() => {
5454
+ (0, import_react23.useEffect)(() => {
5361
5455
  const threadId = options.threadId;
5362
5456
  if (threadId === void 0) return;
5363
5457
  if (threadId === createdThreadId.current) return;
@@ -5398,8 +5492,8 @@ function useAgentChat(options = {}) {
5398
5492
  chatId,
5399
5493
  options.threadId
5400
5494
  ]);
5401
- const turnInFlight = (0, import_react22.useRef)(false);
5402
- const isTurnInFlight = (0, import_react22.useCallback)(() => turnInFlight.current || transport.isAttemptLive, [
5495
+ const turnInFlight = (0, import_react23.useRef)(false);
5496
+ const isTurnInFlight = (0, import_react23.useCallback)(() => turnInFlight.current || transport.isAttemptLive, [
5403
5497
  transport
5404
5498
  ]);
5405
5499
  const quota = useQuota({
@@ -5407,9 +5501,9 @@ function useAgentChat(options = {}) {
5407
5501
  enabled: options.quota !== false && typeof client.getQuota === "function"
5408
5502
  });
5409
5503
  const blocked = options.blocked !== void 0 ? options.blocked : quota.blocked;
5410
- const blockedRef = (0, import_react22.useRef)(blocked);
5504
+ const blockedRef = (0, import_react23.useRef)(blocked);
5411
5505
  blockedRef.current = blocked;
5412
- const sendMessage = (0, import_react22.useCallback)(async (...args) => {
5506
+ const sendMessage = (0, import_react23.useCallback)(async (...args) => {
5413
5507
  const block = blockedRef.current;
5414
5508
  if (block != null) throw new QuotaBlockedError(block);
5415
5509
  if (isTurnInFlight()) return;
@@ -5422,13 +5516,13 @@ function useAgentChat(options = {}) {
5422
5516
  }, [
5423
5517
  isTurnInFlight
5424
5518
  ]);
5425
- const addToolResult = (0, import_react22.useCallback)(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
5519
+ const addToolResult = (0, import_react23.useCallback)(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
5426
5520
  tool,
5427
5521
  toolCallId,
5428
5522
  output
5429
5523
  }), []);
5430
- const [backgroundRuns, setBackgroundRuns] = (0, import_react22.useState)([]);
5431
- const refreshBackground = (0, import_react22.useCallback)(async () => {
5524
+ const [backgroundRuns, setBackgroundRuns] = (0, import_react23.useState)([]);
5525
+ const refreshBackground = (0, import_react23.useCallback)(async () => {
5432
5526
  const threadId = currentThreadId();
5433
5527
  if (threadId === void 0) {
5434
5528
  return;
@@ -5454,7 +5548,7 @@ function useAgentChat(options = {}) {
5454
5548
  ]);
5455
5549
  backgroundRef.current = refreshBackground;
5456
5550
  const isWorking = backgroundRuns.some((run) => run.status === "running");
5457
- (0, import_react22.useEffect)(() => {
5551
+ (0, import_react23.useEffect)(() => {
5458
5552
  if (options.background !== true || options.threadId === void 0) {
5459
5553
  return;
5460
5554
  }
@@ -5465,7 +5559,7 @@ function useAgentChat(options = {}) {
5465
5559
  chatId,
5466
5560
  refreshBackground
5467
5561
  ]);
5468
- (0, import_react22.useEffect)(() => {
5562
+ (0, import_react23.useEffect)(() => {
5469
5563
  const every = latest.current.backgroundPollMs ?? 5e3;
5470
5564
  if (latest.current.background !== true || !isWorking || every <= 0) {
5471
5565
  return;
@@ -5476,7 +5570,7 @@ function useAgentChat(options = {}) {
5476
5570
  isWorking,
5477
5571
  refreshBackground
5478
5572
  ]);
5479
- const cancel = (0, import_react22.useCallback)(async () => {
5573
+ const cancel = (0, import_react23.useCallback)(async () => {
5480
5574
  chatRef.current.stop();
5481
5575
  const active = runIdRef.current;
5482
5576
  if (active) {
@@ -5488,7 +5582,7 @@ function useAgentChat(options = {}) {
5488
5582
  }, [
5489
5583
  client
5490
5584
  ]);
5491
- const approve = (0, import_react22.useCallback)(async ({ toolCallId, remember, via }) => {
5585
+ const approve = (0, import_react23.useCallback)(async ({ toolCallId, remember, via }) => {
5492
5586
  await requireBackendMethod(client, "approveToolCall")({
5493
5587
  toolCallId,
5494
5588
  ...remember === true ? {
@@ -5501,7 +5595,7 @@ function useAgentChat(options = {}) {
5501
5595
  }, [
5502
5596
  client
5503
5597
  ]);
5504
- const reject = (0, import_react22.useCallback)(async ({ toolCallId, reason, via }) => {
5598
+ const reject = (0, import_react23.useCallback)(async ({ toolCallId, reason, via }) => {
5505
5599
  await requireBackendMethod(client, "rejectToolCall")({
5506
5600
  toolCallId,
5507
5601
  ...reason !== void 0 ? {
@@ -5514,7 +5608,7 @@ function useAgentChat(options = {}) {
5514
5608
  }, [
5515
5609
  client
5516
5610
  ]);
5517
- const answer = (0, import_react22.useCallback)(async ({ toolCallId, answers }) => {
5611
+ const answer = (0, import_react23.useCallback)(async ({ toolCallId, answers }) => {
5518
5612
  await requireBackendMethod(client, "answerToolCall")({
5519
5613
  toolCallId,
5520
5614
  ...answers !== void 0 ? {
@@ -5524,14 +5618,14 @@ function useAgentChat(options = {}) {
5524
5618
  }, [
5525
5619
  client
5526
5620
  ]);
5527
- const skip = (0, import_react22.useCallback)(async ({ toolCallId }) => {
5621
+ const skip = (0, import_react23.useCallback)(async ({ toolCallId }) => {
5528
5622
  await requireBackendMethod(client, "skipToolCall")({
5529
5623
  toolCallId
5530
5624
  });
5531
5625
  }, [
5532
5626
  client
5533
5627
  ]);
5534
- const regenerate = (0, import_react22.useCallback)((_input) => {
5628
+ const regenerate = (0, import_react23.useCallback)((_input) => {
5535
5629
  const block = blockedRef.current;
5536
5630
  if (block != null) throw new QuotaBlockedError(block);
5537
5631
  if (isTurnInFlight()) return;
@@ -5543,7 +5637,7 @@ function useAgentChat(options = {}) {
5543
5637
  }, [
5544
5638
  isTurnInFlight
5545
5639
  ]);
5546
- const storedIdOf = (0, import_react22.useCallback)(async (messageId, threadId) => {
5640
+ const storedIdOf = (0, import_react23.useCallback)(async (messageId, threadId) => {
5547
5641
  const message = chatRef.current.messages.find((candidate) => candidate.id === messageId);
5548
5642
  const runOf = message?.metadata?.runId;
5549
5643
  if (runOf === void 0) return messageId;
@@ -5555,7 +5649,7 @@ function useAgentChat(options = {}) {
5555
5649
  }, [
5556
5650
  client
5557
5651
  ]);
5558
- const fork = (0, import_react22.useCallback)(async ({ messageId, threadId }) => {
5652
+ const fork = (0, import_react23.useCallback)(async ({ messageId, threadId }) => {
5559
5653
  const source = threadId ?? currentThreadId();
5560
5654
  if (source === void 0) throw new Error("fork: this chat has no thread yet");
5561
5655
  const stored = await storedIdOf(messageId, source);
@@ -5570,7 +5664,7 @@ function useAgentChat(options = {}) {
5570
5664
  currentThreadId,
5571
5665
  storedIdOf
5572
5666
  ]);
5573
- const truncateFrom = (0, import_react22.useCallback)(async ({ messageId, threadId }) => {
5667
+ const truncateFrom = (0, import_react23.useCallback)(async ({ messageId, threadId }) => {
5574
5668
  const target = threadId ?? currentThreadId();
5575
5669
  if (target === void 0) throw new Error("truncateFrom: this chat has no thread yet");
5576
5670
  const stored = await storedIdOf(messageId, target);
@@ -5580,7 +5674,7 @@ function useAgentChat(options = {}) {
5580
5674
  currentThreadId,
5581
5675
  storedIdOf
5582
5676
  ]);
5583
- const promote = (0, import_react22.useCallback)(async ({ threadId } = {}) => {
5677
+ const promote = (0, import_react23.useCallback)(async ({ threadId } = {}) => {
5584
5678
  const target = threadId ?? currentThreadId();
5585
5679
  if (target === void 0) throw new Error("promote: this chat has no thread yet");
5586
5680
  await requireBackendMethod(client, "promoteThread")(target);
@@ -5591,8 +5685,8 @@ function useAgentChat(options = {}) {
5591
5685
  client,
5592
5686
  currentThreadId
5593
5687
  ]);
5594
- const [modelsWanted, setModelsWanted] = (0, import_react22.useState)(false);
5595
- const modelsWantedRef = (0, import_react22.useRef)(modelsWanted);
5688
+ const [modelsWanted, setModelsWanted] = (0, import_react23.useState)(false);
5689
+ const modelsWantedRef = (0, import_react23.useRef)(modelsWanted);
5596
5690
  modelsWantedRef.current = modelsWanted;
5597
5691
  const catalog = useModels({
5598
5692
  backend: client,
@@ -5601,13 +5695,13 @@ function useAgentChat(options = {}) {
5601
5695
  } : {},
5602
5696
  enabled: modelsWanted && typeof client.listModels === "function"
5603
5697
  });
5604
- const wantModels = (0, import_react22.useCallback)(() => {
5698
+ const wantModels = (0, import_react23.useCallback)(() => {
5605
5699
  if (modelsWantedRef.current) return;
5606
5700
  modelsWantedRef.current = true;
5607
5701
  queueMicrotask(() => setModelsWanted(true));
5608
5702
  }, []);
5609
- const selectModel = (0, import_react22.useCallback)((id) => setPickedModel(id), []);
5610
- const pinToThread = (0, import_react22.useCallback)(async (model) => {
5703
+ const selectModel = (0, import_react23.useCallback)((id) => setPickedModel(id), []);
5704
+ const pinToThread = (0, import_react23.useCallback)(async (model) => {
5611
5705
  const threadId = currentThreadId();
5612
5706
  setThreadModel(model);
5613
5707
  if (threadId === void 0) {
@@ -5636,6 +5730,10 @@ function useAgentChat(options = {}) {
5636
5730
  return catalog.providers;
5637
5731
  },
5638
5732
  selected: options.model ?? pickedModel ?? threadModel ?? catalog.defaultModel ?? null,
5733
+ get defaultModel() {
5734
+ wantModels();
5735
+ return catalog.defaultModel;
5736
+ },
5639
5737
  select: selectModel,
5640
5738
  pinToThread,
5641
5739
  isLoading: modelsWanted && catalog.isLoading,
@@ -5647,9 +5745,9 @@ function useAgentChat(options = {}) {
5647
5745
  ...options.composer,
5648
5746
  backend: client
5649
5747
  });
5650
- const [text, setText] = (0, import_react22.useState)("");
5651
- const blockedBy = blocked != null ? "quota" : files.isUploading ? "uploading" : isBusy ? "busy" : text.trim().length === 0 && files.attachments.length === 0 ? "empty" : null;
5652
- const composerRef = (0, import_react22.useRef)({
5748
+ const [text, setText] = (0, import_react23.useState)("");
5749
+ const blockedBy = blocked != null ? "quota" : files.isUploading ? "uploading" : isBusy ? "busy" : text.trim().length === 0 && files.refs.length === 0 ? "empty" : null;
5750
+ const composerRef = (0, import_react23.useRef)({
5653
5751
  text,
5654
5752
  files,
5655
5753
  blockedBy
@@ -5659,14 +5757,30 @@ function useAgentChat(options = {}) {
5659
5757
  files,
5660
5758
  blockedBy
5661
5759
  };
5662
- const submit = (0, import_react22.useCallback)(async () => {
5760
+ const submit = (0, import_react23.useCallback)(async () => {
5663
5761
  const current = composerRef.current;
5664
5762
  if (current.blockedBy !== null) return;
5665
5763
  const refs = current.files.refs;
5764
+ const files2 = current.files.items.flatMap((item) => item.status === "ready" && item.attachment !== void 0 ? [
5765
+ {
5766
+ type: "file",
5767
+ mediaType: item.attachment.contentType,
5768
+ filename: item.attachment.name,
5769
+ url: item.attachment.url,
5770
+ providerMetadata: {
5771
+ agent: {
5772
+ mediaId: item.attachment.mediaId
5773
+ }
5774
+ }
5775
+ }
5776
+ ] : []);
5666
5777
  const draft = current.text.trim();
5667
5778
  setText("");
5668
5779
  current.files.clear();
5669
- await sendMessage({
5780
+ await sendMessage(files2.length > 0 ? {
5781
+ text: draft,
5782
+ files: files2
5783
+ } : {
5670
5784
  text: draft
5671
5785
  }, refs.length > 0 ? {
5672
5786
  body: {
@@ -5825,6 +5939,7 @@ var QuotaBlockedError = class extends Error {
5825
5939
  toolCatalogFrom,
5826
5940
  useAgentBackend,
5827
5941
  useAgentChat,
5942
+ useAgentConfig,
5828
5943
  useAgents,
5829
5944
  useAmbientRenderUi,
5830
5945
  useApprovalCountdown,