@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.js CHANGED
@@ -203,6 +203,10 @@ var AgentClient = class {
203
203
  listAgents() {
204
204
  return this.request("GET", "/agents");
205
205
  }
206
+ /** `GET <path>/config` — attachment limits and upload mode, and which features are on. */
207
+ getConfig() {
208
+ return this.request("GET", "/config");
209
+ }
206
210
  /** `GET <path>/quota` — the caller's budget windows and the one blocking sends, if any. */
207
211
  getQuota() {
208
212
  return this.request("GET", "/quota");
@@ -860,6 +864,13 @@ var AgentChatTransport = class {
860
864
  }
861
865
  });
862
866
  break;
867
+ case "message-metadata":
868
+ ensureStarted();
869
+ controller.enqueue({
870
+ type: "message-metadata",
871
+ messageMetadata: event.metadata
872
+ });
873
+ break;
863
874
  case "title":
864
875
  case "cancelled":
865
876
  forwardAsData(event, true);
@@ -1113,7 +1124,7 @@ function dragHasFiles(data) {
1113
1124
  __name(dragHasFiles, "dragHasFiles");
1114
1125
 
1115
1126
  // src/attachments/use-attachments.ts
1116
- import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo4, useRef as useRef3, useState as useState3 } from "react";
1127
+ import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo4, useRef as useRef3, useState as useState4 } from "react";
1117
1128
 
1118
1129
  // src/backend.ts
1119
1130
  var AgentBackendUnsupportedError = class extends Error {
@@ -1135,6 +1146,9 @@ function requireBackendMethod(backend, name) {
1135
1146
  }
1136
1147
  __name(requireBackendMethod, "requireBackendMethod");
1137
1148
 
1149
+ // src/config/use-agent-config.ts
1150
+ import { useEffect as useEffect3, useState as useState3 } from "react";
1151
+
1138
1152
  // src/provider.tsx
1139
1153
  import { useContext as useContext3, useMemo as useMemo3, useRef as useRef2 } from "react";
1140
1154
 
@@ -1699,6 +1713,59 @@ function useAgentBackend(own) {
1699
1713
  }
1700
1714
  __name(useAgentBackend, "useAgentBackend");
1701
1715
 
1716
+ // src/config/use-agent-config.ts
1717
+ var shared = /* @__PURE__ */ new WeakMap();
1718
+ function load(backend) {
1719
+ const getConfig = backend.getConfig;
1720
+ if (typeof getConfig !== "function") return void 0;
1721
+ let pending = shared.get(backend);
1722
+ if (pending === void 0) {
1723
+ pending = getConfig.call(backend).catch((error) => {
1724
+ shared.delete(backend);
1725
+ throw error;
1726
+ });
1727
+ shared.set(backend, pending);
1728
+ }
1729
+ return pending;
1730
+ }
1731
+ __name(load, "load");
1732
+ function useAgentConfig(options = {}) {
1733
+ const backend = useAgentBackend(options.backend);
1734
+ const enabled = options.enabled !== false;
1735
+ const [config, setConfig] = useState3(void 0);
1736
+ const [isLoading, setLoading] = useState3(false);
1737
+ const [error, setError] = useState3(null);
1738
+ useEffect3(() => {
1739
+ if (!enabled) return;
1740
+ const pending = load(backend);
1741
+ if (pending === void 0) return;
1742
+ let cancelled = false;
1743
+ setLoading(true);
1744
+ pending.then((loaded) => {
1745
+ if (cancelled) return;
1746
+ setConfig(loaded !== null && typeof loaded === "object" ? loaded : void 0);
1747
+ setError(null);
1748
+ setLoading(false);
1749
+ }, (failure) => {
1750
+ if (cancelled) return;
1751
+ setError(failure instanceof Error ? failure : new Error(String(failure)));
1752
+ setLoading(false);
1753
+ });
1754
+ return () => {
1755
+ cancelled = true;
1756
+ };
1757
+ }, [
1758
+ backend,
1759
+ enabled
1760
+ ]);
1761
+ return {
1762
+ config,
1763
+ isLoading,
1764
+ error
1765
+ };
1766
+ }
1767
+ __name(useAgentConfig, "useAgentConfig");
1768
+
1702
1769
  // src/attachments/use-attachments.ts
1703
1770
  var DEFAULT_REJECTION = {
1704
1771
  type: /* @__PURE__ */ __name((file) => `${file.name} is not a supported file type`, "type"),
@@ -1708,19 +1775,33 @@ var DEFAULT_REJECTION = {
1708
1775
  var sequence = 0;
1709
1776
  function useAttachments(options = {}) {
1710
1777
  const backend = useAgentBackend(options.backend);
1711
- const latest = useRef3({
1712
- ...options,
1778
+ const { config } = useAgentConfig({
1713
1779
  backend
1714
1780
  });
1715
- latest.current = {
1781
+ const limits = config?.attachments;
1782
+ const accept = options.accept ?? limits?.allowedContentTypes;
1783
+ const maxBytes = options.maxBytes ?? limits?.maxBytes;
1784
+ const maxFiles = options.maxFiles ?? limits?.maxPerMessage;
1785
+ const effective = {
1716
1786
  ...options,
1717
- backend
1787
+ backend,
1788
+ ...accept !== void 0 ? {
1789
+ accept
1790
+ } : {},
1791
+ ...maxBytes !== void 0 ? {
1792
+ maxBytes
1793
+ } : {},
1794
+ ...maxFiles !== void 0 ? {
1795
+ maxFiles
1796
+ } : {}
1718
1797
  };
1719
- const [items, setItems] = useState3([]);
1798
+ const latest = useRef3(effective);
1799
+ latest.current = effective;
1800
+ const [items, setItems] = useState4([]);
1720
1801
  const itemsRef = useRef3(items);
1721
1802
  itemsRef.current = items;
1722
1803
  const controllers = useRef3(/* @__PURE__ */ new Map());
1723
- const [dragDepth, setDragDepth] = useState3(0);
1804
+ const [dragDepth, setDragDepth] = useState4(0);
1724
1805
  const patch = useCallback2((id, change) => {
1725
1806
  setItems((current) => current.map((item) => item.id === id ? {
1726
1807
  ...item,
@@ -1765,9 +1846,9 @@ function useAttachments(options = {}) {
1765
1846
  ]);
1766
1847
  const add = useCallback2((files) => {
1767
1848
  if (files == null) return;
1768
- const { accept: accept2, maxBytes, maxFiles, describeRejection } = latest.current;
1849
+ const { accept: accept2, maxBytes: maxBytes2, maxFiles: maxFiles2, describeRejection } = latest.current;
1769
1850
  const describe = /* @__PURE__ */ __name((reason, file) => describeRejection?.(reason, file) ?? DEFAULT_REJECTION[reason](file), "describe");
1770
- let room = maxFiles === void 0 ? Number.POSITIVE_INFINITY : maxFiles - itemsRef.current.filter((item) => item.status !== "rejected").length;
1851
+ let room = maxFiles2 === void 0 ? Number.POSITIVE_INFINITY : maxFiles2 - itemsRef.current.filter((item) => item.status !== "rejected").length;
1771
1852
  const staged = [];
1772
1853
  for (const file of Array.from(files)) {
1773
1854
  sequence += 1;
@@ -1779,7 +1860,7 @@ function useAttachments(options = {}) {
1779
1860
  type: file.type,
1780
1861
  progress: 0
1781
1862
  };
1782
- const reason = !acceptsFile(accept2, file) ? "type" : maxBytes !== void 0 && file.size > maxBytes ? "size" : room <= 0 ? "count" : void 0;
1863
+ const reason = !acceptsFile(accept2, file) ? "type" : maxBytes2 !== void 0 && file.size > maxBytes2 ? "size" : room <= 0 ? "count" : void 0;
1783
1864
  if (reason !== void 0) {
1784
1865
  staged.push({
1785
1866
  ...base,
@@ -1843,7 +1924,7 @@ function useAttachments(options = {}) {
1843
1924
  }, [
1844
1925
  start
1845
1926
  ]);
1846
- useEffect3(() => () => {
1927
+ useEffect4(() => () => {
1847
1928
  for (const item of itemsRef.current) release(item);
1848
1929
  }, [
1849
1930
  release
@@ -1878,11 +1959,10 @@ function useAttachments(options = {}) {
1878
1959
  }), [
1879
1960
  add
1880
1961
  ]);
1881
- const accept = options.accept;
1882
1962
  const inputProps = useMemo4(() => ({
1883
1963
  type: "file",
1884
1964
  accept: typeof accept === "string" ? accept : accept?.join(","),
1885
- multiple: options.maxFiles === void 0 || options.maxFiles > 1,
1965
+ multiple: maxFiles === void 0 || maxFiles > 1,
1886
1966
  onChange: /* @__PURE__ */ __name((event) => {
1887
1967
  const input = event.currentTarget;
1888
1968
  add(input.files);
@@ -1890,12 +1970,11 @@ function useAttachments(options = {}) {
1890
1970
  }, "onChange")
1891
1971
  }), [
1892
1972
  accept,
1893
- options.maxFiles,
1973
+ maxFiles,
1894
1974
  add
1895
1975
  ]);
1896
1976
  return useMemo4(() => {
1897
1977
  const ready = items.filter((item) => item.status === "ready" && item.attachment !== void 0);
1898
- const attachments = ready.map((item) => item.attachment);
1899
1978
  return {
1900
1979
  items,
1901
1980
  add,
@@ -1903,9 +1982,8 @@ function useAttachments(options = {}) {
1903
1982
  retry,
1904
1983
  clear,
1905
1984
  isUploading: items.some((item) => item.status === "uploading"),
1906
- attachments,
1907
- refs: attachments.map((attachment) => ({
1908
- mediaId: attachment.mediaId
1985
+ refs: ready.map((item) => ({
1986
+ mediaId: item.attachment.mediaId
1909
1987
  })),
1910
1988
  inputProps,
1911
1989
  dropZoneProps,
@@ -1930,13 +2008,13 @@ __name(useAttachments, "useAttachments");
1930
2008
  import { useMemo as useMemo5 } from "react";
1931
2009
 
1932
2010
  // src/catalog/use-resource.ts
1933
- import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef4, useState as useState4 } from "react";
1934
- function useResource(load2, key, enabled) {
1935
- const [data, setData] = useState4(void 0);
1936
- const [isLoading, setIsLoading] = useState4(enabled);
1937
- const [error, setError] = useState4(null);
1938
- const loadRef = useRef4(load2);
1939
- loadRef.current = load2;
2011
+ import { useCallback as useCallback3, useEffect as useEffect5, useRef as useRef4, useState as useState5 } from "react";
2012
+ function useResource(load3, key, enabled) {
2013
+ const [data, setData] = useState5(void 0);
2014
+ const [isLoading, setIsLoading] = useState5(enabled);
2015
+ const [error, setError] = useState5(null);
2016
+ const loadRef = useRef4(load3);
2017
+ loadRef.current = load3;
1940
2018
  const generation = useRef4(0);
1941
2019
  const refresh = useCallback3(async () => {
1942
2020
  const mine = ++generation.current;
@@ -1953,7 +2031,7 @@ function useResource(load2, key, enabled) {
1953
2031
  if (mine === generation.current) setIsLoading(false);
1954
2032
  }
1955
2033
  }, []);
1956
- useEffect4(() => {
2034
+ useEffect5(() => {
1957
2035
  if (!enabled) return;
1958
2036
  void refresh();
1959
2037
  }, [
@@ -2029,7 +2107,7 @@ function useModels(options = {}) {
2029
2107
  __name(useModels, "useModels");
2030
2108
 
2031
2109
  // src/quota/use-quota.ts
2032
- import { useEffect as useEffect5, useMemo as useMemo7 } from "react";
2110
+ import { useEffect as useEffect6, useMemo as useMemo7 } from "react";
2033
2111
 
2034
2112
  // src/threads/threads-events.ts
2035
2113
  var listeners = /* @__PURE__ */ new WeakMap();
@@ -2057,7 +2135,7 @@ function useQuota(options = {}) {
2057
2135
  const { enabled = true, pollMs } = options;
2058
2136
  const backend = useAgentBackend(options.backend);
2059
2137
  const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "getQuota")(), "", enabled);
2060
- useEffect5(() => {
2138
+ useEffect6(() => {
2061
2139
  if (!enabled) return;
2062
2140
  return onThreadsEvent(backend, (event) => {
2063
2141
  if (event.type === "changed") void refresh();
@@ -2067,7 +2145,7 @@ function useQuota(options = {}) {
2067
2145
  enabled,
2068
2146
  refresh
2069
2147
  ]);
2070
- useEffect5(() => {
2148
+ useEffect6(() => {
2071
2149
  if (!enabled || pollMs === void 0 || pollMs <= 0) return;
2072
2150
  const timer = setInterval(() => void refresh(), pollMs);
2073
2151
  return () => clearInterval(timer);
@@ -2098,7 +2176,7 @@ function useQuota(options = {}) {
2098
2176
  __name(useQuota, "useQuota");
2099
2177
 
2100
2178
  // src/feedback/use-message-feedback.ts
2101
- import { useCallback as useCallback4, useRef as useRef5, useState as useState5 } from "react";
2179
+ import { useCallback as useCallback4, useRef as useRef5, useState as useState6 } from "react";
2102
2180
  function useMessageFeedback(options = {}) {
2103
2181
  const backend = useAgentBackend(options.backend);
2104
2182
  const latest = useRef5({
@@ -2109,9 +2187,9 @@ function useMessageFeedback(options = {}) {
2109
2187
  ...options,
2110
2188
  backend
2111
2189
  };
2112
- const [local, setLocal] = useState5(/* @__PURE__ */ new Map());
2113
- const [pending, setPending] = useState5(/* @__PURE__ */ new Set());
2114
- const [error, setError] = useState5(null);
2190
+ const [local, setLocal] = useState6(/* @__PURE__ */ new Map());
2191
+ const [pending, setPending] = useState6(/* @__PURE__ */ new Set());
2192
+ const [error, setError] = useState6(null);
2115
2193
  const localRef = useRef5(local);
2116
2194
  localRef.current = local;
2117
2195
  const resolved = useRef5(/* @__PURE__ */ new Map());
@@ -2214,13 +2292,13 @@ function metadataOf(message) {
2214
2292
  __name(metadataOf, "metadataOf");
2215
2293
 
2216
2294
  // src/threads/use-threads.ts
2217
- import { useCallback as useCallback5, useEffect as useEffect6, useRef as useRef6, useState as useState6 } from "react";
2295
+ import { useCallback as useCallback5, useEffect as useEffect7, useRef as useRef6, useState as useState7 } from "react";
2218
2296
  function useThreads(options = {}) {
2219
2297
  const { enabled = true } = options;
2220
2298
  const backend = useAgentBackend(options.backend);
2221
- const [threads, setThreads] = useState6([]);
2222
- const [isLoading, setIsLoading] = useState6(enabled);
2223
- const [error, setError] = useState6(null);
2299
+ const [threads, setThreads] = useState7([]);
2300
+ const [isLoading, setIsLoading] = useState7(enabled);
2301
+ const [error, setError] = useState7(null);
2224
2302
  const threadsRef = useRef6(threads);
2225
2303
  threadsRef.current = threads;
2226
2304
  const generation = useRef6(0);
@@ -2241,7 +2319,7 @@ function useThreads(options = {}) {
2241
2319
  }, [
2242
2320
  backend
2243
2321
  ]);
2244
- useEffect6(() => {
2322
+ useEffect7(() => {
2245
2323
  if (!enabled) return;
2246
2324
  void refresh();
2247
2325
  return onThreadsEvent(backend, (event) => {
@@ -2358,10 +2436,10 @@ function backgroundRunsFromThread(messages) {
2358
2436
  __name(backgroundRunsFromThread, "backgroundRunsFromThread");
2359
2437
 
2360
2438
  // src/components/chat-input.tsx
2361
- import React2, { useEffect as useEffect8, useState as useState8 } from "react";
2439
+ import React2, { useEffect as useEffect9, useState as useState9 } from "react";
2362
2440
 
2363
2441
  // src/components/use-speech-recognition.ts
2364
- import { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo8, useRef as useRef7, useState as useState7 } from "react";
2442
+ import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo8, useRef as useRef7, useState as useState8 } from "react";
2365
2443
  function getRecognitionCtor() {
2366
2444
  if (typeof window === "undefined") return null;
2367
2445
  const scope = window;
@@ -2370,14 +2448,14 @@ function getRecognitionCtor() {
2370
2448
  __name(getRecognitionCtor, "getRecognitionCtor");
2371
2449
  function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTranscript }) {
2372
2450
  const recognitionRef = useRef7(null);
2373
- const [isListening, setIsListening] = useState7(false);
2451
+ const [isListening, setIsListening] = useState8(false);
2374
2452
  const ctor = useMemo8(() => getRecognitionCtor(), []);
2375
2453
  const isSupported = ctor !== null;
2376
2454
  const finalRef = useRef7(onFinalTranscript);
2377
2455
  const interimRef = useRef7(onInterimTranscript);
2378
2456
  finalRef.current = onFinalTranscript;
2379
2457
  interimRef.current = onInterimTranscript;
2380
- useEffect7(() => {
2458
+ useEffect8(() => {
2381
2459
  if (!ctor) return;
2382
2460
  const recognition = new ctor();
2383
2461
  recognition.lang = lang;
@@ -2445,8 +2523,8 @@ __name(useSpeechRecognition, "useSpeechRecognition");
2445
2523
 
2446
2524
  // src/components/chat-input.tsx
2447
2525
  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 }) {
2448
- const [value, setValue] = useState8("");
2449
- const [interim, setInterim] = useState8("");
2526
+ const [value, setValue] = useState9("");
2527
+ const [interim, setInterim] = useState9("");
2450
2528
  const speech = useSpeechRecognition({
2451
2529
  lang: speechLang,
2452
2530
  onFinalTranscript: /* @__PURE__ */ __name((text) => {
@@ -2457,7 +2535,7 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
2457
2535
  }, "onFinalTranscript"),
2458
2536
  onInterimTranscript: /* @__PURE__ */ __name((text) => setInterim(text), "onInterimTranscript")
2459
2537
  });
2460
- useEffect8(() => {
2538
+ useEffect9(() => {
2461
2539
  if (!speech.isListening) setInterim("");
2462
2540
  }, [
2463
2541
  speech.isListening
@@ -2524,7 +2602,7 @@ __name(ChatInput, "ChatInput");
2524
2602
  import React3 from "react";
2525
2603
 
2526
2604
  // src/transcript/use-chat-transcript.ts
2527
- import { useCallback as useCallback8, useEffect as useEffect10, useRef as useRef9, useState as useState10 } from "react";
2605
+ import { useCallback as useCallback8, useEffect as useEffect11, useRef as useRef9, useState as useState11 } from "react";
2528
2606
 
2529
2607
  // src/transcript/model.ts
2530
2608
  import { readElicitationInput, validateElicitationAnswer as validateElicitationAnswer2 } from "@dudousxd/nestjs-agent-core";
@@ -3501,10 +3579,10 @@ function formatCostUsd(cost) {
3501
3579
  __name(formatCostUsd, "formatCostUsd");
3502
3580
 
3503
3581
  // src/transcript/use-stick-to-bottom.ts
3504
- import { useCallback as useCallback7, useEffect as useEffect9, useRef as useRef8, useState as useState9 } from "react";
3582
+ import { useCallback as useCallback7, useEffect as useEffect10, useRef as useRef8, useState as useState10 } from "react";
3505
3583
  function useStickToBottom({ contentKey, threshold = 32 }) {
3506
3584
  const containerRef = useRef8(null);
3507
- const [isAtBottom, setIsAtBottom] = useState9(true);
3585
+ const [isAtBottom, setIsAtBottom] = useState10(true);
3508
3586
  const measure = useCallback7(() => {
3509
3587
  const element = containerRef.current;
3510
3588
  if (!element) {
@@ -3531,7 +3609,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
3531
3609
  }, [
3532
3610
  measure
3533
3611
  ]);
3534
- useEffect9(() => {
3612
+ useEffect10(() => {
3535
3613
  if (isAtBottom) {
3536
3614
  scrollToBottom();
3537
3615
  }
@@ -3564,12 +3642,12 @@ function useChatTranscript(options) {
3564
3642
  const { messages, status, initialVisibleCount = DEFAULT_VISIBLE_COUNT, loadEarlierStep = DEFAULT_LOAD_EARLIER_STEP, followUps, stickToBottomThreshold } = options;
3565
3643
  const latest = useRef9(options);
3566
3644
  latest.current = options;
3567
- const [visibleCount, setVisibleCount] = useState10(initialVisibleCount);
3568
- const [stopRequested, setStopRequested] = useState10(false);
3645
+ const [visibleCount, setVisibleCount] = useState11(initialVisibleCount);
3646
+ const [stopRequested, setStopRequested] = useState11(false);
3569
3647
  const isStreaming = status === "streaming" || status === "reconnecting";
3570
3648
  const isBusy = status === "submitted" || isStreaming;
3571
3649
  const isEmpty = messages.length === 0;
3572
- useEffect10(() => {
3650
+ useEffect11(() => {
3573
3651
  if (!isBusy) {
3574
3652
  setStopRequested(false);
3575
3653
  }
@@ -3649,12 +3727,12 @@ function useTranscriptItem(options) {
3649
3727
  }
3650
3728
  __name(useTranscriptItem, "useTranscriptItem");
3651
3729
  function useTranscriptItems({ messages, visibleStart, streamingMessageId, options }) {
3652
- const [drafts, setDrafts] = useState10(() => /* @__PURE__ */ new Map());
3653
- const [copied, setCopied] = useState10(() => /* @__PURE__ */ new Set());
3654
- const [openReasoning, setOpenReasoning] = useState10(() => /* @__PURE__ */ new Map());
3655
- const [picks, setPicks] = useState10(() => /* @__PURE__ */ new Map());
3656
- const [settling, setSettling] = useState10(() => /* @__PURE__ */ new Map());
3657
- const [settleErrors, setSettleErrors] = useState10(() => /* @__PURE__ */ new Map());
3730
+ const [drafts, setDrafts] = useState11(() => /* @__PURE__ */ new Map());
3731
+ const [copied, setCopied] = useState11(() => /* @__PURE__ */ new Set());
3732
+ const [openReasoning, setOpenReasoning] = useState11(() => /* @__PURE__ */ new Map());
3733
+ const [picks, setPicks] = useState11(() => /* @__PURE__ */ new Map());
3734
+ const [settling, setSettling] = useState11(() => /* @__PURE__ */ new Map());
3735
+ const [settleErrors, setSettleErrors] = useState11(() => /* @__PURE__ */ new Map());
3658
3736
  const backend = useAgentBackend();
3659
3737
  const handlers = settleHandlers(options, backend);
3660
3738
  const latest = useRef9({
@@ -3672,7 +3750,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
3672
3750
  messages
3673
3751
  };
3674
3752
  const copyTimers = useRef9(/* @__PURE__ */ new Map());
3675
- useEffect10(() => () => {
3753
+ useEffect11(() => () => {
3676
3754
  for (const timer of copyTimers.current.values()) {
3677
3755
  clearTimeout(timer);
3678
3756
  }
@@ -4476,18 +4554,18 @@ function toItem(entry) {
4476
4554
  __name(toItem, "toItem");
4477
4555
 
4478
4556
  // src/composer/use-composer-autocomplete.ts
4479
- import { useCallback as useCallback9, useEffect as useEffect11, useId, useLayoutEffect, useMemo as useMemo9, useRef as useRef10, useState as useState11 } from "react";
4557
+ import { useCallback as useCallback9, useEffect as useEffect12, useId, useLayoutEffect, useMemo as useMemo9, useRef as useRef10, useState as useState12 } from "react";
4480
4558
  function useComposerAutocomplete(options) {
4481
4559
  const { value, sources, acceptOnTab = true } = options;
4482
4560
  const latest = useRef10(options);
4483
4561
  latest.current = options;
4484
4562
  const inputRef = useRef10(null);
4485
- const [caret, setCaret] = useState11(value.length);
4486
- const [items, setItems] = useState11([]);
4487
- const [isLoading, setLoading] = useState11(false);
4488
- const [error, setError] = useState11(null);
4489
- const [activeIndex, setActiveIndex] = useState11(0);
4490
- const [dismissedIndex, setDismissedIndex] = useState11(null);
4563
+ const [caret, setCaret] = useState12(value.length);
4564
+ const [items, setItems] = useState12([]);
4565
+ const [isLoading, setLoading] = useState12(false);
4566
+ const [error, setError] = useState12(null);
4567
+ const [activeIndex, setActiveIndex] = useState12(0);
4568
+ const [dismissedIndex, setDismissedIndex] = useState12(null);
4491
4569
  const safeCaret = Math.min(caret, value.length);
4492
4570
  const match = useMemo9(() => findActiveTrigger(value, safeCaret, sources), [
4493
4571
  value,
@@ -4504,7 +4582,7 @@ function useComposerAutocomplete(options) {
4504
4582
  const activeIndexRef = useRef10(activeIndex);
4505
4583
  activeIndexRef.current = activeIndex;
4506
4584
  const requestKey = isActive && match ? `${match.source.id}\0${match.query}` : null;
4507
- useEffect11(() => {
4585
+ useEffect12(() => {
4508
4586
  const current = matchRef.current;
4509
4587
  if (requestKey === null || current === null) {
4510
4588
  setItems([]);
@@ -4714,13 +4792,13 @@ function isPromise(value) {
4714
4792
  __name(isPromise, "isPromise");
4715
4793
 
4716
4794
  // src/presentation/use-tool-catalog.ts
4717
- import { useCallback as useCallback10, useEffect as useEffect12, useMemo as useMemo10, useState as useState12 } from "react";
4718
- var shared = /* @__PURE__ */ new WeakMap();
4719
- function load(client, agent) {
4720
- let byAgent = shared.get(client);
4795
+ import { useCallback as useCallback10, useEffect as useEffect13, useMemo as useMemo10, useState as useState13 } from "react";
4796
+ var shared2 = /* @__PURE__ */ new WeakMap();
4797
+ function load2(client, agent) {
4798
+ let byAgent = shared2.get(client);
4721
4799
  if (byAgent === void 0) {
4722
4800
  byAgent = /* @__PURE__ */ new Map();
4723
- shared.set(client, byAgent);
4801
+ shared2.set(client, byAgent);
4724
4802
  }
4725
4803
  const key = agent ?? "";
4726
4804
  const cached = byAgent.get(key);
@@ -4735,22 +4813,22 @@ function load(client, agent) {
4735
4813
  byAgent.set(key, request);
4736
4814
  return request;
4737
4815
  }
4738
- __name(load, "load");
4816
+ __name(load2, "load");
4739
4817
  function useToolCatalog(options = {}) {
4740
4818
  const { agent, enabled = true } = options;
4741
4819
  const client = useAgentBackend(options.backend);
4742
- const [entries, setEntries] = useState12([]);
4743
- const [isLoading, setLoading] = useState12(enabled);
4744
- const [error, setError] = useState12(null);
4745
- const [generation, setGeneration] = useState12(0);
4746
- useEffect12(() => {
4820
+ const [entries, setEntries] = useState13([]);
4821
+ const [isLoading, setLoading] = useState13(enabled);
4822
+ const [error, setError] = useState13(null);
4823
+ const [generation, setGeneration] = useState13(0);
4824
+ useEffect13(() => {
4747
4825
  if (!enabled) {
4748
4826
  setLoading(false);
4749
4827
  return;
4750
4828
  }
4751
4829
  let cancelled = false;
4752
4830
  setLoading(true);
4753
- load(client, agent).then((loaded) => {
4831
+ load2(client, agent).then((loaded) => {
4754
4832
  if (cancelled) return;
4755
4833
  setEntries(Array.isArray(loaded) ? loaded : []);
4756
4834
  setError(null);
@@ -4770,7 +4848,7 @@ function useToolCatalog(options = {}) {
4770
4848
  generation
4771
4849
  ]);
4772
4850
  const refresh = useCallback10(() => {
4773
- shared.get(client)?.delete(agent ?? "");
4851
+ shared2.get(client)?.delete(agent ?? "");
4774
4852
  setGeneration((current) => current + 1);
4775
4853
  }, [
4776
4854
  client,
@@ -4790,7 +4868,7 @@ function useToolCatalog(options = {}) {
4790
4868
  __name(useToolCatalog, "useToolCatalog");
4791
4869
 
4792
4870
  // src/approvals/countdown.ts
4793
- import { useEffect as useEffect13, useRef as useRef11, useState as useState13 } from "react";
4871
+ import { useEffect as useEffect14, useRef as useRef11, useState as useState14 } from "react";
4794
4872
  function approvalCountdown(expiresAt, now = Date.now()) {
4795
4873
  const deadline = expiresAt == null ? Number.NaN : Date.parse(expiresAt);
4796
4874
  if (!Number.isFinite(deadline)) {
@@ -4810,8 +4888,8 @@ function useApprovalCountdown(expiresAt, options = {}) {
4810
4888
  const { intervalMs = 1e3 } = options;
4811
4889
  const nowRef = useRef11(options.now ?? Date.now);
4812
4890
  nowRef.current = options.now ?? Date.now;
4813
- const [state, setState] = useState13(() => approvalCountdown(expiresAt, nowRef.current()));
4814
- useEffect13(() => {
4891
+ const [state, setState] = useState14(() => approvalCountdown(expiresAt, nowRef.current()));
4892
+ useEffect14(() => {
4815
4893
  const read = /* @__PURE__ */ __name(() => approvalCountdown(expiresAt, nowRef.current()), "read");
4816
4894
  const first = read();
4817
4895
  setState(first);
@@ -4947,13 +5025,19 @@ function storedMessageToUiMessage(message) {
4947
5025
  for (const call of message.toolCalls ?? []) {
4948
5026
  const result = message.toolResults?.find((candidate) => candidate.id === call.id);
4949
5027
  const toolKind2 = call.kind;
5028
+ const toolMetadata = {
5029
+ ...toolKind2 !== void 0 ? {
5030
+ toolKind: toolKind2
5031
+ } : {},
5032
+ ...call.parentId !== void 0 ? {
5033
+ parentId: call.parentId
5034
+ } : {}
5035
+ };
4950
5036
  parts.push({
4951
5037
  type: `tool-${call.name}`,
4952
5038
  toolCallId: call.id,
4953
- ...toolKind2 !== void 0 ? {
4954
- toolMetadata: {
4955
- toolKind: toolKind2
4956
- }
5039
+ ...Object.keys(toolMetadata).length > 0 ? {
5040
+ toolMetadata
4957
5041
  } : {},
4958
5042
  ...result !== void 0 ? isRefusal(result) ? {
4959
5043
  // A declined action is NOT an available output. Reloading a thread used to bring one
@@ -4981,6 +5065,8 @@ function storedMessageToUiMessage(message) {
4981
5065
  parts.push(...pushedByCall.get(call.id) ?? []);
4982
5066
  }
4983
5067
  const metadata = {
5068
+ // The host's own facts first: the library's keys win on a clash.
5069
+ ...message.metadata,
4984
5070
  ...message.feedback !== void 0 ? {
4985
5071
  feedback: message.feedback
4986
5072
  } : {},
@@ -5040,6 +5126,8 @@ function mergeTurn(rows) {
5040
5126
  const feedback = lastRow.feedback;
5041
5127
  const createdAt = rows[0]?.createdAt;
5042
5128
  const metadata = {
5129
+ // Host facts of every row, a later row's winning (the turn's final state), under the library's.
5130
+ ...Object.assign({}, ...rows.map((row) => row.metadata ?? {})),
5043
5131
  ...usage !== void 0 ? {
5044
5132
  usage
5045
5133
  } : {},
@@ -5076,7 +5164,7 @@ __name(sumUsage, "sumUsage");
5076
5164
 
5077
5165
  // src/use-agent-chat.ts
5078
5166
  import { useChat } from "@ai-sdk/react";
5079
- import { useCallback as useCallback11, useEffect as useEffect14, useMemo as useMemo11, useRef as useRef12, useState as useState14 } from "react";
5167
+ import { useCallback as useCallback11, useEffect as useEffect15, useMemo as useMemo11, useRef as useRef12, useState as useState15 } from "react";
5080
5168
  var localChatSequence = 0;
5081
5169
  function localChatId() {
5082
5170
  localChatSequence += 1;
@@ -5100,22 +5188,22 @@ function useAgentChat(options = {}) {
5100
5188
  }
5101
5189
  }
5102
5190
  const chatId = chatIdRef.current;
5103
- const [runId, setRunId] = useState14(options.resumeRunId);
5191
+ const [runId, setRunId] = useState15(options.resumeRunId);
5104
5192
  const runIdRef = useRef12(runId);
5105
5193
  runIdRef.current = runId;
5106
5194
  const settlingRunIdRef = useRef12(void 0);
5107
5195
  const autoResumeRunIdRef = useRef12(void 0);
5108
- const [activeRunId, setActiveRunId] = useState14(null);
5109
- const [isLoadingHistory, setIsLoadingHistory] = useState14(false);
5110
- const [historyError, setHistoryError] = useState14(null);
5111
- const [threadModel, setThreadModel] = useState14(null);
5112
- const [pickedModel, setPickedModel] = useState14(void 0);
5196
+ const [activeRunId, setActiveRunId] = useState15(null);
5197
+ const [isLoadingHistory, setIsLoadingHistory] = useState15(false);
5198
+ const [historyError, setHistoryError] = useState15(null);
5199
+ const [threadModel, setThreadModel] = useState15(null);
5200
+ const [pickedModel, setPickedModel] = useState15(void 0);
5113
5201
  const pickedModelRef = useRef12(pickedModel);
5114
5202
  pickedModelRef.current = pickedModel;
5115
5203
  const pendingPin = useRef12(void 0);
5116
5204
  const regenerateNext = useRef12(false);
5117
5205
  const currentThreadId = useCallback11(() => latest.current.threadId ?? createdThreadId.current, []);
5118
- const [connection, setConnection] = useState14({
5206
+ const [connection, setConnection] = useState15({
5119
5207
  status: "live"
5120
5208
  });
5121
5209
  const resyncAfterSettle = useRef12(false);
@@ -5161,6 +5249,11 @@ function useAgentChat(options = {}) {
5161
5249
  const threadId = currentThreadId();
5162
5250
  const model = current.model ?? pickedModelRef.current;
5163
5251
  return {
5252
+ // Read per send: a host that switches agents before the first message (a picker on a
5253
+ // new chat) sends the one picked now, not the one this chat mounted with.
5254
+ ...current.agent !== void 0 ? {
5255
+ agent: current.agent
5256
+ } : {},
5164
5257
  ...threadId !== void 0 ? {
5165
5258
  threadId
5166
5259
  } : {},
@@ -5242,7 +5335,7 @@ function useAgentChat(options = {}) {
5242
5335
  }
5243
5336
  __name(resyncFromThread, "resyncFromThread");
5244
5337
  const firstChatId = useRef12(chatId);
5245
- useEffect14(() => {
5338
+ useEffect15(() => {
5246
5339
  if (chatId === firstChatId.current) return;
5247
5340
  firstChatId.current = chatId;
5248
5341
  setRunId(void 0);
@@ -5255,7 +5348,7 @@ function useAgentChat(options = {}) {
5255
5348
  }, [
5256
5349
  chatId
5257
5350
  ]);
5258
- useEffect14(() => {
5351
+ useEffect15(() => {
5259
5352
  const threadId = options.threadId;
5260
5353
  if (threadId === void 0) return;
5261
5354
  if (threadId === createdThreadId.current) return;
@@ -5325,7 +5418,7 @@ function useAgentChat(options = {}) {
5325
5418
  toolCallId,
5326
5419
  output
5327
5420
  }), []);
5328
- const [backgroundRuns, setBackgroundRuns] = useState14([]);
5421
+ const [backgroundRuns, setBackgroundRuns] = useState15([]);
5329
5422
  const refreshBackground = useCallback11(async () => {
5330
5423
  const threadId = currentThreadId();
5331
5424
  if (threadId === void 0) {
@@ -5352,7 +5445,7 @@ function useAgentChat(options = {}) {
5352
5445
  ]);
5353
5446
  backgroundRef.current = refreshBackground;
5354
5447
  const isWorking = backgroundRuns.some((run) => run.status === "running");
5355
- useEffect14(() => {
5448
+ useEffect15(() => {
5356
5449
  if (options.background !== true || options.threadId === void 0) {
5357
5450
  return;
5358
5451
  }
@@ -5363,7 +5456,7 @@ function useAgentChat(options = {}) {
5363
5456
  chatId,
5364
5457
  refreshBackground
5365
5458
  ]);
5366
- useEffect14(() => {
5459
+ useEffect15(() => {
5367
5460
  const every = latest.current.backgroundPollMs ?? 5e3;
5368
5461
  if (latest.current.background !== true || !isWorking || every <= 0) {
5369
5462
  return;
@@ -5489,7 +5582,7 @@ function useAgentChat(options = {}) {
5489
5582
  client,
5490
5583
  currentThreadId
5491
5584
  ]);
5492
- const [modelsWanted, setModelsWanted] = useState14(false);
5585
+ const [modelsWanted, setModelsWanted] = useState15(false);
5493
5586
  const modelsWantedRef = useRef12(modelsWanted);
5494
5587
  modelsWantedRef.current = modelsWanted;
5495
5588
  const catalog = useModels({
@@ -5534,6 +5627,10 @@ function useAgentChat(options = {}) {
5534
5627
  return catalog.providers;
5535
5628
  },
5536
5629
  selected: options.model ?? pickedModel ?? threadModel ?? catalog.defaultModel ?? null,
5630
+ get defaultModel() {
5631
+ wantModels();
5632
+ return catalog.defaultModel;
5633
+ },
5537
5634
  select: selectModel,
5538
5635
  pinToThread,
5539
5636
  isLoading: modelsWanted && catalog.isLoading,
@@ -5545,8 +5642,8 @@ function useAgentChat(options = {}) {
5545
5642
  ...options.composer,
5546
5643
  backend: client
5547
5644
  });
5548
- const [text, setText] = useState14("");
5549
- const blockedBy = blocked != null ? "quota" : files.isUploading ? "uploading" : isBusy ? "busy" : text.trim().length === 0 && files.attachments.length === 0 ? "empty" : null;
5645
+ const [text, setText] = useState15("");
5646
+ const blockedBy = blocked != null ? "quota" : files.isUploading ? "uploading" : isBusy ? "busy" : text.trim().length === 0 && files.refs.length === 0 ? "empty" : null;
5550
5647
  const composerRef = useRef12({
5551
5648
  text,
5552
5649
  files,
@@ -5561,10 +5658,26 @@ function useAgentChat(options = {}) {
5561
5658
  const current = composerRef.current;
5562
5659
  if (current.blockedBy !== null) return;
5563
5660
  const refs = current.files.refs;
5661
+ const files2 = current.files.items.flatMap((item) => item.status === "ready" && item.attachment !== void 0 ? [
5662
+ {
5663
+ type: "file",
5664
+ mediaType: item.attachment.contentType,
5665
+ filename: item.attachment.name,
5666
+ url: item.attachment.url,
5667
+ providerMetadata: {
5668
+ agent: {
5669
+ mediaId: item.attachment.mediaId
5670
+ }
5671
+ }
5672
+ }
5673
+ ] : []);
5564
5674
  const draft = current.text.trim();
5565
5675
  setText("");
5566
5676
  current.files.clear();
5567
- await sendMessage({
5677
+ await sendMessage(files2.length > 0 ? {
5678
+ text: draft,
5679
+ files: files2
5680
+ } : {
5568
5681
  text: draft
5569
5682
  }, refs.length > 0 ? {
5570
5683
  body: {
@@ -5722,6 +5835,7 @@ export {
5722
5835
  toolCatalogFrom,
5723
5836
  useAgentBackend,
5724
5837
  useAgentChat,
5838
+ useAgentConfig,
5725
5839
  useAgents,
5726
5840
  useAmbientRenderUi,
5727
5841
  useApprovalCountdown,