@cntyclub/agent-react 0.16.0 → 0.17.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
@@ -1,6 +1,6 @@
1
1
  import { cn, Button, ThinkingOrb, Tooltip, TooltipTrigger, TooltipContent, ChatMessage, ChatMessageBubble, Markdown, AuroraText, Spinner, Checkbox, Collapsible, CollapsibleTrigger, ChatToolChip, CollapsiblePanel, ChatToolCard, ChatToolCardHeader, ChatToolCardActions, Group, Menu, MenuTrigger, MenuPopup, MenuItem, ChatHeader, ChatHeaderAvatar, ChatHeaderTitle, ChatHeaderActions, Chat, ChatEmptyState, ChatEmptyStateIcon, ChatEmptyStateTitle, ChatEmptyStateDescription, ChatSuggestions, ChatSuggestion, useMediaQuery, TooltipProvider, DataTablePaged } from '@cntyclub/ui-react';
2
2
  import { XIcon, Trash2Icon, SquareIcon, PauseIcon, PlayIcon, CheckIcon, FileTextIcon, PaperclipIcon, MicIcon, ArrowUpIcon, CopyIcon, Maximize2Icon, ListChecksIcon, ChevronDownIcon, ShieldAlertIcon, CheckCheckIcon, UploadCloudIcon, HistoryIcon, SquarePenIcon, Minimize2Icon, ChevronsRightIcon, SparklesIcon, DownloadIcon, CodeIcon } from 'lucide-react';
3
- import * as React11 from 'react';
3
+ import * as React12 from 'react';
4
4
  import { AnimatePresence, motion } from 'motion/react';
5
5
  import { createPortal } from 'react-dom';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -259,7 +259,7 @@ function formatBytes(bytes) {
259
259
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
260
260
  }
261
261
  function AgentImageLightbox({ src, alt, onClose }) {
262
- React11.useEffect(() => {
262
+ React12.useEffect(() => {
263
263
  if (!src) return;
264
264
  const onKey = (event) => {
265
265
  if (event.key === "Escape") onClose();
@@ -329,24 +329,24 @@ function pickMimeType() {
329
329
  return "";
330
330
  }
331
331
  function AgentVoiceRecorder({ maxSeconds, transcribe, onDone, onCancel, onError }) {
332
- const [phase, setPhase] = React11.useState("recording");
333
- const [elapsed, setElapsed] = React11.useState(0);
334
- const [playing, setPlaying] = React11.useState(false);
335
- const recorderRef = React11.useRef(null);
336
- const streamRef = React11.useRef(null);
337
- const chunksRef = React11.useRef([]);
338
- const blobRef = React11.useRef(null);
339
- const audioUrlRef = React11.useRef(null);
340
- const audioRef = React11.useRef(null);
341
- const timerRef = React11.useRef(null);
342
- const canvasRef = React11.useRef(null);
343
- const audioContextRef = React11.useRef(null);
344
- const analyserRef = React11.useRef(null);
345
- const rafRef = React11.useRef(null);
346
- const levelsRef = React11.useRef(new Array(MAX_BARS).fill(0));
347
- const onErrorRef = React11.useRef(onError);
332
+ const [phase, setPhase] = React12.useState("recording");
333
+ const [elapsed, setElapsed] = React12.useState(0);
334
+ const [playing, setPlaying] = React12.useState(false);
335
+ const recorderRef = React12.useRef(null);
336
+ const streamRef = React12.useRef(null);
337
+ const chunksRef = React12.useRef([]);
338
+ const blobRef = React12.useRef(null);
339
+ const audioUrlRef = React12.useRef(null);
340
+ const audioRef = React12.useRef(null);
341
+ const timerRef = React12.useRef(null);
342
+ const canvasRef = React12.useRef(null);
343
+ const audioContextRef = React12.useRef(null);
344
+ const analyserRef = React12.useRef(null);
345
+ const rafRef = React12.useRef(null);
346
+ const levelsRef = React12.useRef(new Array(MAX_BARS).fill(0));
347
+ const onErrorRef = React12.useRef(onError);
348
348
  onErrorRef.current = onError;
349
- const stopMeter = React11.useCallback(() => {
349
+ const stopMeter = React12.useCallback(() => {
350
350
  if (rafRef.current != null) {
351
351
  cancelAnimationFrame(rafRef.current);
352
352
  rafRef.current = null;
@@ -357,7 +357,7 @@ function AgentVoiceRecorder({ maxSeconds, transcribe, onDone, onCancel, onError
357
357
  if (ctx && ctx.state !== "closed") void ctx.close().catch(() => {
358
358
  });
359
359
  }, []);
360
- const stopTracks = React11.useCallback(() => {
360
+ const stopTracks = React12.useCallback(() => {
361
361
  streamRef.current?.getTracks().forEach((track) => track.stop());
362
362
  streamRef.current = null;
363
363
  if (timerRef.current) {
@@ -366,7 +366,7 @@ function AgentVoiceRecorder({ maxSeconds, transcribe, onDone, onCancel, onError
366
366
  }
367
367
  stopMeter();
368
368
  }, [stopMeter]);
369
- const startMeter = React11.useCallback((stream) => {
369
+ const startMeter = React12.useCallback((stream) => {
370
370
  const Ctor = typeof window === "undefined" ? void 0 : window.AudioContext ?? window.webkitAudioContext;
371
371
  if (!Ctor) return;
372
372
  let context;
@@ -436,7 +436,7 @@ function AgentVoiceRecorder({ maxSeconds, transcribe, onDone, onCancel, onError
436
436
  };
437
437
  rafRef.current = requestAnimationFrame(draw);
438
438
  }, []);
439
- React11.useEffect(() => {
439
+ React12.useEffect(() => {
440
440
  let cancelled = false;
441
441
  void (async () => {
442
442
  if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
@@ -589,40 +589,40 @@ function AgentComposer({
589
589
  voiceEnabled,
590
590
  voiceMaxSeconds = 600
591
591
  }) {
592
- const textareaRef = React11.useRef(null);
593
- const inputRef = React11.useRef(null);
594
- const [recording, setRecording] = React11.useState(false);
595
- const [lightboxSrc, setLightboxSrc] = React11.useState(null);
592
+ const textareaRef = React12.useRef(null);
593
+ const inputRef = React12.useRef(null);
594
+ const [recording, setRecording] = React12.useState(false);
595
+ const [lightboxSrc, setLightboxSrc] = React12.useState(null);
596
596
  const canSubmit = !disabled && !busy && (value.trim().length > 0 || files.length > 0);
597
597
  const voiceAvailable = Boolean(voiceEnabled && onTranscribe);
598
- const submit = React11.useCallback(() => {
598
+ const submit = React12.useCallback(() => {
599
599
  if (!canSubmit) return;
600
600
  onSubmit(value.trim());
601
601
  textareaRef.current?.focus();
602
602
  }, [canSubmit, onSubmit, value]);
603
- React11.useEffect(() => {
603
+ React12.useEffect(() => {
604
604
  if (!disabled) textareaRef.current?.focus();
605
605
  }, [disabled]);
606
- React11.useEffect(() => {
606
+ React12.useEffect(() => {
607
607
  const textarea = textareaRef.current;
608
608
  if (!textarea) return;
609
609
  textarea.style.height = "auto";
610
610
  textarea.style.height = `${Math.min(textarea.scrollHeight, 144)}px`;
611
611
  }, [value]);
612
- const previews = React11.useMemo(
612
+ const previews = React12.useMemo(
613
613
  () => files.map((file, originalIndex) => {
614
614
  const image = isImageFile(file);
615
615
  return { file, image, originalIndex, url: image ? URL.createObjectURL(file) : null };
616
616
  }),
617
617
  [files]
618
618
  );
619
- React11.useEffect(
619
+ React12.useEffect(
620
620
  () => () => {
621
621
  previews.forEach((preview) => preview.url && URL.revokeObjectURL(preview.url));
622
622
  },
623
623
  [previews]
624
624
  );
625
- const ordered = React11.useMemo(
625
+ const ordered = React12.useMemo(
626
626
  () => [...previews].sort((a, b) => Number(b.image) - Number(a.image)),
627
627
  [previews]
628
628
  );
@@ -867,15 +867,15 @@ function groupMessages(messages) {
867
867
  return items;
868
868
  }
869
869
  function ChatScroller({ children, className, ...props }) {
870
- const viewportRef = React11.useRef(null);
871
- const pinnedRef = React11.useRef(true);
872
- const handleScroll = React11.useCallback(() => {
870
+ const viewportRef = React12.useRef(null);
871
+ const pinnedRef = React12.useRef(true);
872
+ const handleScroll = React12.useCallback(() => {
873
873
  const viewport = viewportRef.current;
874
874
  if (!viewport) return;
875
875
  const distanceFromBottom = viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight;
876
876
  pinnedRef.current = distanceFromBottom < 64;
877
877
  }, []);
878
- React11.useEffect(() => {
878
+ React12.useEffect(() => {
879
879
  const viewport = viewportRef.current;
880
880
  if (!viewport || !pinnedRef.current) return;
881
881
  viewport.scrollTop = viewport.scrollHeight;
@@ -892,15 +892,66 @@ function ChatScroller({ children, className, ...props }) {
892
892
  }
893
893
  );
894
894
  }
895
+ var MIN_CHARS_PER_FRAME = 2;
896
+ var CATCH_UP = 0.22;
897
+ function usePrefersReducedMotion() {
898
+ const [reduced, setReduced] = React12.useState(
899
+ () => typeof matchMedia !== "undefined" && matchMedia("(prefers-reduced-motion: reduce)").matches
900
+ );
901
+ React12.useEffect(() => {
902
+ if (typeof matchMedia === "undefined") return;
903
+ const mq = matchMedia("(prefers-reduced-motion: reduce)");
904
+ const onChange = (event) => setReduced(event.matches);
905
+ mq.addEventListener("change", onChange);
906
+ return () => mq.removeEventListener("change", onChange);
907
+ }, []);
908
+ return reduced;
909
+ }
910
+ function useSmoothText(target, animate) {
911
+ const prefersReduced = usePrefersReducedMotion();
912
+ const enabled = animate && !prefersReduced;
913
+ const [count, setCount] = React12.useState(() => enabled ? 0 : target.length);
914
+ const countRef = React12.useRef(count);
915
+ countRef.current = count;
916
+ const everEnabled = React12.useRef(enabled);
917
+ if (enabled) everEnabled.current = true;
918
+ React12.useEffect(() => {
919
+ if (!everEnabled.current) {
920
+ if (countRef.current !== target.length) setCount(target.length);
921
+ return;
922
+ }
923
+ if (countRef.current > target.length) {
924
+ setCount(target.length);
925
+ return;
926
+ }
927
+ if (countRef.current >= target.length) return;
928
+ let raf = 0;
929
+ let last = performance.now();
930
+ const tick = (now) => {
931
+ const dt = Math.min(64, now - last);
932
+ last = now;
933
+ const frames = dt / (1e3 / 60);
934
+ const gap = target.length - countRef.current;
935
+ const step = Math.max(MIN_CHARS_PER_FRAME * frames, gap * CATCH_UP * frames);
936
+ const next = Math.min(target.length, countRef.current + step);
937
+ countRef.current = next;
938
+ setCount(next);
939
+ if (next < target.length) raf = requestAnimationFrame(tick);
940
+ };
941
+ raf = requestAnimationFrame(tick);
942
+ return () => cancelAnimationFrame(raf);
943
+ }, [target, enabled]);
944
+ return everEnabled.current ? target.slice(0, Math.floor(count)) : target;
945
+ }
895
946
  function CopyButton({ className, text }) {
896
- const [copied, setCopied] = React11.useState(false);
897
- const timerRef = React11.useRef(null);
898
- React11.useEffect(() => {
947
+ const [copied, setCopied] = React12.useState(false);
948
+ const timerRef = React12.useRef(null);
949
+ React12.useEffect(() => {
899
950
  return () => {
900
951
  if (timerRef.current) clearTimeout(timerRef.current);
901
952
  };
902
953
  }, []);
903
- const copy = React11.useCallback(async () => {
954
+ const copy = React12.useCallback(async () => {
904
955
  try {
905
956
  await navigator.clipboard.writeText(text);
906
957
  } catch {
@@ -932,8 +983,9 @@ function CopyButton({ className, text }) {
932
983
  ] });
933
984
  }
934
985
  var isImageAttachment = (format) => IMAGE_ACCEPT.includes(`.${format.toLowerCase()}`);
935
- function MessageItem({ message }) {
936
- const [lightboxSrc, setLightboxSrc] = React11.useState(null);
986
+ function MessageItem({ animate = false, message }) {
987
+ const [lightboxSrc, setLightboxSrc] = React12.useState(null);
988
+ const displayed = useSmoothText(message.content ?? "", animate && message.role === "assistant");
937
989
  if (message.role === "user") {
938
990
  const attachments = message.attachments ?? [];
939
991
  const images = attachments.filter((a) => isImageAttachment(a.format) && a.url);
@@ -989,7 +1041,7 @@ function MessageItem({ message }) {
989
1041
  if (src) setLightboxSrc(src);
990
1042
  },
991
1043
  role: "presentation",
992
- children: /* @__PURE__ */ jsx(Markdown, { children: message.content })
1044
+ children: /* @__PURE__ */ jsx(Markdown, { children: displayed })
993
1045
  }
994
1046
  ) }),
995
1047
  /* @__PURE__ */ jsx(
@@ -1017,8 +1069,8 @@ var DEFAULT_PHRASES = [
1017
1069
  ];
1018
1070
  function ThinkingIndicator({ className, intervalMs = 1800, phrases }) {
1019
1071
  const words = phrases && phrases.length ? phrases : DEFAULT_PHRASES;
1020
- const [index, setIndex] = React11.useState(0);
1021
- React11.useEffect(() => {
1072
+ const [index, setIndex] = React12.useState(0);
1073
+ React12.useEffect(() => {
1022
1074
  setIndex(0);
1023
1075
  const timer = setInterval(() => {
1024
1076
  setIndex((current) => (current + 1) % words.length);
@@ -1037,14 +1089,7 @@ function ThinkingIndicator({ className, intervalMs = 1800, phrases }) {
1037
1089
  role: "status",
1038
1090
  children: [
1039
1091
  /* @__PURE__ */ jsx(ThinkingOrb, { className: "shrink-0", size: 20, speed: 0.7, state: "solving" }),
1040
- /* @__PURE__ */ jsx(
1041
- "span",
1042
- {
1043
- className: "fade-in-0 animate-in text-xs font-medium duration-300",
1044
- children: /* @__PURE__ */ jsx(AuroraText, { children: words[index] })
1045
- },
1046
- index
1047
- )
1092
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: /* @__PURE__ */ jsx(AuroraText, { speed: 2.2, children: /* @__PURE__ */ jsx("span", { className: "fade-in-0 inline-block animate-in duration-300", children: words[index] }, index) }) })
1048
1093
  ]
1049
1094
  }
1050
1095
  );
@@ -1273,7 +1318,7 @@ function DownloadButton({ block, size = "sm" }) {
1273
1318
  );
1274
1319
  }
1275
1320
  function DocumentViewer({ block, onClose }) {
1276
- React11.useEffect(() => {
1321
+ React12.useEffect(() => {
1277
1322
  const onKey = (event) => event.key === "Escape" && onClose();
1278
1323
  window.addEventListener("keydown", onKey);
1279
1324
  return () => window.removeEventListener("keydown", onKey);
@@ -1298,7 +1343,7 @@ function DocumentViewer({ block, onClose }) {
1298
1343
  ] });
1299
1344
  }
1300
1345
  function DocumentCard({ block }) {
1301
- const [open, setOpen] = React11.useState(false);
1346
+ const [open, setOpen] = React12.useState(false);
1302
1347
  const previewLines = (block.preview || "").split("\n").slice(0, 6).join("\n");
1303
1348
  return /* @__PURE__ */ jsxs("div", { className: "w-full max-w-full overflow-hidden rounded-xl border border-border bg-card shadow-xs", children: [
1304
1349
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-border/72 border-b px-3 py-2", children: [
@@ -1420,7 +1465,7 @@ function StepDetail({
1420
1465
  ] });
1421
1466
  }
1422
1467
  function ToolActivityGroup({ describeToolCall, steps }) {
1423
- const [open, setOpen] = React11.useState(false);
1468
+ const [open, setOpen] = React12.useState(false);
1424
1469
  if (steps.length === 0) return null;
1425
1470
  const last = steps[steps.length - 1];
1426
1471
  const anyRunning = steps.some((step) => step.status === "running");
@@ -1525,12 +1570,12 @@ function AgentPanel({
1525
1570
  onClose,
1526
1571
  onToggleAgentMode
1527
1572
  }) {
1528
- const [draft, setDraft] = React11.useState("");
1529
- const [view, setView] = React11.useState("chat");
1530
- const [files, setFiles] = React11.useState([]);
1531
- const [uploadError, setUploadError] = React11.useState(null);
1532
- const [dragging, setDragging] = React11.useState(false);
1533
- const dragDepth = React11.useRef(0);
1573
+ const [draft, setDraft] = React12.useState("");
1574
+ const [view, setView] = React12.useState("chat");
1575
+ const [files, setFiles] = React12.useState([]);
1576
+ const [uploadError, setUploadError] = React12.useState(null);
1577
+ const [dragging, setDragging] = React12.useState(false);
1578
+ const dragDepth = React12.useRef(0);
1534
1579
  const agentName = config.agentName ?? chat.agentInfo?.name ?? "Assistant";
1535
1580
  const caps = {
1536
1581
  visionEnabled: chat.agentInfo?.vision_enabled,
@@ -1541,7 +1586,7 @@ function AgentPanel({
1541
1586
  "What can you help me with?",
1542
1587
  "Give me a quick summary of my data."
1543
1588
  ];
1544
- const addFiles = React11.useCallback(
1589
+ const addFiles = React12.useCallback(
1545
1590
  (incoming) => {
1546
1591
  const accepted = [];
1547
1592
  let rejection = null;
@@ -1558,10 +1603,10 @@ function AgentPanel({
1558
1603
  },
1559
1604
  [config, caps.visionEnabled, caps.visionMaxMb]
1560
1605
  );
1561
- const removeFile = React11.useCallback((index) => {
1606
+ const removeFile = React12.useCallback((index) => {
1562
1607
  setFiles((current) => current.filter((_, i) => i !== index));
1563
1608
  }, []);
1564
- const handleSubmit = React11.useCallback(
1609
+ const handleSubmit = React12.useCallback(
1565
1610
  (text) => {
1566
1611
  const staged = files;
1567
1612
  setDraft("");
@@ -1571,7 +1616,7 @@ function AgentPanel({
1571
1616
  },
1572
1617
  [chat, files]
1573
1618
  );
1574
- const onDragEnter = React11.useCallback(
1619
+ const onDragEnter = React12.useCallback(
1575
1620
  (event) => {
1576
1621
  if (!uploadEnabled || !event.dataTransfer?.types?.includes("Files")) return;
1577
1622
  dragDepth.current += 1;
@@ -1579,12 +1624,12 @@ function AgentPanel({
1579
1624
  },
1580
1625
  [uploadEnabled]
1581
1626
  );
1582
- const onDragLeave = React11.useCallback((event) => {
1627
+ const onDragLeave = React12.useCallback((event) => {
1583
1628
  if (!event.dataTransfer?.types?.includes("Files")) return;
1584
1629
  dragDepth.current = Math.max(0, dragDepth.current - 1);
1585
1630
  if (dragDepth.current === 0) setDragging(false);
1586
1631
  }, []);
1587
- const onDrop = React11.useCallback(
1632
+ const onDrop = React12.useCallback(
1588
1633
  (event) => {
1589
1634
  if (!uploadEnabled) return;
1590
1635
  event.preventDefault();
@@ -1595,7 +1640,7 @@ function AgentPanel({
1595
1640
  },
1596
1641
  [addFiles, uploadEnabled]
1597
1642
  );
1598
- const openHistory = React11.useCallback(() => {
1643
+ const openHistory = React12.useCallback(() => {
1599
1644
  setView("history");
1600
1645
  void chat.refreshConversations();
1601
1646
  }, [chat]);
@@ -1759,7 +1804,16 @@ function AgentPanel({
1759
1804
  const anchorKey = newMessageAnchorId ? grouped.find(
1760
1805
  (it) => it.kind !== "tool-activity" && it.message.id === newMessageAnchorId
1761
1806
  )?.key : void 0;
1762
- return grouped.map((item) => /* @__PURE__ */ jsxs(React11.Fragment, { children: [
1807
+ let liveAssistantKey = null;
1808
+ if (chat.sending) {
1809
+ for (let i = grouped.length - 1; i >= 0; i -= 1) {
1810
+ if (grouped[i].kind === "assistant-text") {
1811
+ liveAssistantKey = grouped[i].key;
1812
+ break;
1813
+ }
1814
+ }
1815
+ }
1816
+ return grouped.map((item) => /* @__PURE__ */ jsxs(React12.Fragment, { children: [
1763
1817
  item.key === anchorKey ? /* @__PURE__ */ jsx(NewMessagesDivider, {}) : null,
1764
1818
  /* @__PURE__ */ jsx(
1765
1819
  motion.div,
@@ -1773,7 +1827,7 @@ function AgentPanel({
1773
1827
  describeToolCall: config.describeToolCall,
1774
1828
  steps: item.steps
1775
1829
  }
1776
- ) }) : /* @__PURE__ */ jsx(MessageItem, { message: item.message })
1830
+ ) }) : /* @__PURE__ */ jsx(MessageItem, { animate: item.key === liveAssistantKey, message: item.message })
1777
1831
  }
1778
1832
  )
1779
1833
  ] }, item.key));
@@ -1859,17 +1913,17 @@ function buildOptimisticUserMessage(text, files) {
1859
1913
  };
1860
1914
  }
1861
1915
  function useAgentChat(config) {
1862
- const client = React11.useMemo(() => new AgentApiClient(config), [config]);
1863
- const [agentInfo, setAgentInfo] = React11.useState(null);
1864
- const [conversationId, setConversationId] = React11.useState(null);
1865
- const [conversationEpoch, setConversationEpoch] = React11.useState(0);
1866
- const [conversations, setConversations] = React11.useState([]);
1867
- const [messages, setMessages] = React11.useState([]);
1868
- const [pendingApprovals, setPendingApprovals] = React11.useState([]);
1869
- const [sending, setSending] = React11.useState(false);
1870
- const [resolvingApprovalId, setResolvingApprovalId] = React11.useState(null);
1871
- const [error, setError] = React11.useState(null);
1872
- React11.useEffect(() => {
1916
+ const client = React12.useMemo(() => new AgentApiClient(config), [config]);
1917
+ const [agentInfo, setAgentInfo] = React12.useState(null);
1918
+ const [conversationId, setConversationId] = React12.useState(null);
1919
+ const [conversationEpoch, setConversationEpoch] = React12.useState(0);
1920
+ const [conversations, setConversations] = React12.useState([]);
1921
+ const [messages, setMessages] = React12.useState([]);
1922
+ const [pendingApprovals, setPendingApprovals] = React12.useState([]);
1923
+ const [sending, setSending] = React12.useState(false);
1924
+ const [resolvingApprovalId, setResolvingApprovalId] = React12.useState(null);
1925
+ const [error, setError] = React12.useState(null);
1926
+ React12.useEffect(() => {
1873
1927
  let cancelled = false;
1874
1928
  client.getConfig().then((info) => {
1875
1929
  if (!cancelled) setAgentInfo(info);
@@ -1879,11 +1933,11 @@ function useAgentChat(config) {
1879
1933
  cancelled = true;
1880
1934
  };
1881
1935
  }, [client]);
1882
- const handleFailure = React11.useCallback((err) => {
1936
+ const handleFailure = React12.useCallback((err) => {
1883
1937
  const message = err instanceof AgentApiError ? err.message : "Something went wrong. Please try again.";
1884
1938
  setError(message);
1885
1939
  }, []);
1886
- const applyResponse = React11.useCallback(
1940
+ const applyResponse = React12.useCallback(
1887
1941
  (response) => {
1888
1942
  if (response.status === "error" && !response.messages?.length) {
1889
1943
  setError(response.message ?? "The assistant could not answer.");
@@ -1913,7 +1967,7 @@ function useAgentChat(config) {
1913
1967
  },
1914
1968
  []
1915
1969
  );
1916
- const handleStreamEvent = React11.useCallback(
1970
+ const handleStreamEvent = React12.useCallback(
1917
1971
  (event, ctx) => {
1918
1972
  switch (event.type) {
1919
1973
  case "conversation":
@@ -1992,7 +2046,7 @@ function useAgentChat(config) {
1992
2046
  []
1993
2047
  );
1994
2048
  const streamingEnabled = config.streaming !== false && typeof ReadableStream !== "undefined";
1995
- const send = React11.useCallback(
2049
+ const send = React12.useCallback(
1996
2050
  async (text, files) => {
1997
2051
  if (sending) return;
1998
2052
  if (!text.trim() && !(files && files.length)) return;
@@ -2023,14 +2077,14 @@ function useAgentChat(config) {
2023
2077
  },
2024
2078
  [applyResponse, client, conversationId, handleFailure, handleStreamEvent, sending, streamingEnabled]
2025
2079
  );
2026
- const transcribe = React11.useCallback(
2080
+ const transcribe = React12.useCallback(
2027
2081
  async (audio) => {
2028
2082
  const { text } = await client.transcribe(audio);
2029
2083
  return text;
2030
2084
  },
2031
2085
  [client]
2032
2086
  );
2033
- const resolveApproval = React11.useCallback(
2087
+ const resolveApproval = React12.useCallback(
2034
2088
  async (callId, approve) => {
2035
2089
  if (resolvingApprovalId) return;
2036
2090
  setResolvingApprovalId(callId);
@@ -2059,14 +2113,14 @@ function useAgentChat(config) {
2059
2113
  },
2060
2114
  [applyResponse, client, handleFailure, handleStreamEvent, resolvingApprovalId, streamingEnabled]
2061
2115
  );
2062
- const newChat = React11.useCallback(() => {
2116
+ const newChat = React12.useCallback(() => {
2063
2117
  setConversationId(null);
2064
2118
  setMessages([]);
2065
2119
  setPendingApprovals([]);
2066
2120
  setError(null);
2067
2121
  setConversationEpoch((e) => e + 1);
2068
2122
  }, []);
2069
- const refreshConversations = React11.useCallback(async () => {
2123
+ const refreshConversations = React12.useCallback(async () => {
2070
2124
  try {
2071
2125
  const { conversations: list } = await client.listConversations();
2072
2126
  setConversations(list);
@@ -2076,7 +2130,7 @@ function useAgentChat(config) {
2076
2130
  return [];
2077
2131
  }
2078
2132
  }, [client, handleFailure]);
2079
- const openConversation = React11.useCallback(
2133
+ const openConversation = React12.useCallback(
2080
2134
  async (id) => {
2081
2135
  setError(null);
2082
2136
  try {
@@ -2091,7 +2145,7 @@ function useAgentChat(config) {
2091
2145
  },
2092
2146
  [client, handleFailure]
2093
2147
  );
2094
- const deleteConversation = React11.useCallback(
2148
+ const deleteConversation = React12.useCallback(
2095
2149
  async (id) => {
2096
2150
  try {
2097
2151
  await client.deleteConversation(id);
@@ -2103,7 +2157,7 @@ function useAgentChat(config) {
2103
2157
  },
2104
2158
  [client, conversationId, handleFailure, newChat]
2105
2159
  );
2106
- const clearError = React11.useCallback(() => setError(null), []);
2160
+ const clearError = React12.useCallback(() => setError(null), []);
2107
2161
  return {
2108
2162
  agentInfo,
2109
2163
  clearError,
@@ -2140,11 +2194,11 @@ function readStored(clientId) {
2140
2194
  }
2141
2195
  }
2142
2196
  function useAlwaysApprove(clientId) {
2143
- const [approved, setApproved] = React11.useState(() => /* @__PURE__ */ new Set());
2144
- React11.useEffect(() => {
2197
+ const [approved, setApproved] = React12.useState(() => /* @__PURE__ */ new Set());
2198
+ React12.useEffect(() => {
2145
2199
  setApproved(readStored(clientId));
2146
2200
  }, [clientId]);
2147
- const persist = React11.useCallback(
2201
+ const persist = React12.useCallback(
2148
2202
  (next) => {
2149
2203
  setApproved(next);
2150
2204
  if (typeof window === "undefined") return;
@@ -2155,8 +2209,8 @@ function useAlwaysApprove(clientId) {
2155
2209
  },
2156
2210
  [clientId]
2157
2211
  );
2158
- const isAlwaysApproved = React11.useCallback((toolName) => approved.has(toolName), [approved]);
2159
- const setAlwaysApprove = React11.useCallback(
2212
+ const isAlwaysApproved = React12.useCallback((toolName) => approved.has(toolName), [approved]);
2213
+ const setAlwaysApprove = React12.useCallback(
2160
2214
  (toolName) => {
2161
2215
  if (approved.has(toolName)) return;
2162
2216
  const next = new Set(approved);
@@ -2165,7 +2219,7 @@ function useAlwaysApprove(clientId) {
2165
2219
  },
2166
2220
  [approved, persist]
2167
2221
  );
2168
- const clearAlwaysApprove = React11.useCallback(
2222
+ const clearAlwaysApprove = React12.useCallback(
2169
2223
  (toolName) => {
2170
2224
  if (!approved.has(toolName)) return;
2171
2225
  const next = new Set(approved);
@@ -2191,10 +2245,10 @@ function AgentWidget({
2191
2245
  const isControlled = controlledOpen !== void 0;
2192
2246
  const isDocked = presentation === "docked";
2193
2247
  const storageKey2 = `cc-agent-open:${config.clientId}`;
2194
- const [uncontrolledOpen, setUncontrolledOpen] = React11.useState(false);
2248
+ const [uncontrolledOpen, setUncontrolledOpen] = React12.useState(false);
2195
2249
  const open = controlledOpen ?? uncontrolledOpen;
2196
- const [bootstrapDone, setBootstrapDone] = React11.useState(isControlled);
2197
- const persist = React11.useCallback(
2250
+ const [bootstrapDone, setBootstrapDone] = React12.useState(isControlled);
2251
+ const persist = React12.useCallback(
2198
2252
  (next) => {
2199
2253
  if (isControlled || !behavior.persistOpenState) return;
2200
2254
  try {
@@ -2204,7 +2258,7 @@ function AgentWidget({
2204
2258
  },
2205
2259
  [behavior.persistOpenState, isControlled, storageKey2]
2206
2260
  );
2207
- const setOpen = React11.useCallback(
2261
+ const setOpen = React12.useCallback(
2208
2262
  (next) => {
2209
2263
  setUncontrolledOpen(next);
2210
2264
  persist(next);
@@ -2212,14 +2266,14 @@ function AgentWidget({
2212
2266
  },
2213
2267
  [onOpenChange, persist]
2214
2268
  );
2215
- const [agentMode, setAgentMode] = React11.useState(false);
2269
+ const [agentMode, setAgentMode] = React12.useState(false);
2216
2270
  const isDesktop = useMediaQuery("(min-width: 640px)", { defaultSSRValue: true, ssr: true });
2217
2271
  const fullscreen = !isDesktop || agentMode;
2218
2272
  const chat = useAgentChat(config);
2219
2273
  const alwaysApprove = useAlwaysApprove(config.clientId);
2220
2274
  const { messages, pendingApprovals, resolveApproval, resolvingApprovalId, sending } = chat;
2221
- const bootRef = React11.useRef(false);
2222
- React11.useEffect(() => {
2275
+ const bootRef = React12.useRef(false);
2276
+ React12.useEffect(() => {
2223
2277
  if (bootRef.current) return;
2224
2278
  if (isControlled && !isDocked) return;
2225
2279
  bootRef.current = true;
@@ -2251,15 +2305,15 @@ function AgentWidget({
2251
2305
  cancelled = true;
2252
2306
  };
2253
2307
  }, []);
2254
- const seenCountRef = React11.useRef(0);
2255
- const [baselined, setBaselined] = React11.useState(false);
2256
- const [anchorId, setAnchorId] = React11.useState(null);
2257
- React11.useEffect(() => {
2308
+ const seenCountRef = React12.useRef(0);
2309
+ const [baselined, setBaselined] = React12.useState(false);
2310
+ const [anchorId, setAnchorId] = React12.useState(null);
2311
+ React12.useEffect(() => {
2258
2312
  if (baselined || !bootstrapDone) return;
2259
2313
  seenCountRef.current = messages.length;
2260
2314
  setBaselined(true);
2261
2315
  }, [baselined, bootstrapDone, messages.length]);
2262
- React11.useEffect(() => {
2316
+ React12.useEffect(() => {
2263
2317
  if (open) {
2264
2318
  if (messages.length > seenCountRef.current) {
2265
2319
  const firstUnread = messages[seenCountRef.current];
@@ -2269,7 +2323,7 @@ function AgentWidget({
2269
2323
  }
2270
2324
  }, [open, messages]);
2271
2325
  const unreadCount = open || !baselined ? 0 : messages.slice(seenCountRef.current).filter(isUnreadable).length;
2272
- const workLabel = React11.useMemo(() => {
2326
+ const workLabel = React12.useMemo(() => {
2273
2327
  if (!sending) return null;
2274
2328
  const last = messages[messages.length - 1];
2275
2329
  if (last?.role === "tool") return "Calling tools\u2026";
@@ -2278,14 +2332,14 @@ function AgentWidget({
2278
2332
  }, [sending, messages]);
2279
2333
  const approvalWaiting = pendingApprovals.length > 0;
2280
2334
  const { isAlwaysApproved } = alwaysApprove;
2281
- React11.useEffect(() => {
2335
+ React12.useEffect(() => {
2282
2336
  if (resolvingApprovalId) return;
2283
2337
  const target = pendingApprovals.find((approval) => isAlwaysApproved(approval.tool_name));
2284
2338
  if (target) void resolveApproval(target.id, true);
2285
2339
  }, [pendingApprovals, resolvingApprovalId, isAlwaysApproved, resolveApproval]);
2286
- const firedWriteIds = React11.useRef(/* @__PURE__ */ new Set());
2340
+ const firedWriteIds = React12.useRef(/* @__PURE__ */ new Set());
2287
2341
  const { onWriteSuccess } = config;
2288
- React11.useEffect(() => {
2342
+ React12.useEffect(() => {
2289
2343
  if (!onWriteSuccess) return;
2290
2344
  for (const message of messages) {
2291
2345
  if (message.role !== "tool" || !message.is_write || message.tool_status !== "success") continue;
@@ -2295,9 +2349,9 @@ function AgentWidget({
2295
2349
  onWriteSuccess({ arguments: args, toolName: message.tool_name ?? "" });
2296
2350
  }
2297
2351
  }, [messages, onWriteSuccess]);
2298
- const lastNavigatedMessageId = React11.useRef(null);
2299
- const navEpochRef = React11.useRef(-1);
2300
- React11.useEffect(() => {
2352
+ const lastNavigatedMessageId = React12.useRef(null);
2353
+ const navEpochRef = React12.useRef(-1);
2354
+ React12.useEffect(() => {
2301
2355
  if (!open || fullscreen || !config.navigate || !config.pages?.length) return;
2302
2356
  const toolMessages = messages.filter((message) => message.role === "tool");
2303
2357
  const latest = toolMessages[toolMessages.length - 1];
@@ -2316,7 +2370,7 @@ function AgentWidget({
2316
2370
  const scrollTo = typeof mapping.scrollTo === "function" ? mapping.scrollTo(args) : mapping.scrollTo;
2317
2371
  config.navigate(path, { scrollTo: scrollTo ?? null });
2318
2372
  }, [chat.conversationEpoch, config, fullscreen, messages, open]);
2319
- const closePanel = React11.useCallback(() => {
2373
+ const closePanel = React12.useCallback(() => {
2320
2374
  setOpen(false);
2321
2375
  setAgentMode(false);
2322
2376
  }, [setOpen]);
@@ -2489,6 +2543,6 @@ function defineAgentConfig(config) {
2489
2543
  return config;
2490
2544
  }
2491
2545
 
2492
- export { AgentApiClient, AgentApiError, AgentComposer, AgentImageLightbox, AgentPanel, AgentVoiceRecorder, AgentWidget, ChatScroller, CopyButton, DEFAULT_ACCEPT, DocumentCard, IMAGE_ACCEPT, MessageItem, TaskChecklist, ThinkingIndicator, ToolActivityGroup, ToolApprovalCard, acceptAttribute, acceptedExtensions, attachmentsEnabled, defineAgentConfig, deriveDetails, fileUploadEnabled, formatBytes, groupMessages, humanizeToolName, isImageFile, resolveToolPresentation, textExtensions, useAgentChat, useAlwaysApprove, validateFile };
2546
+ export { AgentApiClient, AgentApiError, AgentComposer, AgentImageLightbox, AgentPanel, AgentVoiceRecorder, AgentWidget, ChatScroller, CopyButton, DEFAULT_ACCEPT, DocumentCard, IMAGE_ACCEPT, MessageItem, TaskChecklist, ThinkingIndicator, ToolActivityGroup, ToolApprovalCard, acceptAttribute, acceptedExtensions, attachmentsEnabled, defineAgentConfig, deriveDetails, fileUploadEnabled, formatBytes, groupMessages, humanizeToolName, isImageFile, resolveToolPresentation, textExtensions, useAgentChat, useAlwaysApprove, useSmoothText, validateFile };
2493
2547
  //# sourceMappingURL=index.js.map
2494
2548
  //# sourceMappingURL=index.js.map