@cntyclub/agent-react 0.9.0 → 0.9.1

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.
@@ -4,7 +4,13 @@ export interface AgentComposerProps {
4
4
  onValueChange: (value: string) => void;
5
5
  /** Submit the trimmed text plus any staged files. */
6
6
  onSubmit: (text: string) => void;
7
+ /** Hard-disable the input entirely (e.g. a pending approval must be resolved). */
7
8
  disabled?: boolean;
9
+ /**
10
+ * A reply is in progress. The textarea stays enabled and focused so the user
11
+ * can start writing their next message, but submitting is blocked until done.
12
+ */
13
+ busy?: boolean;
8
14
  placeholder?: string;
9
15
  className?: string;
10
16
  /** File upload wiring. Omit `onPickFiles` to hide the attach button. */
@@ -19,5 +25,5 @@ export interface AgentComposerProps {
19
25
  * Shift+Enter inserts a newline. Submitting is allowed when there is text OR at
20
26
  * least one staged file.
21
27
  */
22
- export declare function AgentComposer({ acceptAttribute, className, disabled, files, onPickFiles, onRemoveFile, onSubmit, onValueChange, placeholder, value, }: AgentComposerProps): React.JSX.Element;
28
+ export declare function AgentComposer({ acceptAttribute, busy, className, disabled, files, onPickFiles, onRemoveFile, onSubmit, onValueChange, placeholder, value, }: AgentComposerProps): React.JSX.Element;
23
29
  //# sourceMappingURL=agent-composer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-composer.d.ts","sourceRoot":"","sources":["../../src/components/agent-composer.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,qDAAqD;IACrD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IACtC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAC5B,eAAe,EACf,SAAS,EACT,QAAQ,EACR,KAAK,EACL,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,WAA6B,EAC7B,KAAK,GACN,EAAE,kBAAkB,qBAqHpB"}
1
+ {"version":3,"file":"agent-composer.d.ts","sourceRoot":"","sources":["../../src/components/agent-composer.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,qDAAqD;IACrD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,kFAAkF;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IACtC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAC5B,eAAe,EACf,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,KAAK,EACL,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,WAA6B,EAC7B,KAAK,GACN,EAAE,kBAAkB,qBA6HpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"agent-panel.d.ts","sourceRoot":"","sources":["../../src/components/agent-panel.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAO5C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,cAAc,GAAG,gBAAgB,CAAC;IACxC,yCAAyC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,4DAA4D;IAC5D,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,iEAAiE;IACjE,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EACzB,SAAS,EACT,kBAAkB,EAClB,IAAI,EACJ,SAAS,EACT,MAAM,EACN,eAAe,EACf,OAAO,EACP,iBAAiB,GAClB,EAAE,eAAe,qBAiTjB"}
1
+ {"version":3,"file":"agent-panel.d.ts","sourceRoot":"","sources":["../../src/components/agent-panel.tsx"],"names":[],"mappings":"AA8BA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAQ5C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,cAAc,GAAG,gBAAgB,CAAC;IACxC,yCAAyC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,4DAA4D;IAC5D,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,iEAAiE;IACjE,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EACzB,SAAS,EACT,kBAAkB,EAClB,IAAI,EACJ,SAAS,EACT,MAAM,EACN,eAAe,EACf,OAAO,EACP,iBAAiB,GAClB,EAAE,eAAe,qBAkTjB"}
@@ -0,0 +1,17 @@
1
+ import * as React from "react";
2
+ export type ChatScrollerProps = React.ComponentProps<"div">;
3
+ /**
4
+ * Scrollable message viewport that stays pinned to the bottom while content
5
+ * grows — including token-by-token streaming, where text is appended to the
6
+ * SAME message rather than adding new ones.
7
+ *
8
+ * Why not the UI kit's ChatMessages autoScroll: that container uses CSS
9
+ * `scroll-smooth`, so a programmatic jump to the bottom emits intermediate
10
+ * `scroll` events mid-animation whose distance-from-bottom is large, which
11
+ * flips its "pinned" flag to false — after the first delta it stops following.
12
+ * Here we scroll INSTANTLY (no smooth), so the only resulting scroll event is
13
+ * at the true bottom and the pin holds for the whole stream. The user can still
14
+ * scroll up to read history (that unpins), and scrolling back down re-pins.
15
+ */
16
+ export declare function ChatScroller({ children, className, ...props }: ChatScrollerProps): React.JSX.Element;
17
+ //# sourceMappingURL=chat-scroller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-scroller.d.ts","sourceRoot":"","sources":["../../src/components/chat-scroller.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,iBAAiB,GAAG,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;AAE5D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,iBAAiB,qBA8BhF"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { AgentApiClient, AgentApiError } from "./api-client";
2
2
  export { AgentComposer, type AgentComposerProps } from "./components/agent-composer";
3
3
  export { AgentPanel, type AgentPanelProps } from "./components/agent-panel";
4
4
  export { AgentWidget, type AgentWidgetProps } from "./components/agent-widget";
5
+ export { ChatScroller, type ChatScrollerProps } from "./components/chat-scroller";
5
6
  export { DocumentCard } from "./components/document-card";
6
7
  export { MessageItem } from "./components/message-item";
7
8
  export { TaskChecklist } from "./components/task-checklist";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACrF,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACjG,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAClG,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAC/F,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,WAAW,EACX,YAAY,GACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACjF,YAAY,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,eAAe,EACf,UAAU,EACV,QAAQ,EACR,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,UAAU,IAAI,mBAAmB,EACjC,UAAU,IAAI,mBAAmB,EACjC,KAAK,IAAI,cAAc,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACrF,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACjG,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAClG,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAC/F,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,WAAW,EACX,YAAY,GACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACjF,YAAY,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,eAAe,EACf,UAAU,EACV,QAAQ,EACR,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,UAAU,IAAI,mBAAmB,EACjC,UAAU,IAAI,mBAAmB,EACjC,KAAK,IAAI,cAAc,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { Button, cn, ChatMessage, ChatMessageBubble, Markdown, Spinner, Checkbox, Collapsible, CollapsibleTrigger, ChatToolChip, CollapsiblePanel, ChatToolCard, ChatToolCardHeader, ChatToolCardActions, Group, Menu, MenuTrigger, MenuPopup, MenuItem, ChatHeader, ChatHeaderAvatar, ChatHeaderTitle, ChatHeaderActions, Tooltip, TooltipTrigger, TooltipContent, Chat, ChatMessages, ChatEmptyState, ChatEmptyStateIcon, ChatEmptyStateTitle, ChatEmptyStateDescription, ChatSuggestions, ChatSuggestion, useMediaQuery, TooltipProvider, Fab, DataTablePaged } from '@cntyclub/ui-react';
1
+ import { Button, cn, ChatMessage, ChatMessageBubble, Markdown, Spinner, Checkbox, Collapsible, CollapsibleTrigger, ChatToolChip, CollapsiblePanel, ChatToolCard, ChatToolCardHeader, ChatToolCardActions, Group, Menu, MenuTrigger, MenuPopup, MenuItem, ChatHeader, ChatHeaderAvatar, ChatHeaderTitle, ChatHeaderActions, Tooltip, TooltipTrigger, TooltipContent, Chat, ChatEmptyState, ChatEmptyStateIcon, ChatEmptyStateTitle, ChatEmptyStateDescription, ChatSuggestions, ChatSuggestion, useMediaQuery, TooltipProvider, Fab, DataTablePaged } from '@cntyclub/ui-react';
2
2
  import { FileTextIcon, XIcon, PaperclipIcon, ArrowUpIcon, Maximize2Icon, ListChecksIcon, ChevronDownIcon, CheckIcon, ShieldAlertIcon, CheckCheckIcon, UploadCloudIcon, HistoryIcon, SquarePenIcon, Minimize2Icon, Trash2Icon, SparklesIcon, DownloadIcon, CodeIcon } from 'lucide-react';
3
- import * as React6 from 'react';
3
+ import * as React7 from 'react';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
 
6
6
  // src/api-client.ts
@@ -219,6 +219,7 @@ function formatBytes(bytes) {
219
219
  }
220
220
  function AgentComposer({
221
221
  acceptAttribute: acceptAttribute2,
222
+ busy,
222
223
  className,
223
224
  disabled,
224
225
  files,
@@ -229,14 +230,18 @@ function AgentComposer({
229
230
  placeholder = "Ask anything\u2026",
230
231
  value
231
232
  }) {
232
- const textareaRef = React6.useRef(null);
233
- const inputRef = React6.useRef(null);
234
- const canSubmit = !disabled && (value.trim().length > 0 || files.length > 0);
235
- const submit = React6.useCallback(() => {
233
+ const textareaRef = React7.useRef(null);
234
+ const inputRef = React7.useRef(null);
235
+ const canSubmit = !disabled && !busy && (value.trim().length > 0 || files.length > 0);
236
+ const submit = React7.useCallback(() => {
236
237
  if (!canSubmit) return;
237
238
  onSubmit(value.trim());
239
+ textareaRef.current?.focus();
238
240
  }, [canSubmit, onSubmit, value]);
239
- React6.useEffect(() => {
241
+ React7.useEffect(() => {
242
+ if (!disabled) textareaRef.current?.focus();
243
+ }, [disabled]);
244
+ React7.useEffect(() => {
240
245
  const textarea = textareaRef.current;
241
246
  if (!textarea) return;
242
247
  textarea.style.height = "auto";
@@ -417,6 +422,32 @@ function groupMessages(messages) {
417
422
  flush();
418
423
  return items;
419
424
  }
425
+ function ChatScroller({ children, className, ...props }) {
426
+ const viewportRef = React7.useRef(null);
427
+ const pinnedRef = React7.useRef(true);
428
+ const handleScroll = React7.useCallback(() => {
429
+ const viewport = viewportRef.current;
430
+ if (!viewport) return;
431
+ const distanceFromBottom = viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight;
432
+ pinnedRef.current = distanceFromBottom < 64;
433
+ }, []);
434
+ React7.useEffect(() => {
435
+ const viewport = viewportRef.current;
436
+ if (!viewport || !pinnedRef.current) return;
437
+ viewport.scrollTop = viewport.scrollHeight;
438
+ });
439
+ return /* @__PURE__ */ jsx(
440
+ "div",
441
+ {
442
+ className: cn("flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-4", className),
443
+ "data-slot": "chat-scroller",
444
+ onScroll: handleScroll,
445
+ ref: viewportRef,
446
+ ...props,
447
+ children
448
+ }
449
+ );
450
+ }
420
451
  function MessageItem({ message }) {
421
452
  if (message.role === "user") {
422
453
  const attachments = message.attachments ?? [];
@@ -451,8 +482,8 @@ var DEFAULT_PHRASES = [
451
482
  ];
452
483
  function ThinkingIndicator({ className, intervalMs = 1800, phrases }) {
453
484
  const words = phrases && phrases.length ? phrases : DEFAULT_PHRASES;
454
- const [index, setIndex] = React6.useState(0);
455
- React6.useEffect(() => {
485
+ const [index, setIndex] = React7.useState(0);
486
+ React7.useEffect(() => {
456
487
  setIndex(0);
457
488
  const timer = setInterval(() => {
458
489
  setIndex((current) => (current + 1) % words.length);
@@ -481,7 +512,7 @@ function ThinkingIndicator({ className, intervalMs = 1800, phrases }) {
481
512
  className: "fade-in-0 animate-in text-muted-foreground text-xs duration-300",
482
513
  children: [
483
514
  words[index],
484
- "\u2026"
515
+ " \u2026"
485
516
  ]
486
517
  },
487
518
  index
@@ -714,7 +745,7 @@ function DownloadButton({ block, size = "sm" }) {
714
745
  );
715
746
  }
716
747
  function DocumentViewer({ block, onClose }) {
717
- React6.useEffect(() => {
748
+ React7.useEffect(() => {
718
749
  const onKey = (event) => event.key === "Escape" && onClose();
719
750
  window.addEventListener("keydown", onKey);
720
751
  return () => window.removeEventListener("keydown", onKey);
@@ -739,7 +770,7 @@ function DocumentViewer({ block, onClose }) {
739
770
  ] });
740
771
  }
741
772
  function DocumentCard({ block }) {
742
- const [open, setOpen] = React6.useState(false);
773
+ const [open, setOpen] = React7.useState(false);
743
774
  const previewLines = (block.preview || "").split("\n").slice(0, 6).join("\n");
744
775
  return /* @__PURE__ */ jsxs("div", { className: "w-full max-w-full overflow-hidden rounded-xl border border-border bg-card shadow-xs", children: [
745
776
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-border/72 border-b px-3 py-2", children: [
@@ -861,7 +892,7 @@ function StepDetail({
861
892
  ] });
862
893
  }
863
894
  function ToolActivityGroup({ describeToolCall, steps }) {
864
- const [open, setOpen] = React6.useState(false);
895
+ const [open, setOpen] = React7.useState(false);
865
896
  if (steps.length === 0) return null;
866
897
  const last = steps[steps.length - 1];
867
898
  const anyRunning = steps.some((step) => step.status === "running");
@@ -964,19 +995,19 @@ function AgentPanel({
964
995
  onClose,
965
996
  onToggleAgentMode
966
997
  }) {
967
- const [draft, setDraft] = React6.useState("");
968
- const [view, setView] = React6.useState("chat");
969
- const [files, setFiles] = React6.useState([]);
970
- const [uploadError, setUploadError] = React6.useState(null);
971
- const [dragging, setDragging] = React6.useState(false);
972
- const dragDepth = React6.useRef(0);
998
+ const [draft, setDraft] = React7.useState("");
999
+ const [view, setView] = React7.useState("chat");
1000
+ const [files, setFiles] = React7.useState([]);
1001
+ const [uploadError, setUploadError] = React7.useState(null);
1002
+ const [dragging, setDragging] = React7.useState(false);
1003
+ const dragDepth = React7.useRef(0);
973
1004
  const agentName = config.agentName ?? chat.agentInfo?.name ?? "Assistant";
974
1005
  const uploadEnabled = fileUploadEnabled(config);
975
1006
  const suggestions = config.suggestions ?? [
976
1007
  "What can you help me with?",
977
1008
  "Give me a quick summary of my data."
978
1009
  ];
979
- const addFiles = React6.useCallback(
1010
+ const addFiles = React7.useCallback(
980
1011
  (incoming) => {
981
1012
  const accepted = [];
982
1013
  let rejection = null;
@@ -993,10 +1024,10 @@ function AgentPanel({
993
1024
  },
994
1025
  [config]
995
1026
  );
996
- const removeFile = React6.useCallback((index) => {
1027
+ const removeFile = React7.useCallback((index) => {
997
1028
  setFiles((current) => current.filter((_, i) => i !== index));
998
1029
  }, []);
999
- const handleSubmit = React6.useCallback(
1030
+ const handleSubmit = React7.useCallback(
1000
1031
  (text) => {
1001
1032
  const staged = files;
1002
1033
  setDraft("");
@@ -1006,7 +1037,7 @@ function AgentPanel({
1006
1037
  },
1007
1038
  [chat, files]
1008
1039
  );
1009
- const onDragEnter = React6.useCallback(
1040
+ const onDragEnter = React7.useCallback(
1010
1041
  (event) => {
1011
1042
  if (!uploadEnabled || !event.dataTransfer?.types?.includes("Files")) return;
1012
1043
  dragDepth.current += 1;
@@ -1014,12 +1045,12 @@ function AgentPanel({
1014
1045
  },
1015
1046
  [uploadEnabled]
1016
1047
  );
1017
- const onDragLeave = React6.useCallback((event) => {
1048
+ const onDragLeave = React7.useCallback((event) => {
1018
1049
  if (!event.dataTransfer?.types?.includes("Files")) return;
1019
1050
  dragDepth.current = Math.max(0, dragDepth.current - 1);
1020
1051
  if (dragDepth.current === 0) setDragging(false);
1021
1052
  }, []);
1022
- const onDrop = React6.useCallback(
1053
+ const onDrop = React7.useCallback(
1023
1054
  (event) => {
1024
1055
  if (!uploadEnabled) return;
1025
1056
  event.preventDefault();
@@ -1030,7 +1061,7 @@ function AgentPanel({
1030
1061
  },
1031
1062
  [addFiles, uploadEnabled]
1032
1063
  );
1033
- const openHistory = React6.useCallback(() => {
1064
+ const openHistory = React7.useCallback(() => {
1034
1065
  setView("history");
1035
1066
  void chat.refreshConversations();
1036
1067
  }, [chat]);
@@ -1160,7 +1191,7 @@ function AgentPanel({
1160
1191
  },
1161
1192
  conversation.id
1162
1193
  )) }) : /* @__PURE__ */ jsxs(Chat, { children: [
1163
- /* @__PURE__ */ jsx(ChatMessages, { className: cn(agentMode && "mx-auto w-full max-w-3xl"), children: chat.messages.length === 0 && !chat.sending ? /* @__PURE__ */ jsxs(ChatEmptyState, { children: [
1194
+ /* @__PURE__ */ jsx(ChatScroller, { className: cn(agentMode && "mx-auto w-full max-w-3xl"), children: chat.messages.length === 0 && !chat.sending ? /* @__PURE__ */ jsxs(ChatEmptyState, { children: [
1164
1195
  /* @__PURE__ */ jsx(ChatEmptyStateIcon, {}),
1165
1196
  /* @__PURE__ */ jsxs("div", { children: [
1166
1197
  /* @__PURE__ */ jsxs(ChatEmptyStateTitle, { children: [
@@ -1215,8 +1246,9 @@ function AgentPanel({
1215
1246
  AgentComposer,
1216
1247
  {
1217
1248
  acceptAttribute: acceptAttribute(config),
1249
+ busy,
1218
1250
  className: cn(agentMode && "mx-auto w-full max-w-3xl"),
1219
- disabled: busy || chat.pendingApprovals.length > 0,
1251
+ disabled: chat.pendingApprovals.length > 0,
1220
1252
  files,
1221
1253
  onPickFiles: uploadEnabled ? addFiles : void 0,
1222
1254
  onRemoveFile: removeFile,
@@ -1252,16 +1284,16 @@ function buildOptimisticUserMessage(text, files) {
1252
1284
  };
1253
1285
  }
1254
1286
  function useAgentChat(config) {
1255
- const client = React6.useMemo(() => new AgentApiClient(config), [config]);
1256
- const [agentInfo, setAgentInfo] = React6.useState(null);
1257
- const [conversationId, setConversationId] = React6.useState(null);
1258
- const [conversations, setConversations] = React6.useState([]);
1259
- const [messages, setMessages] = React6.useState([]);
1260
- const [pendingApprovals, setPendingApprovals] = React6.useState([]);
1261
- const [sending, setSending] = React6.useState(false);
1262
- const [resolvingApprovalId, setResolvingApprovalId] = React6.useState(null);
1263
- const [error, setError] = React6.useState(null);
1264
- React6.useEffect(() => {
1287
+ const client = React7.useMemo(() => new AgentApiClient(config), [config]);
1288
+ const [agentInfo, setAgentInfo] = React7.useState(null);
1289
+ const [conversationId, setConversationId] = React7.useState(null);
1290
+ const [conversations, setConversations] = React7.useState([]);
1291
+ const [messages, setMessages] = React7.useState([]);
1292
+ const [pendingApprovals, setPendingApprovals] = React7.useState([]);
1293
+ const [sending, setSending] = React7.useState(false);
1294
+ const [resolvingApprovalId, setResolvingApprovalId] = React7.useState(null);
1295
+ const [error, setError] = React7.useState(null);
1296
+ React7.useEffect(() => {
1265
1297
  let cancelled = false;
1266
1298
  client.getConfig().then((info) => {
1267
1299
  if (!cancelled) setAgentInfo(info);
@@ -1271,11 +1303,11 @@ function useAgentChat(config) {
1271
1303
  cancelled = true;
1272
1304
  };
1273
1305
  }, [client]);
1274
- const handleFailure = React6.useCallback((err) => {
1306
+ const handleFailure = React7.useCallback((err) => {
1275
1307
  const message = err instanceof AgentApiError ? err.message : "Something went wrong. Please try again.";
1276
1308
  setError(message);
1277
1309
  }, []);
1278
- const applyResponse = React6.useCallback(
1310
+ const applyResponse = React7.useCallback(
1279
1311
  (response) => {
1280
1312
  if (response.status === "error" && !response.messages?.length) {
1281
1313
  setError(response.message ?? "The assistant could not answer.");
@@ -1297,7 +1329,7 @@ function useAgentChat(config) {
1297
1329
  },
1298
1330
  []
1299
1331
  );
1300
- const handleStreamEvent = React6.useCallback(
1332
+ const handleStreamEvent = React7.useCallback(
1301
1333
  (event, ctx) => {
1302
1334
  switch (event.type) {
1303
1335
  case "conversation":
@@ -1362,7 +1394,7 @@ function useAgentChat(config) {
1362
1394
  []
1363
1395
  );
1364
1396
  const streamingEnabled = config.streaming !== false && typeof ReadableStream !== "undefined";
1365
- const send = React6.useCallback(
1397
+ const send = React7.useCallback(
1366
1398
  async (text, files) => {
1367
1399
  if (sending) return;
1368
1400
  if (!text.trim() && !(files && files.length)) return;
@@ -1393,7 +1425,7 @@ function useAgentChat(config) {
1393
1425
  },
1394
1426
  [applyResponse, client, conversationId, handleFailure, handleStreamEvent, sending, streamingEnabled]
1395
1427
  );
1396
- const resolveApproval = React6.useCallback(
1428
+ const resolveApproval = React7.useCallback(
1397
1429
  async (callId, approve) => {
1398
1430
  if (resolvingApprovalId) return;
1399
1431
  setResolvingApprovalId(callId);
@@ -1422,13 +1454,13 @@ function useAgentChat(config) {
1422
1454
  },
1423
1455
  [applyResponse, client, handleFailure, handleStreamEvent, resolvingApprovalId, streamingEnabled]
1424
1456
  );
1425
- const newChat = React6.useCallback(() => {
1457
+ const newChat = React7.useCallback(() => {
1426
1458
  setConversationId(null);
1427
1459
  setMessages([]);
1428
1460
  setPendingApprovals([]);
1429
1461
  setError(null);
1430
1462
  }, []);
1431
- const refreshConversations = React6.useCallback(async () => {
1463
+ const refreshConversations = React7.useCallback(async () => {
1432
1464
  try {
1433
1465
  const { conversations: list } = await client.listConversations();
1434
1466
  setConversations(list);
@@ -1436,7 +1468,7 @@ function useAgentChat(config) {
1436
1468
  handleFailure(err);
1437
1469
  }
1438
1470
  }, [client, handleFailure]);
1439
- const openConversation = React6.useCallback(
1471
+ const openConversation = React7.useCallback(
1440
1472
  async (id) => {
1441
1473
  setError(null);
1442
1474
  try {
@@ -1450,7 +1482,7 @@ function useAgentChat(config) {
1450
1482
  },
1451
1483
  [client, handleFailure]
1452
1484
  );
1453
- const deleteConversation = React6.useCallback(
1485
+ const deleteConversation = React7.useCallback(
1454
1486
  async (id) => {
1455
1487
  try {
1456
1488
  await client.deleteConversation(id);
@@ -1462,7 +1494,7 @@ function useAgentChat(config) {
1462
1494
  },
1463
1495
  [client, conversationId, handleFailure, newChat]
1464
1496
  );
1465
- const clearError = React6.useCallback(() => setError(null), []);
1497
+ const clearError = React7.useCallback(() => setError(null), []);
1466
1498
  return {
1467
1499
  agentInfo,
1468
1500
  clearError,
@@ -1497,11 +1529,11 @@ function readStored(clientId) {
1497
1529
  }
1498
1530
  }
1499
1531
  function useAlwaysApprove(clientId) {
1500
- const [approved, setApproved] = React6.useState(() => /* @__PURE__ */ new Set());
1501
- React6.useEffect(() => {
1532
+ const [approved, setApproved] = React7.useState(() => /* @__PURE__ */ new Set());
1533
+ React7.useEffect(() => {
1502
1534
  setApproved(readStored(clientId));
1503
1535
  }, [clientId]);
1504
- const persist = React6.useCallback(
1536
+ const persist = React7.useCallback(
1505
1537
  (next) => {
1506
1538
  setApproved(next);
1507
1539
  if (typeof window === "undefined") return;
@@ -1512,8 +1544,8 @@ function useAlwaysApprove(clientId) {
1512
1544
  },
1513
1545
  [clientId]
1514
1546
  );
1515
- const isAlwaysApproved = React6.useCallback((toolName) => approved.has(toolName), [approved]);
1516
- const setAlwaysApprove = React6.useCallback(
1547
+ const isAlwaysApproved = React7.useCallback((toolName) => approved.has(toolName), [approved]);
1548
+ const setAlwaysApprove = React7.useCallback(
1517
1549
  (toolName) => {
1518
1550
  if (approved.has(toolName)) return;
1519
1551
  const next = new Set(approved);
@@ -1522,7 +1554,7 @@ function useAlwaysApprove(clientId) {
1522
1554
  },
1523
1555
  [approved, persist]
1524
1556
  );
1525
- const clearAlwaysApprove = React6.useCallback(
1557
+ const clearAlwaysApprove = React7.useCallback(
1526
1558
  (toolName) => {
1527
1559
  if (!approved.has(toolName)) return;
1528
1560
  const next = new Set(approved);
@@ -1534,16 +1566,16 @@ function useAlwaysApprove(clientId) {
1534
1566
  return { clearAlwaysApprove, isAlwaysApproved, setAlwaysApprove };
1535
1567
  }
1536
1568
  function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
1537
- const [uncontrolledOpen, setUncontrolledOpen] = React6.useState(false);
1569
+ const [uncontrolledOpen, setUncontrolledOpen] = React7.useState(false);
1538
1570
  const open = controlledOpen ?? uncontrolledOpen;
1539
- const setOpen = React6.useCallback(
1571
+ const setOpen = React7.useCallback(
1540
1572
  (next) => {
1541
1573
  setUncontrolledOpen(next);
1542
1574
  onOpenChange?.(next);
1543
1575
  },
1544
1576
  [onOpenChange]
1545
1577
  );
1546
- const [agentMode, setAgentMode] = React6.useState(false);
1578
+ const [agentMode, setAgentMode] = React7.useState(false);
1547
1579
  const isDesktop = useMediaQuery("(min-width: 640px)", {
1548
1580
  defaultSSRValue: true,
1549
1581
  ssr: true
@@ -1553,14 +1585,14 @@ function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
1553
1585
  const alwaysApprove = useAlwaysApprove(config.clientId);
1554
1586
  const { pendingApprovals, resolveApproval, resolvingApprovalId } = chat;
1555
1587
  const { isAlwaysApproved } = alwaysApprove;
1556
- React6.useEffect(() => {
1588
+ React7.useEffect(() => {
1557
1589
  if (!open || resolvingApprovalId) return;
1558
1590
  const target = pendingApprovals.find((approval) => isAlwaysApproved(approval.tool_name));
1559
1591
  if (target) void resolveApproval(target.id, true);
1560
1592
  }, [open, pendingApprovals, resolvingApprovalId, isAlwaysApproved, resolveApproval]);
1561
- const firedWriteIds = React6.useRef(/* @__PURE__ */ new Set());
1593
+ const firedWriteIds = React7.useRef(/* @__PURE__ */ new Set());
1562
1594
  const { onWriteSuccess } = config;
1563
- React6.useEffect(() => {
1595
+ React7.useEffect(() => {
1564
1596
  if (!onWriteSuccess) return;
1565
1597
  for (const message of chat.messages) {
1566
1598
  if (message.role !== "tool" || !message.is_write || message.tool_status !== "success") continue;
@@ -1570,9 +1602,9 @@ function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
1570
1602
  onWriteSuccess({ arguments: args, toolName: message.tool_name ?? "" });
1571
1603
  }
1572
1604
  }, [chat.messages, onWriteSuccess]);
1573
- const lastNavigatedMessageId = React6.useRef(null);
1605
+ const lastNavigatedMessageId = React7.useRef(null);
1574
1606
  const { messages } = chat;
1575
- React6.useEffect(() => {
1607
+ React7.useEffect(() => {
1576
1608
  if (!open || fullscreen || !config.navigate || !config.pages?.length) return;
1577
1609
  const toolMessages = messages.filter((message) => message.role === "tool");
1578
1610
  const latest = toolMessages[toolMessages.length - 1];
@@ -1584,7 +1616,7 @@ function AgentWidget({ config, onOpenChange, open: controlledOpen }) {
1584
1616
  const path = mapping.buildRoute ? mapping.buildRoute(args) : mapping.route;
1585
1617
  if (path) config.navigate(path);
1586
1618
  }, [config, fullscreen, messages, open]);
1587
- const closePanel = React6.useCallback(() => {
1619
+ const closePanel = React7.useCallback(() => {
1588
1620
  setOpen(false);
1589
1621
  setAgentMode(false);
1590
1622
  }, [setOpen]);
@@ -1663,6 +1695,6 @@ function defineAgentConfig(config) {
1663
1695
  return config;
1664
1696
  }
1665
1697
 
1666
- export { AgentApiClient, AgentApiError, AgentComposer, AgentPanel, AgentWidget, DEFAULT_ACCEPT, DocumentCard, MessageItem, TaskChecklist, ThinkingIndicator, ToolActivityGroup, ToolApprovalCard, acceptAttribute, acceptedExtensions, defineAgentConfig, deriveDetails, fileUploadEnabled, formatBytes, groupMessages, humanizeToolName, resolveToolPresentation, useAgentChat, useAlwaysApprove, validateFile };
1698
+ export { AgentApiClient, AgentApiError, AgentComposer, AgentPanel, AgentWidget, ChatScroller, DEFAULT_ACCEPT, DocumentCard, MessageItem, TaskChecklist, ThinkingIndicator, ToolActivityGroup, ToolApprovalCard, acceptAttribute, acceptedExtensions, defineAgentConfig, deriveDetails, fileUploadEnabled, formatBytes, groupMessages, humanizeToolName, resolveToolPresentation, useAgentChat, useAlwaysApprove, validateFile };
1667
1699
  //# sourceMappingURL=index.js.map
1668
1700
  //# sourceMappingURL=index.js.map