@copilotz/chat-ui 0.1.0 → 0.1.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.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/components/chat/ChatUI.tsx
2
- import { useState as useState8, useEffect as useEffect7, useRef as useRef4, useCallback as useCallback4 } from "react";
2
+ import { useState as useState8, useEffect as useEffect10, useRef as useRef7, useCallback as useCallback4 } from "react";
3
3
 
4
4
  // src/config/chatConfig.ts
5
5
  var defaultChatConfig = {
@@ -9,6 +9,11 @@ var defaultChatConfig = {
9
9
  title: "Chat Assistant",
10
10
  subtitle: "How can I help you today?"
11
11
  },
12
+ agentSelector: {
13
+ enabled: false,
14
+ label: "Select agent",
15
+ hideIfSingle: true
16
+ },
12
17
  labels: {
13
18
  inputPlaceholder: "Type your message...",
14
19
  sendButton: "Send",
@@ -101,6 +106,10 @@ function mergeConfig(_baseConfig, userConfig) {
101
106
  ...defaultChatConfig.ui,
102
107
  ...userConfig.ui
103
108
  },
109
+ agentSelector: {
110
+ ...defaultChatConfig.agentSelector,
111
+ ...userConfig.agentSelector
112
+ },
104
113
  customComponent: userConfig.customComponent || defaultChatConfig.customComponent,
105
114
  headerActions: userConfig.headerActions || defaultChatConfig.headerActions
106
115
  };
@@ -228,7 +237,7 @@ var configUtils = {
228
237
  };
229
238
 
230
239
  // src/components/chat/Message.tsx
231
- import { useState, useRef } from "react";
240
+ import { useState, useRef, memo } from "react";
232
241
  import ReactMarkdown from "react-markdown";
233
242
  import remarkGfm from "remark-gfm";
234
243
  import rehypeHighlight from "rehype-highlight";
@@ -521,7 +530,7 @@ import {
521
530
  ChevronDown
522
531
  } from "lucide-react";
523
532
  import { Fragment, jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
524
- var ThinkingIndicator = ({ label = "Thinking..." }) => {
533
+ var ThinkingIndicator = memo(function ThinkingIndicator2({ label = "Thinking..." }) {
525
534
  return /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 py-2", children: [
526
535
  /* @__PURE__ */ jsxs2("div", { className: "flex gap-1", children: [
527
536
  /* @__PURE__ */ jsx7(
@@ -548,26 +557,30 @@ var ThinkingIndicator = ({ label = "Thinking..." }) => {
548
557
  ] }),
549
558
  /* @__PURE__ */ jsx7("span", { className: "text-sm text-muted-foreground animate-pulse", children: label })
550
559
  ] });
560
+ });
561
+ var markdownComponents = {
562
+ code: ({ node, className, children, ...props }) => {
563
+ const inline = props.inline;
564
+ const match = /language-(\w+)/.exec(className || "");
565
+ return !inline && match ? /* @__PURE__ */ jsx7("pre", { className: "relative", children: /* @__PURE__ */ jsx7("code", { className, ...props, children }) }) : /* @__PURE__ */ jsx7("code", { className: "bg-muted px-1 py-0.5 rounded text-sm", ...props, children });
566
+ }
551
567
  };
552
- var StreamingText = ({
568
+ var remarkPluginsDefault = [remarkGfm];
569
+ var rehypePluginsDefault = [rehypeHighlight];
570
+ var rehypePluginsEmpty = [];
571
+ var StreamingText = memo(function StreamingText2({
553
572
  content,
554
573
  isStreaming = false,
555
574
  thinkingLabel = "Thinking..."
556
- }) => {
575
+ }) {
557
576
  const hasContent = content.trim().length > 0;
558
577
  return /* @__PURE__ */ jsxs2("div", { className: "prose prose-sm max-w-none dark:prose-invert", children: [
559
578
  hasContent ? /* @__PURE__ */ jsx7(
560
579
  ReactMarkdown,
561
580
  {
562
- remarkPlugins: [remarkGfm],
563
- rehypePlugins: isStreaming ? [] : [rehypeHighlight],
564
- components: {
565
- code: ({ node, className, children, ...props }) => {
566
- const inline = props.inline;
567
- const match = /language-(\w+)/.exec(className || "");
568
- return !inline && match ? /* @__PURE__ */ jsx7("pre", { className: "relative", children: /* @__PURE__ */ jsx7("code", { className, ...props, children }) }) : /* @__PURE__ */ jsx7("code", { className: "bg-muted px-1 py-0.5 rounded text-sm", ...props, children });
569
- }
570
- },
581
+ remarkPlugins: remarkPluginsDefault,
582
+ rehypePlugins: isStreaming ? rehypePluginsEmpty : rehypePluginsDefault,
583
+ components: markdownComponents,
571
584
  children: content
572
585
  }
573
586
  ) : isStreaming ? (
@@ -576,8 +589,8 @@ var StreamingText = ({
576
589
  ) : null,
577
590
  isStreaming && hasContent && /* @__PURE__ */ jsx7("span", { className: "inline-block w-2 h-4 bg-primary animate-pulse ml-1" })
578
591
  ] });
579
- };
580
- var MediaRenderer = ({ attachment }) => {
592
+ });
593
+ var MediaRenderer = memo(function MediaRenderer2({ attachment }) {
581
594
  const [isPlaying, setIsPlaying] = useState(false);
582
595
  const audioRef = useRef(null);
583
596
  const videoRef = useRef(null);
@@ -651,8 +664,8 @@ var MediaRenderer = ({ attachment }) => {
651
664
  default:
652
665
  return null;
653
666
  }
654
- };
655
- var ToolCallsDisplay = ({ toolCalls, label }) => {
667
+ });
668
+ var ToolCallsDisplay = memo(function ToolCallsDisplay2({ toolCalls, label }) {
656
669
  const [expandedCall, setExpandedCall] = useState(null);
657
670
  const getStatusIcon = (status) => {
658
671
  switch (status) {
@@ -721,8 +734,48 @@ var ToolCallsDisplay = ({ toolCalls, label }) => {
721
734
  ] }, call.id);
722
735
  })
723
736
  ] });
737
+ });
738
+ var arePropsEqual = (prevProps, nextProps) => {
739
+ if (prevProps.message.id !== nextProps.message.id) return false;
740
+ if (prevProps.message.content !== nextProps.message.content) return false;
741
+ if (prevProps.message.isStreaming !== nextProps.message.isStreaming) return false;
742
+ if (prevProps.message.isComplete !== nextProps.message.isComplete) return false;
743
+ if (prevProps.message.isEdited !== nextProps.message.isEdited) return false;
744
+ if (prevProps.message.timestamp !== nextProps.message.timestamp) return false;
745
+ if (prevProps.message.toolCalls !== nextProps.message.toolCalls) {
746
+ const prevCalls = prevProps.message.toolCalls;
747
+ const nextCalls = nextProps.message.toolCalls;
748
+ if (!prevCalls || !nextCalls || prevCalls.length !== nextCalls.length) return false;
749
+ for (let i = 0; i < prevCalls.length; i++) {
750
+ if (prevCalls[i].id !== nextCalls[i].id || prevCalls[i].status !== nextCalls[i].status || prevCalls[i].result !== nextCalls[i].result) {
751
+ return false;
752
+ }
753
+ }
754
+ }
755
+ if (prevProps.message.attachments !== nextProps.message.attachments) {
756
+ const prevAtt = prevProps.message.attachments;
757
+ const nextAtt = nextProps.message.attachments;
758
+ if (!prevAtt || !nextAtt || prevAtt.length !== nextAtt.length) return false;
759
+ }
760
+ if (prevProps.isUser !== nextProps.isUser) return false;
761
+ if (prevProps.userAvatar !== nextProps.userAvatar) return false;
762
+ if (prevProps.userName !== nextProps.userName) return false;
763
+ if (prevProps.assistantName !== nextProps.assistantName) return false;
764
+ if (prevProps.showTimestamp !== nextProps.showTimestamp) return false;
765
+ if (prevProps.showAvatar !== nextProps.showAvatar) return false;
766
+ if (prevProps.enableCopy !== nextProps.enableCopy) return false;
767
+ if (prevProps.enableEdit !== nextProps.enableEdit) return false;
768
+ if (prevProps.enableRegenerate !== nextProps.enableRegenerate) return false;
769
+ if (prevProps.enableToolCallsDisplay !== nextProps.enableToolCallsDisplay) return false;
770
+ if (prevProps.compactMode !== nextProps.compactMode) return false;
771
+ if (prevProps.className !== nextProps.className) return false;
772
+ if (prevProps.toolUsedLabel !== nextProps.toolUsedLabel) return false;
773
+ if (prevProps.thinkingLabel !== nextProps.thinkingLabel) return false;
774
+ if (prevProps.isGrouped !== nextProps.isGrouped) return false;
775
+ if (prevProps.assistantAvatar !== nextProps.assistantAvatar) return false;
776
+ return true;
724
777
  };
725
- var Message = ({
778
+ var Message = memo(({
726
779
  message,
727
780
  isUser,
728
781
  userAvatar,
@@ -739,7 +792,8 @@ var Message = ({
739
792
  onAction,
740
793
  className = "",
741
794
  toolUsedLabel,
742
- thinkingLabel = "Thinking..."
795
+ thinkingLabel = "Thinking...",
796
+ isGrouped = false
743
797
  }) => {
744
798
  const [isEditing, setIsEditing] = useState(false);
745
799
  const [editContent, setEditContent] = useState(message.content);
@@ -789,7 +843,7 @@ var Message = ({
789
843
  onMouseEnter: () => setShowActions(true),
790
844
  onMouseLeave: () => setShowActions(false),
791
845
  children: [
792
- /* @__PURE__ */ jsxs2("div", { className: `flex gap-3 ${messageIsUser ? "flex-row-reverse" : "flex-row"} w-full mb-1`, children: [
846
+ !isGrouped && /* @__PURE__ */ jsxs2("div", { className: `flex gap-3 ${messageIsUser ? "flex-row-reverse" : "flex-row"} w-full mb-1`, children: [
793
847
  showAvatar && /* @__PURE__ */ jsx7("div", { className: `flex-shrink-0 ${compactMode ? "mt-1" : "mt-0"}`, children: /* @__PURE__ */ jsx7(Avatar, { className: compactMode ? "h-6 w-6" : "h-8 w-8", children: messageIsUser ? /* @__PURE__ */ jsxs2(Fragment, { children: [
794
848
  /* @__PURE__ */ jsx7(AvatarImage, { src: userAvatar, alt: userName }),
795
849
  /* @__PURE__ */ jsx7(AvatarFallback, { className: "bg-primary text-primary-foreground", children: userName.charAt(0).toUpperCase() })
@@ -800,7 +854,7 @@ var Message = ({
800
854
  message.isEdited && /* @__PURE__ */ jsx7(Badge, { variant: "outline", className: "text-xs", children: "editado" })
801
855
  ] })
802
856
  ] }),
803
- /* @__PURE__ */ jsx7("div", { className: `flex-1 min-w-0 ${messageIsUser ? "text-right" : "text-left"}`, children: /* @__PURE__ */ jsxs2("div", { className: `relative inline-flex flex-col ${messageIsUser ? "rounded-lg p-3 bg-primary text-primary-foreground ml-auto max-w-[85%]" : "max-w-[85%]"}`, children: [
857
+ /* @__PURE__ */ jsx7("div", { className: `flex-1 min-w-0 ${messageIsUser ? "text-right" : "text-left"} ${isGrouped && showAvatar && !messageIsUser ? compactMode ? "ml-9" : "ml-11" : ""} ${isGrouped && showAvatar && messageIsUser ? compactMode ? "mr-9" : "mr-11" : ""}`, children: /* @__PURE__ */ jsxs2("div", { className: `relative inline-flex flex-col ${messageIsUser ? "rounded-lg p-3 bg-primary text-primary-foreground ml-auto max-w-[85%]" : "max-w-[85%]"}`, children: [
804
858
  isEditing ? /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
805
859
  /* @__PURE__ */ jsx7(
806
860
  Textarea,
@@ -878,10 +932,10 @@ var Message = ({
878
932
  ]
879
933
  }
880
934
  ) });
881
- };
935
+ }, arePropsEqual);
882
936
 
883
937
  // src/components/chat/Sidebar.tsx
884
- import { useState as useState4, useRef as useRef2, useEffect as useEffect4 } from "react";
938
+ import { useState as useState4, useRef as useRef5, useEffect as useEffect7 } from "react";
885
939
 
886
940
  // src/components/ui/input.tsx
887
941
  import { jsx as jsx8 } from "react/jsx-runtime";
@@ -903,7 +957,7 @@ function Input({ className, type, ...props }) {
903
957
  }
904
958
 
905
959
  // src/components/ui/sidebar.tsx
906
- import * as React3 from "react";
960
+ import * as React4 from "react";
907
961
  import { Slot as Slot3 } from "@radix-ui/react-slot";
908
962
  import { cva as cva3 } from "class-variance-authority";
909
963
  import { PanelLeftIcon } from "lucide-react";
@@ -950,11 +1004,30 @@ function Separator({
950
1004
  }
951
1005
 
952
1006
  // src/components/ui/sheet.tsx
1007
+ import * as React3 from "react";
953
1008
  import * as SheetPrimitive from "@radix-ui/react-dialog";
954
1009
  import { XIcon } from "lucide-react";
955
1010
  import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
956
- function Sheet({ ...props }) {
957
- return /* @__PURE__ */ jsx10(SheetPrimitive.Root, { "data-slot": "sheet", ...props });
1011
+ function cleanupBodyStyles() {
1012
+ if (typeof document !== "undefined" && document.body.style.pointerEvents === "none") {
1013
+ document.body.style.pointerEvents = "";
1014
+ }
1015
+ }
1016
+ function Sheet({ open, onOpenChange, ...props }) {
1017
+ const prevOpenRef = React3.useRef(open);
1018
+ React3.useEffect(() => {
1019
+ if (prevOpenRef.current === true && open === false) {
1020
+ const timeout = setTimeout(cleanupBodyStyles, 350);
1021
+ return () => clearTimeout(timeout);
1022
+ }
1023
+ prevOpenRef.current = open;
1024
+ }, [open]);
1025
+ React3.useEffect(() => {
1026
+ return () => {
1027
+ cleanupBodyStyles();
1028
+ };
1029
+ }, []);
1030
+ return /* @__PURE__ */ jsx10(SheetPrimitive.Root, { "data-slot": "sheet", open, onOpenChange, ...props });
958
1031
  }
959
1032
  function SheetPortal({
960
1033
  ...props
@@ -970,7 +1043,10 @@ function SheetOverlay({
970
1043
  {
971
1044
  "data-slot": "sheet-overlay",
972
1045
  className: cn(
973
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
1046
+ "fixed inset-0 z-50 bg-black/50",
1047
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
1048
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1049
+ "data-[state=closed]:pointer-events-none",
974
1050
  className
975
1051
  ),
976
1052
  ...props
@@ -989,6 +1065,7 @@ function SheetContent({
989
1065
  SheetPrimitive.Content,
990
1066
  {
991
1067
  "data-slot": "sheet-content",
1068
+ "aria-describedby": void 0,
992
1069
  className: cn(
993
1070
  "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
994
1071
  side === "right" && "data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
@@ -1054,9 +1131,9 @@ var SIDEBAR_WIDTH = "16rem";
1054
1131
  var SIDEBAR_WIDTH_MOBILE = "18rem";
1055
1132
  var SIDEBAR_WIDTH_ICON = "3rem";
1056
1133
  var SIDEBAR_KEYBOARD_SHORTCUT = "b";
1057
- var SidebarContext = React3.createContext(null);
1134
+ var SidebarContext = React4.createContext(null);
1058
1135
  function useSidebar() {
1059
- const context = React3.useContext(SidebarContext);
1136
+ const context = React4.useContext(SidebarContext);
1060
1137
  if (!context) {
1061
1138
  throw new Error("useSidebar must be used within a SidebarProvider.");
1062
1139
  }
@@ -1072,10 +1149,10 @@ function SidebarProvider({
1072
1149
  ...props
1073
1150
  }) {
1074
1151
  const isMobile = useIsMobile();
1075
- const [openMobile, setOpenMobile] = React3.useState(false);
1076
- const [_open, _setOpen] = React3.useState(defaultOpen);
1152
+ const [openMobile, setOpenMobile] = React4.useState(false);
1153
+ const [_open, _setOpen] = React4.useState(defaultOpen);
1077
1154
  const open = openProp ?? _open;
1078
- const setOpen = React3.useCallback(
1155
+ const setOpen = React4.useCallback(
1079
1156
  (value) => {
1080
1157
  const openState = typeof value === "function" ? value(open) : value;
1081
1158
  if (setOpenProp) {
@@ -1087,10 +1164,10 @@ function SidebarProvider({
1087
1164
  },
1088
1165
  [setOpenProp, open]
1089
1166
  );
1090
- const toggleSidebar = React3.useCallback(() => {
1167
+ const toggleSidebar = React4.useCallback(() => {
1091
1168
  return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
1092
1169
  }, [isMobile, setOpen, setOpenMobile]);
1093
- React3.useEffect(() => {
1170
+ React4.useEffect(() => {
1094
1171
  const handleKeyDown = (event) => {
1095
1172
  if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
1096
1173
  event.preventDefault();
@@ -1101,7 +1178,7 @@ function SidebarProvider({
1101
1178
  return () => window.removeEventListener("keydown", handleKeyDown);
1102
1179
  }, [toggleSidebar]);
1103
1180
  const state = open ? "expanded" : "collapsed";
1104
- const contextValue = React3.useMemo(
1181
+ const contextValue = React4.useMemo(
1105
1182
  () => ({
1106
1183
  state,
1107
1184
  open,
@@ -1484,13 +1561,34 @@ function SidebarMenuAction({
1484
1561
  }
1485
1562
 
1486
1563
  // src/components/ui/dialog.tsx
1564
+ import * as React5 from "react";
1487
1565
  import * as DialogPrimitive from "@radix-ui/react-dialog";
1488
1566
  import { XIcon as XIcon2 } from "lucide-react";
1489
1567
  import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
1568
+ function cleanupBodyStyles2() {
1569
+ if (typeof document !== "undefined" && document.body.style.pointerEvents === "none") {
1570
+ document.body.style.pointerEvents = "";
1571
+ }
1572
+ }
1490
1573
  function Dialog({
1574
+ open,
1575
+ onOpenChange,
1491
1576
  ...props
1492
1577
  }) {
1493
- return /* @__PURE__ */ jsx12(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
1578
+ const prevOpenRef = React5.useRef(open);
1579
+ React5.useEffect(() => {
1580
+ if (prevOpenRef.current === true && open === false) {
1581
+ const timeout = setTimeout(cleanupBodyStyles2, 250);
1582
+ return () => clearTimeout(timeout);
1583
+ }
1584
+ prevOpenRef.current = open;
1585
+ }, [open]);
1586
+ React5.useEffect(() => {
1587
+ return () => {
1588
+ cleanupBodyStyles2();
1589
+ };
1590
+ }, []);
1591
+ return /* @__PURE__ */ jsx12(DialogPrimitive.Root, { "data-slot": "dialog", open, onOpenChange, ...props });
1494
1592
  }
1495
1593
  function DialogTrigger({
1496
1594
  ...props
@@ -1511,7 +1609,10 @@ function DialogOverlay({
1511
1609
  {
1512
1610
  "data-slot": "dialog-overlay",
1513
1611
  className: cn(
1514
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
1612
+ "fixed inset-0 z-50 bg-black/50",
1613
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
1614
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1615
+ "data-[state=closed]:pointer-events-none",
1515
1616
  className
1516
1617
  ),
1517
1618
  ...props
@@ -1530,6 +1631,7 @@ function DialogContent({
1530
1631
  DialogPrimitive.Content,
1531
1632
  {
1532
1633
  "data-slot": "dialog-content",
1634
+ "aria-describedby": void 0,
1533
1635
  className: cn(
1534
1636
  "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
1535
1637
  className
@@ -1604,12 +1706,33 @@ function DialogDescription({
1604
1706
  }
1605
1707
 
1606
1708
  // src/components/ui/alert-dialog.tsx
1709
+ import * as React6 from "react";
1607
1710
  import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
1608
1711
  import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
1712
+ function cleanupBodyStyles3() {
1713
+ if (typeof document !== "undefined" && document.body.style.pointerEvents === "none") {
1714
+ document.body.style.pointerEvents = "";
1715
+ }
1716
+ }
1609
1717
  function AlertDialog({
1718
+ open,
1719
+ onOpenChange,
1610
1720
  ...props
1611
1721
  }) {
1612
- return /* @__PURE__ */ jsx13(AlertDialogPrimitive.Root, { "data-slot": "alert-dialog", ...props });
1722
+ const prevOpenRef = React6.useRef(open);
1723
+ React6.useEffect(() => {
1724
+ if (prevOpenRef.current === true && open === false) {
1725
+ const timeout = setTimeout(cleanupBodyStyles3, 250);
1726
+ return () => clearTimeout(timeout);
1727
+ }
1728
+ prevOpenRef.current = open;
1729
+ }, [open]);
1730
+ React6.useEffect(() => {
1731
+ return () => {
1732
+ cleanupBodyStyles3();
1733
+ };
1734
+ }, []);
1735
+ return /* @__PURE__ */ jsx13(AlertDialogPrimitive.Root, { "data-slot": "alert-dialog", open, onOpenChange, ...props });
1613
1736
  }
1614
1737
  function AlertDialogPortal({
1615
1738
  ...props
@@ -1625,7 +1748,10 @@ function AlertDialogOverlay({
1625
1748
  {
1626
1749
  "data-slot": "alert-dialog-overlay",
1627
1750
  className: cn(
1628
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
1751
+ "fixed inset-0 z-50 bg-black/50",
1752
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
1753
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1754
+ "data-[state=closed]:pointer-events-none",
1629
1755
  className
1630
1756
  ),
1631
1757
  ...props
@@ -1829,7 +1955,8 @@ import {
1829
1955
  Trash2,
1830
1956
  Archive,
1831
1957
  Search,
1832
- Filter
1958
+ Filter,
1959
+ Bot
1833
1960
  } from "lucide-react";
1834
1961
 
1835
1962
  // src/components/chat/UserMenu.tsx
@@ -2044,9 +2171,9 @@ var Sidebar2 = ({
2044
2171
  const [deleteThreadId, setDeleteThreadId] = useState4(null);
2045
2172
  const [editingThreadId, setEditingThreadId] = useState4(null);
2046
2173
  const [editTitle, setEditTitle] = useState4("");
2047
- const inputRef = useRef2(null);
2174
+ const inputRef = useRef5(null);
2048
2175
  const { setOpen } = useSidebar();
2049
- useEffect4(() => {
2176
+ useEffect7(() => {
2050
2177
  if (editingThreadId && inputRef.current) {
2051
2178
  inputRef.current.focus();
2052
2179
  inputRef.current.select();
@@ -2099,6 +2226,13 @@ var Sidebar2 = ({
2099
2226
  };
2100
2227
  return /* @__PURE__ */ jsxs9(Sidebar, { collapsible: "icon", ...props, children: [
2101
2228
  /* @__PURE__ */ jsxs9(SidebarHeader, { children: [
2229
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-3 px-2 py-3", children: [
2230
+ /* @__PURE__ */ jsx16("div", { className: "flex items-center justify-center shrink-0", children: config.branding?.logo || /* @__PURE__ */ jsx16(Avatar, { className: "h-8 w-8", children: /* @__PURE__ */ jsx16(AvatarFallback, { className: "bg-primary text-primary-foreground", children: /* @__PURE__ */ jsx16(Bot, { className: "h-4 w-4" }) }) }) }),
2231
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-col min-w-0 group-data-[collapsible=icon]:hidden", children: [
2232
+ /* @__PURE__ */ jsx16("span", { className: "text-sm font-semibold truncate", children: config.branding?.title || "Chat" }),
2233
+ config.branding?.subtitle && /* @__PURE__ */ jsx16("span", { className: "text-xs text-muted-foreground truncate", children: config.branding.subtitle })
2234
+ ] })
2235
+ ] }),
2102
2236
  onCreateThread && /* @__PURE__ */ jsx16(
2103
2237
  CreateThreadDialog,
2104
2238
  {
@@ -2118,7 +2252,7 @@ var Sidebar2 = ({
2118
2252
  ) }) })
2119
2253
  }
2120
2254
  ),
2121
- /* @__PURE__ */ jsxs9("div", { className: "px-2 py-1 mt-6", children: [
2255
+ /* @__PURE__ */ jsxs9("div", { className: "px-2 py-1 mt-4", children: [
2122
2256
  /* @__PURE__ */ jsxs9("div", { className: "relative group-data-[collapsible=icon]:hidden", children: [
2123
2257
  /* @__PURE__ */ jsx16(Search, { className: "pointer-events-none absolute left-2 top-1/2 size-4 -translate-y-1/2 select-none opacity-50" }),
2124
2258
  /* @__PURE__ */ jsx16(
@@ -2233,7 +2367,7 @@ var Sidebar2 = ({
2233
2367
  }
2234
2368
  ) }),
2235
2369
  /* @__PURE__ */ jsx16(SidebarRail, {}),
2236
- /* @__PURE__ */ jsx16(AlertDialog, { open: !!deleteThreadId, onOpenChange: () => setDeleteThreadId(null), children: /* @__PURE__ */ jsxs9(AlertDialogContent, { children: [
2370
+ deleteThreadId && /* @__PURE__ */ jsx16(AlertDialog, { open: !!deleteThreadId, onOpenChange: () => setDeleteThreadId(null), children: /* @__PURE__ */ jsxs9(AlertDialogContent, { children: [
2237
2371
  /* @__PURE__ */ jsxs9(AlertDialogHeader, { children: [
2238
2372
  /* @__PURE__ */ jsx16(AlertDialogTitle, { children: config.labels?.deleteConfirmTitle || "Delete Conversation" }),
2239
2373
  /* @__PURE__ */ jsx16(AlertDialogDescription, { children: config.labels?.deleteConfirmDescription || "Are you sure you want to delete this conversation? This action cannot be undone." })
@@ -2254,9 +2388,9 @@ var Sidebar2 = ({
2254
2388
  };
2255
2389
 
2256
2390
  // src/components/chat/ChatHeader.tsx
2257
- import React5 from "react";
2391
+ import React8 from "react";
2258
2392
  import {
2259
- Bot,
2393
+ Bot as Bot2,
2260
2394
  MoreVertical,
2261
2395
  Download,
2262
2396
  Upload,
@@ -2264,7 +2398,9 @@ import {
2264
2398
  Plus as Plus2,
2265
2399
  Menu,
2266
2400
  Moon as Moon2,
2267
- Sun as Sun2
2401
+ Sun as Sun2,
2402
+ ChevronDown as ChevronDown2,
2403
+ Check as Check2
2268
2404
  } from "lucide-react";
2269
2405
  import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
2270
2406
  var ChatHeader = ({
@@ -2278,13 +2414,17 @@ var ChatHeader = ({
2278
2414
  onClearAll,
2279
2415
  showCustomComponentButton,
2280
2416
  isMobile,
2417
+ showAgentSelector = false,
2418
+ agentOptions = [],
2419
+ selectedAgentId = null,
2420
+ onSelectAgent,
2281
2421
  className = ""
2282
2422
  }) => {
2283
- const [isDarkMode, setIsDarkMode] = React5.useState(() => {
2423
+ const [isDarkMode, setIsDarkMode] = React8.useState(() => {
2284
2424
  if (typeof window === "undefined") return false;
2285
2425
  return document.documentElement.classList.contains("dark");
2286
2426
  });
2287
- React5.useEffect(() => {
2427
+ React8.useEffect(() => {
2288
2428
  const observer = new MutationObserver(() => {
2289
2429
  setIsDarkMode(document.documentElement.classList.contains("dark"));
2290
2430
  });
@@ -2328,22 +2468,64 @@ var ChatHeader = ({
2328
2468
  };
2329
2469
  input.click();
2330
2470
  };
2471
+ const selectedAgent = agentOptions.find((agent) => agent.id === selectedAgentId) || null;
2472
+ const agentPlaceholder = config.agentSelector?.label || "Select agent";
2331
2473
  return /* @__PURE__ */ jsx17(
2332
2474
  Card,
2333
2475
  {
2334
2476
  "data-chat-header": true,
2335
2477
  className: `py-0 border-b rounded-none relative z-10 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 ${className}`,
2336
2478
  style: isMobile ? { paddingTop: "env(safe-area-inset-top)" } : void 0,
2337
- children: /* @__PURE__ */ jsx17(CardHeader, { className: "p-2", children: /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between", children: [
2338
- /* @__PURE__ */ jsx17("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxs10(Tooltip, { children: [
2339
- /* @__PURE__ */ jsx17(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx17(SidebarTrigger, { className: "-ml-1" }) }),
2340
- /* @__PURE__ */ jsx17(TooltipContent, { children: config.labels?.sidebarToggle || "Toggle Sidebar" })
2341
- ] }) }),
2342
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-3 flex-1 justify-center", children: [
2343
- config.branding?.logo || /* @__PURE__ */ jsx17(Avatar, { className: "h-8 w-8", children: /* @__PURE__ */ jsx17(AvatarFallback, { children: /* @__PURE__ */ jsx17(Bot, { className: "h-4 w-4" }) }) }),
2344
- /* @__PURE__ */ jsx17("div", { className: "text-center hidden md:block", children: /* @__PURE__ */ jsx17(CardTitle, { className: "text-sm font-medium", children: config.branding?.title || "Chat Assistant" }) }),
2345
- /* @__PURE__ */ jsx17("div", { className: "md:hidden text-sm font-medium truncate max-w-[150px]", children: currentThreadTitle || config.branding?.title || "Chat" })
2479
+ children: /* @__PURE__ */ jsx17(CardHeader, { className: "p-2", children: /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between gap-2", children: [
2480
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1", children: [
2481
+ /* @__PURE__ */ jsxs10(Tooltip, { children: [
2482
+ /* @__PURE__ */ jsx17(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx17(SidebarTrigger, { className: "-ml-1" }) }),
2483
+ /* @__PURE__ */ jsx17(TooltipContent, { children: config.labels?.sidebarToggle || "Toggle Sidebar" })
2484
+ ] }),
2485
+ showAgentSelector && /* @__PURE__ */ jsxs10(DropdownMenu, { children: [
2486
+ /* @__PURE__ */ jsx17(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs10(
2487
+ Button,
2488
+ {
2489
+ variant: "ghost",
2490
+ className: "h-9 px-3 gap-1.5 font-medium text-base hover:bg-accent/50",
2491
+ children: [
2492
+ selectedAgent?.avatarUrl ? /* @__PURE__ */ jsxs10(Avatar, { className: "h-5 w-5", children: [
2493
+ /* @__PURE__ */ jsx17(AvatarImage, { src: selectedAgent.avatarUrl, alt: selectedAgent.name }),
2494
+ /* @__PURE__ */ jsx17(AvatarFallback, { className: "text-[10px]", children: selectedAgent.name.charAt(0).toUpperCase() })
2495
+ ] }) : null,
2496
+ /* @__PURE__ */ jsx17("span", { className: "max-w-[200px] truncate", children: selectedAgent?.name || agentPlaceholder }),
2497
+ /* @__PURE__ */ jsx17(ChevronDown2, { className: "h-4 w-4 opacity-50" })
2498
+ ]
2499
+ }
2500
+ ) }),
2501
+ /* @__PURE__ */ jsx17(DropdownMenuContent, { align: "start", className: "w-[280px]", children: agentOptions.map((agent) => {
2502
+ const isSelected = agent.id === selectedAgentId;
2503
+ return /* @__PURE__ */ jsxs10(
2504
+ DropdownMenuItem,
2505
+ {
2506
+ onClick: () => onSelectAgent?.(agent.id),
2507
+ className: "flex items-start gap-3 p-3 cursor-pointer",
2508
+ children: [
2509
+ agent.avatarUrl ? /* @__PURE__ */ jsxs10(Avatar, { className: "h-6 w-6 mt-0.5 shrink-0", children: [
2510
+ /* @__PURE__ */ jsx17(AvatarImage, { src: agent.avatarUrl, alt: agent.name }),
2511
+ /* @__PURE__ */ jsx17(AvatarFallback, { className: "text-[10px]", children: agent.name.charAt(0).toUpperCase() })
2512
+ ] }) : /* @__PURE__ */ jsx17("div", { className: "h-6 w-6 mt-0.5 shrink-0 flex items-center justify-center rounded-full bg-primary/10", children: /* @__PURE__ */ jsx17(Bot2, { className: "h-3.5 w-3.5 text-primary" }) }),
2513
+ /* @__PURE__ */ jsxs10("div", { className: "flex-1 min-w-0", children: [
2514
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
2515
+ /* @__PURE__ */ jsx17("span", { className: "font-medium text-sm", children: agent.name }),
2516
+ isSelected && /* @__PURE__ */ jsx17(Check2, { className: "h-4 w-4 text-primary shrink-0" })
2517
+ ] }),
2518
+ agent.description && /* @__PURE__ */ jsx17("p", { className: "text-xs text-muted-foreground mt-0.5 line-clamp-2", children: agent.description })
2519
+ ] })
2520
+ ]
2521
+ },
2522
+ agent.id
2523
+ );
2524
+ }) })
2525
+ ] }),
2526
+ !showAgentSelector && isMobile && /* @__PURE__ */ jsx17("span", { className: "text-sm font-medium truncate max-w-[150px] ml-2", children: currentThreadTitle || config.branding?.title || "Chat" })
2346
2527
  ] }),
2528
+ /* @__PURE__ */ jsx17("div", { className: "flex-1" }),
2347
2529
  /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1", children: [
2348
2530
  showCustomComponentButton && config.customComponent && /* @__PURE__ */ jsxs10(Tooltip, { children: [
2349
2531
  /* @__PURE__ */ jsx17(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx17(
@@ -2408,10 +2590,10 @@ var ChatHeader = ({
2408
2590
  };
2409
2591
 
2410
2592
  // src/components/chat/ChatInput.tsx
2411
- import { useState as useState6, useRef as useRef3, useCallback as useCallback3, useEffect as useEffect6 } from "react";
2593
+ import { useState as useState6, useRef as useRef6, useCallback as useCallback3, useEffect as useEffect9, memo as memo2 } from "react";
2412
2594
 
2413
2595
  // src/components/chat/UserContext.tsx
2414
- import { createContext as createContext2, useCallback as useCallback2, useContext as useContext2, useEffect as useEffect5, useMemo as useMemo2, useState as useState5 } from "react";
2596
+ import { createContext as createContext2, useCallback as useCallback2, useContext as useContext2, useEffect as useEffect8, useMemo as useMemo2, useState as useState5 } from "react";
2415
2597
  import { jsx as jsx18 } from "react/jsx-runtime";
2416
2598
  var Ctx = createContext2(void 0);
2417
2599
  var ChatUserContextProvider = ({ children, initial }) => {
@@ -2419,7 +2601,7 @@ var ChatUserContextProvider = ({ children, initial }) => {
2419
2601
  updatedAt: Date.now(),
2420
2602
  ...initial ?? {}
2421
2603
  }));
2422
- useEffect5(() => {
2604
+ useEffect8(() => {
2423
2605
  if (!initial) return;
2424
2606
  setCtx((prev) => ({
2425
2607
  ...prev,
@@ -2490,7 +2672,7 @@ import {
2490
2672
  Loader2
2491
2673
  } from "lucide-react";
2492
2674
  import { Fragment as Fragment4, jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
2493
- var FileUploadItem = ({ file, progress, onCancel }) => {
2675
+ var FileUploadItem = memo2(function FileUploadItem2({ file, progress, onCancel }) {
2494
2676
  const guessTypeFromName = (name) => {
2495
2677
  const ext = (name || "").split(".").pop()?.toLowerCase();
2496
2678
  switch (ext) {
@@ -2548,10 +2730,10 @@ var FileUploadItem = ({ file, progress, onCancel }) => {
2548
2730
  }
2549
2731
  )
2550
2732
  ] }) }) });
2551
- };
2552
- var AttachmentPreview = ({ attachment, onRemove }) => {
2733
+ });
2734
+ var AttachmentPreview = memo2(function AttachmentPreview2({ attachment, onRemove }) {
2553
2735
  const [isPlaying, setIsPlaying] = useState6(false);
2554
- const audioRef = useRef3(null);
2736
+ const audioRef = useRef6(null);
2555
2737
  const handlePlayPause = () => {
2556
2738
  if (audioRef.current) {
2557
2739
  if (isPlaying) {
@@ -2649,8 +2831,8 @@ var AttachmentPreview = ({ attachment, onRemove }) => {
2649
2831
  ] }),
2650
2832
  attachment.fileName && attachment.kind !== "audio" && /* @__PURE__ */ jsx20("div", { className: "absolute bottom-0 left-0 right-0 bg-black/70 text-white text-xs p-1 rounded-b", children: /* @__PURE__ */ jsx20("p", { className: "truncate", children: attachment.fileName }) })
2651
2833
  ] }) });
2652
- };
2653
- var AudioRecorder = ({ isRecording, onStartRecording, onStopRecording, onCancel, recordingDuration, config }) => {
2834
+ });
2835
+ var AudioRecorder = memo2(function AudioRecorder2({ isRecording, onStartRecording, onStopRecording, onCancel, recordingDuration, config }) {
2654
2836
  const formatTime = (seconds) => {
2655
2837
  const mins = Math.floor(seconds / 60);
2656
2838
  const secs = seconds % 60;
@@ -2704,8 +2886,8 @@ var AudioRecorder = ({ isRecording, onStartRecording, onStopRecording, onCancel,
2704
2886
  )
2705
2887
  ] })
2706
2888
  ] }) }) });
2707
- };
2708
- var ChatInput = ({
2889
+ });
2890
+ var ChatInput = memo2(function ChatInput2({
2709
2891
  value,
2710
2892
  onChange,
2711
2893
  onSubmit,
@@ -2723,18 +2905,18 @@ var ChatInput = ({
2723
2905
  acceptedFileTypes = ["image/*", "video/*", "audio/*"],
2724
2906
  className = "",
2725
2907
  config
2726
- }) => {
2908
+ }) {
2727
2909
  const [isRecording, setIsRecording] = useState6(false);
2728
2910
  const { setContext } = useChatUserContext();
2729
2911
  const [recordingDuration, setRecordingDuration] = useState6(0);
2730
2912
  const [uploadProgress, setUploadProgress] = useState6(/* @__PURE__ */ new Map());
2731
- const textareaRef = useRef3(null);
2732
- const fileInputRef = useRef3(null);
2733
- const mediaRecorderRef = useRef3(null);
2734
- const recordingStartTime = useRef3(0);
2735
- const recordingInterval = useRef3(null);
2736
- const mediaStreamRef = useRef3(null);
2737
- useEffect6(() => {
2913
+ const textareaRef = useRef6(null);
2914
+ const fileInputRef = useRef6(null);
2915
+ const mediaRecorderRef = useRef6(null);
2916
+ const recordingStartTime = useRef6(0);
2917
+ const recordingInterval = useRef6(null);
2918
+ const mediaStreamRef = useRef6(null);
2919
+ useEffect9(() => {
2738
2920
  return () => {
2739
2921
  if (mediaStreamRef.current) {
2740
2922
  mediaStreamRef.current.getTracks().forEach((track) => track.stop());
@@ -3065,16 +3247,16 @@ var ChatInput = ({
3065
3247
  ] })
3066
3248
  ] })
3067
3249
  ] }) }) });
3068
- };
3250
+ });
3069
3251
 
3070
3252
  // src/components/chat/UserProfile.tsx
3071
3253
  import { useState as useState7 } from "react";
3072
3254
 
3073
3255
  // src/components/ui/scroll-area.tsx
3074
- import * as React8 from "react";
3256
+ import * as React11 from "react";
3075
3257
  import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
3076
3258
  import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
3077
- var ScrollArea = React8.forwardRef(({ className, children, viewportClassName, onScroll, onScrollCapture, ...props }, ref) => {
3259
+ var ScrollArea = React11.forwardRef(({ className, children, viewportClassName, onScroll, onScrollCapture, ...props }, ref) => {
3078
3260
  return /* @__PURE__ */ jsxs12(
3079
3261
  ScrollAreaPrimitive.Root,
3080
3262
  {
@@ -3154,9 +3336,9 @@ import {
3154
3336
  Lightbulb,
3155
3337
  Info,
3156
3338
  Heart,
3157
- Bot as Bot2,
3339
+ Bot as Bot3,
3158
3340
  Pencil,
3159
- Check as Check2,
3341
+ Check as Check3,
3160
3342
  X as X3
3161
3343
  } from "lucide-react";
3162
3344
  import { Fragment as Fragment5, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
@@ -3423,7 +3605,7 @@ var UserProfile = ({
3423
3605
  {
3424
3606
  className: "flex items-start gap-3 p-3 rounded-lg bg-muted/50 group",
3425
3607
  children: [
3426
- /* @__PURE__ */ jsx22("div", { className: "mt-0.5 shrink-0", children: memory.source === "agent" ? /* @__PURE__ */ jsx22(Bot2, { className: "h-4 w-4 text-primary" }) : getMemoryCategoryIcon(memory.category) }),
3608
+ /* @__PURE__ */ jsx22("div", { className: "mt-0.5 shrink-0", children: memory.source === "agent" ? /* @__PURE__ */ jsx22(Bot3, { className: "h-4 w-4 text-primary" }) : getMemoryCategoryIcon(memory.category) }),
3427
3609
  /* @__PURE__ */ jsxs13("div", { className: "flex-1 min-w-0", children: [
3428
3610
  /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 mb-0.5", children: [
3429
3611
  /* @__PURE__ */ jsx22("span", { className: "text-xs text-muted-foreground", children: getMemoryCategoryLabel(memory.category) }),
@@ -3470,7 +3652,7 @@ var UserProfile = ({
3470
3652
  onClick: handleSaveEdit,
3471
3653
  disabled: !editingMemoryContent.trim(),
3472
3654
  children: [
3473
- /* @__PURE__ */ jsx22(Check2, { className: "h-3.5 w-3.5 mr-1" }),
3655
+ /* @__PURE__ */ jsx22(Check3, { className: "h-3.5 w-3.5 mr-1" }),
3474
3656
  "Salvar"
3475
3657
  ]
3476
3658
  }
@@ -3533,7 +3715,7 @@ var UserProfile = ({
3533
3715
  };
3534
3716
 
3535
3717
  // src/components/chat/ChatUI.tsx
3536
- import { Sparkles } from "lucide-react";
3718
+ import { Sparkles, ArrowRight, MessageSquare, Lightbulb as Lightbulb2, Zap, HelpCircle } from "lucide-react";
3537
3719
  import { jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
3538
3720
  var ChatUI = ({
3539
3721
  messages = [],
@@ -3546,10 +3728,16 @@ var ChatUI = ({
3546
3728
  user,
3547
3729
  assistant,
3548
3730
  suggestions = [],
3731
+ messageSuggestions = {},
3732
+ agentOptions = [],
3733
+ selectedAgentId = null,
3734
+ onSelectAgent,
3549
3735
  className = "",
3550
3736
  onAddMemory,
3551
3737
  onUpdateMemory,
3552
- onDeleteMemory
3738
+ onDeleteMemory,
3739
+ initialInput,
3740
+ onInitialInputConsumed
3553
3741
  }) => {
3554
3742
  const config = mergeConfig(defaultChatConfig, userConfig);
3555
3743
  const [isMobile, setIsMobile] = useState8(false);
@@ -3567,9 +3755,9 @@ var ChatUI = ({
3567
3755
  }
3568
3756
  return false;
3569
3757
  };
3758
+ const [inputValue, setInputValue] = useState8("");
3759
+ const [attachments, setAttachments] = useState8([]);
3570
3760
  const [state, setState] = useState8({
3571
- input: "",
3572
- attachments: [],
3573
3761
  isRecording: false,
3574
3762
  selectedThreadId: currentThreadId,
3575
3763
  isAtBottom: true,
@@ -3581,23 +3769,48 @@ var ChatUI = ({
3581
3769
  isSidebarCollapsed: false
3582
3770
  // No longer used for main sidebar
3583
3771
  });
3584
- useEffect7(() => {
3772
+ useEffect10(() => {
3585
3773
  if (currentThreadId !== state.selectedThreadId) {
3586
3774
  setState((prev) => ({ ...prev, selectedThreadId: currentThreadId }));
3587
3775
  }
3588
3776
  }, [currentThreadId]);
3589
- const messagesEndRef = useRef4(null);
3590
- const scrollAreaRef = useRef4(null);
3777
+ const initialInputApplied = useRef7(false);
3778
+ const initialInputConsumedRef = useRef7(false);
3779
+ useEffect10(() => {
3780
+ if (initialInput && !initialInputApplied.current) {
3781
+ setInputValue(initialInput);
3782
+ initialInputApplied.current = true;
3783
+ }
3784
+ }, [initialInput]);
3785
+ const messagesEndRef = useRef7(null);
3786
+ const scrollAreaRef = useRef7(null);
3787
+ const stateRef = useRef7(state);
3788
+ const inputValueRef = useRef7(inputValue);
3789
+ const attachmentsRef = useRef7(attachments);
3790
+ useEffect10(() => {
3791
+ stateRef.current = state;
3792
+ }, [state]);
3793
+ useEffect10(() => {
3794
+ inputValueRef.current = inputValue;
3795
+ }, [inputValue]);
3796
+ useEffect10(() => {
3797
+ attachmentsRef.current = attachments;
3798
+ }, [attachments]);
3591
3799
  const [isCustomMounted, setIsCustomMounted] = useState8(false);
3592
3800
  const [isCustomVisible, setIsCustomVisible] = useState8(false);
3593
3801
  const createStateCallback = useCallback4(
3594
3802
  (setter) => ({
3595
3803
  setState: (newState) => setter?.(newState),
3596
- getState: () => state
3804
+ getState: () => ({
3805
+ ...stateRef.current,
3806
+ input: inputValueRef.current,
3807
+ attachments: attachmentsRef.current
3808
+ })
3597
3809
  }),
3598
- [state]
3810
+ []
3811
+ // No dependencies - uses refs for latest state
3599
3812
  );
3600
- useEffect7(() => {
3813
+ useEffect10(() => {
3601
3814
  const checkMobile = () => {
3602
3815
  setIsMobile(globalThis.innerWidth < 1024);
3603
3816
  };
@@ -3605,7 +3818,7 @@ var ChatUI = ({
3605
3818
  globalThis.addEventListener("resize", checkMobile);
3606
3819
  return () => globalThis.removeEventListener("resize", checkMobile);
3607
3820
  }, []);
3608
- useEffect7(() => {
3821
+ useEffect10(() => {
3609
3822
  if (!isMobile || !config.customComponent?.component) return;
3610
3823
  if (state.showSidebar) {
3611
3824
  setIsCustomMounted(true);
@@ -3616,7 +3829,7 @@ var ChatUI = ({
3616
3829
  return () => clearTimeout(t);
3617
3830
  }
3618
3831
  }, [state.showSidebar, isMobile, config.customComponent]);
3619
- useEffect7(() => {
3832
+ useEffect10(() => {
3620
3833
  if (!state.isAtBottom) return;
3621
3834
  const viewport = scrollAreaRef.current;
3622
3835
  if (!viewport) return;
@@ -3632,15 +3845,16 @@ var ChatUI = ({
3632
3845
  const isAtBottom = scrollHeight - scrollTop - clientHeight < 50;
3633
3846
  setState((prev) => ({ ...prev, isAtBottom }));
3634
3847
  }, []);
3635
- const handleSendMessage = useCallback4((content, attachments = []) => {
3636
- if (!content.trim() && attachments.length === 0) return;
3637
- callbacks.onSendMessage?.(content, attachments, createStateCallback());
3638
- setState((prev) => ({
3639
- ...prev,
3640
- input: "",
3641
- attachments: []
3642
- }));
3643
- }, [callbacks, createStateCallback]);
3848
+ const handleSendMessage = useCallback4((content, messageAttachments = []) => {
3849
+ if (!content.trim() && messageAttachments.length === 0) return;
3850
+ callbacks.onSendMessage?.(content, messageAttachments, createStateCallback());
3851
+ if (initialInputApplied.current && !initialInputConsumedRef.current) {
3852
+ initialInputConsumedRef.current = true;
3853
+ onInitialInputConsumed?.();
3854
+ }
3855
+ setInputValue("");
3856
+ setAttachments([]);
3857
+ }, [callbacks, createStateCallback, onInitialInputConsumed]);
3644
3858
  const handleMessageAction = useCallback4((event) => {
3645
3859
  const { action, messageId, content } = event;
3646
3860
  switch (action) {
@@ -3661,7 +3875,7 @@ var ChatUI = ({
3661
3875
  }
3662
3876
  }, [callbacks, createStateCallback]);
3663
3877
  const handleCreateThread = useCallback4((title) => {
3664
- callbacks.onCreateThread?.(title, createStateCallback(setState));
3878
+ callbacks.onCreateThread?.(title, createStateCallback());
3665
3879
  }, [callbacks, createStateCallback]);
3666
3880
  const handleSelectThread = useCallback4((threadId) => {
3667
3881
  callbacks.onSelectThread?.(threadId, createStateCallback());
@@ -3686,23 +3900,54 @@ var ChatUI = ({
3686
3900
  }
3687
3901
  return component;
3688
3902
  }, [config?.customComponent?.component, closeSidebar, isMobile]);
3903
+ const SuggestionIconComponents = [MessageSquare, Lightbulb2, Zap, HelpCircle];
3689
3904
  const renderSuggestions = () => {
3690
3905
  if (messages.length > 0 || !suggestions.length) return null;
3691
- return /* @__PURE__ */ jsxs14("div", { className: "text-center py-8", children: [
3692
- /* @__PURE__ */ jsx23("div", { className: "inline-flex items-center justify-center w-16 h-16 rounded-full bg-primary/10 mb-4", children: /* @__PURE__ */ jsx23(Sparkles, { className: "w-8 h-8 text-primary" }) }),
3693
- /* @__PURE__ */ jsx23("h3", { className: "text-lg font-semibold mb-2", children: config.branding.title }),
3694
- /* @__PURE__ */ jsx23("p", { className: "text-muted-foreground mb-6", children: config.branding.subtitle }),
3695
- /* @__PURE__ */ jsx23("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3 max-w-2xl mx-auto", children: suggestions.map((suggestion, index) => /* @__PURE__ */ jsx23(
3696
- Card,
3906
+ return /* @__PURE__ */ jsxs14("div", { className: "flex flex-col items-center justify-center min-h-[60vh] py-8 px-4", children: [
3907
+ /* @__PURE__ */ jsxs14("div", { className: "text-center mb-8", children: [
3908
+ /* @__PURE__ */ jsx23("div", { className: "inline-flex items-center justify-center w-14 h-14 rounded-2xl bg-gradient-to-br from-primary/20 to-primary/5 mb-4 shadow-sm", children: /* @__PURE__ */ jsx23(Sparkles, { className: "w-7 h-7 text-primary" }) }),
3909
+ /* @__PURE__ */ jsx23("h2", { className: "text-xl font-semibold mb-2", children: config.branding.title }),
3910
+ /* @__PURE__ */ jsx23("p", { className: "text-muted-foreground text-sm max-w-md", children: config.branding.subtitle })
3911
+ ] }),
3912
+ /* @__PURE__ */ jsx23("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 w-full max-w-2xl", children: suggestions.map((suggestion, index) => /* @__PURE__ */ jsxs14(
3913
+ "button",
3697
3914
  {
3698
- className: "cursor-pointer hover:bg-muted/50 transition-colors",
3915
+ type: "button",
3699
3916
  onClick: () => handleSendMessage(suggestion),
3700
- children: /* @__PURE__ */ jsx23(CardContent, { className: "p-4 text-left", children: /* @__PURE__ */ jsx23("p", { className: "text-sm", children: suggestion }) })
3917
+ className: "group relative flex items-start gap-3 p-4 text-left rounded-xl border bg-card hover:bg-accent/50 hover:border-accent transition-all duration-200 hover:shadow-sm",
3918
+ children: [
3919
+ (() => {
3920
+ const IconComponent = SuggestionIconComponents[index % SuggestionIconComponents.length];
3921
+ return /* @__PURE__ */ jsx23("div", { className: "flex items-center justify-center w-8 h-8 rounded-lg bg-primary/10 text-primary shrink-0 group-hover:bg-primary/15 transition-colors", children: /* @__PURE__ */ jsx23(IconComponent, { className: "h-4 w-4" }) });
3922
+ })(),
3923
+ /* @__PURE__ */ jsx23("div", { className: "flex-1 min-w-0 pr-6", children: /* @__PURE__ */ jsx23("p", { className: "text-sm font-medium leading-snug line-clamp-2", children: suggestion }) }),
3924
+ /* @__PURE__ */ jsx23(ArrowRight, { className: "absolute right-4 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" })
3925
+ ]
3701
3926
  },
3702
3927
  index
3703
3928
  )) })
3704
3929
  ] });
3705
3930
  };
3931
+ const renderInlineSuggestions = (messageId) => {
3932
+ const items = messageSuggestions?.[messageId];
3933
+ if (!items || items.length === 0) return null;
3934
+ return /* @__PURE__ */ jsx23("div", { className: "flex flex-wrap gap-2 mt-2 ml-11", children: items.map((suggestion, index) => /* @__PURE__ */ jsxs14(
3935
+ "button",
3936
+ {
3937
+ type: "button",
3938
+ onClick: () => handleSendMessage(suggestion),
3939
+ className: "group inline-flex items-center gap-1.5 px-3 py-1.5 text-sm rounded-full border border-border bg-background hover:bg-accent hover:border-accent-foreground/20 transition-all duration-150 text-foreground/80 hover:text-foreground",
3940
+ children: [
3941
+ /* @__PURE__ */ jsx23(Sparkles, { className: "h-3 w-3 text-primary opacity-70 group-hover:opacity-100" }),
3942
+ /* @__PURE__ */ jsx23("span", { className: "max-w-[200px] truncate", children: suggestion })
3943
+ ]
3944
+ },
3945
+ `${messageId}-suggestion-${index}`
3946
+ )) });
3947
+ };
3948
+ const shouldShowAgentSelector = Boolean(
3949
+ config.agentSelector?.enabled && onSelectAgent && agentOptions.length > 0 && (!config.agentSelector?.hideIfSingle || agentOptions.length > 1)
3950
+ );
3706
3951
  return /* @__PURE__ */ jsx23(TooltipProvider, { children: /* @__PURE__ */ jsx23(SidebarProvider, { defaultOpen: true, children: /* @__PURE__ */ jsxs14("div", { className: `flex h-[100svh] md:h-screen bg-background w-full overflow-hidden ${className}`, children: [
3707
3952
  /* @__PURE__ */ jsx23(
3708
3953
  Sidebar2,
@@ -3743,7 +3988,11 @@ var ChatUI = ({
3743
3988
  isMobile,
3744
3989
  onCustomComponentToggle: () => setState((prev) => ({ ...prev, showSidebar: !prev.showSidebar })),
3745
3990
  onNewThread: handleCreateThread,
3746
- showCustomComponentButton: !!config?.customComponent?.component
3991
+ showCustomComponentButton: !!config?.customComponent?.component,
3992
+ showAgentSelector: shouldShowAgentSelector,
3993
+ agentOptions,
3994
+ selectedAgentId,
3995
+ onSelectAgent
3747
3996
  }
3748
3997
  ),
3749
3998
  /* @__PURE__ */ jsxs14("div", { className: "flex flex-1 flex-row min-h-0 overflow-hidden", children: [
@@ -3757,27 +4006,34 @@ var ChatUI = ({
3757
4006
  onScrollCapture: handleScroll,
3758
4007
  children: /* @__PURE__ */ jsxs14("div", { className: "max-w-4xl mx-auto space-y-4 pb-4", children: [
3759
4008
  renderSuggestions(),
3760
- messages.map((message) => /* @__PURE__ */ jsx23(
3761
- Message,
3762
- {
3763
- message,
3764
- userAvatar: user?.avatar,
3765
- userName: user?.name,
3766
- assistantAvatar: assistant?.avatar,
3767
- assistantName: assistant?.name,
3768
- showTimestamp: config.ui.showTimestamps,
3769
- showAvatar: config.ui.showAvatars,
3770
- enableCopy: config.features.enableMessageCopy,
3771
- enableEdit: config.features.enableMessageEditing,
3772
- enableRegenerate: config.features.enableRegeneration,
3773
- enableToolCallsDisplay: config.features.enableToolCallsDisplay,
3774
- compactMode: config.ui.compactMode,
3775
- onAction: handleMessageAction,
3776
- toolUsedLabel: config.labels.toolUsed,
3777
- thinkingLabel: config.labels.thinking
3778
- },
3779
- message.id
3780
- )),
4009
+ messages.map((message, index) => {
4010
+ const prevMessage = index > 0 ? messages[index - 1] : null;
4011
+ const isGrouped = prevMessage !== null && prevMessage.role === message.role;
4012
+ return /* @__PURE__ */ jsxs14("div", { className: isGrouped ? "space-y-1 -mt-2" : "space-y-2", children: [
4013
+ /* @__PURE__ */ jsx23(
4014
+ Message,
4015
+ {
4016
+ message,
4017
+ userAvatar: user?.avatar,
4018
+ userName: user?.name,
4019
+ assistantAvatar: assistant?.avatar,
4020
+ assistantName: assistant?.name,
4021
+ showTimestamp: config.ui.showTimestamps,
4022
+ showAvatar: config.ui.showAvatars,
4023
+ enableCopy: config.features.enableMessageCopy,
4024
+ enableEdit: config.features.enableMessageEditing,
4025
+ enableRegenerate: config.features.enableRegeneration,
4026
+ enableToolCallsDisplay: config.features.enableToolCallsDisplay,
4027
+ compactMode: config.ui.compactMode,
4028
+ onAction: handleMessageAction,
4029
+ toolUsedLabel: config.labels.toolUsed,
4030
+ thinkingLabel: config.labels.thinking,
4031
+ isGrouped
4032
+ }
4033
+ ),
4034
+ message.role === "assistant" && renderInlineSuggestions(message.id)
4035
+ ] }, message.id);
4036
+ }),
3781
4037
  /* @__PURE__ */ jsx23("div", { ref: messagesEndRef })
3782
4038
  ] })
3783
4039
  }
@@ -3785,11 +4041,17 @@ var ChatUI = ({
3785
4041
  /* @__PURE__ */ jsx23("div", { className: "bg-background pb-[env(safe-area-inset-bottom)]", children: /* @__PURE__ */ jsx23(
3786
4042
  ChatInput,
3787
4043
  {
3788
- value: state.input,
3789
- onChange: (value) => setState((prev) => ({ ...prev, input: value })),
4044
+ value: inputValue,
4045
+ onChange: (value) => {
4046
+ setInputValue(value);
4047
+ if (initialInputApplied.current && !initialInputConsumedRef.current) {
4048
+ initialInputConsumedRef.current = true;
4049
+ onInitialInputConsumed?.();
4050
+ }
4051
+ },
3790
4052
  onSubmit: handleSendMessage,
3791
- attachments: state.attachments,
3792
- onAttachmentsChange: (attachments) => setState((prev) => ({ ...prev, attachments })),
4053
+ attachments,
4054
+ onAttachmentsChange: setAttachments,
3793
4055
  placeholder: config.labels.inputPlaceholder,
3794
4056
  disabled: false,
3795
4057
  isGenerating,
@@ -3829,7 +4091,7 @@ var ChatUI = ({
3829
4091
  }
3830
4092
  )
3831
4093
  ] }),
3832
- /* @__PURE__ */ jsx23(
4094
+ isUserProfileOpen && /* @__PURE__ */ jsx23(
3833
4095
  UserProfile,
3834
4096
  {
3835
4097
  isOpen: isUserProfileOpen,
@@ -3852,10 +4114,10 @@ var ChatUI = ({
3852
4114
  };
3853
4115
 
3854
4116
  // src/components/chat/ThreadManager.tsx
3855
- import { useState as useState9, useRef as useRef5, useEffect as useEffect8 } from "react";
4117
+ import { useState as useState9, useRef as useRef8, useEffect as useEffect11 } from "react";
3856
4118
  import {
3857
4119
  Plus as Plus4,
3858
- MessageSquare,
4120
+ MessageSquare as MessageSquare2,
3859
4121
  MoreVertical as MoreVertical2,
3860
4122
  Edit2 as Edit22,
3861
4123
  Trash2 as Trash24,
@@ -3865,14 +4127,14 @@ import {
3865
4127
  Calendar as Calendar2,
3866
4128
  Hash,
3867
4129
  X as X4,
3868
- Check as Check3
4130
+ Check as Check4
3869
4131
  } from "lucide-react";
3870
4132
  import { Fragment as Fragment6, jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
3871
4133
  var ThreadItem = ({ thread, isActive, config, onSelect, onRename, onDelete, onArchive }) => {
3872
4134
  const [isEditing, setIsEditing] = useState9(false);
3873
4135
  const [editTitle, setEditTitle] = useState9(thread.title);
3874
- const inputRef = useRef5(null);
3875
- useEffect8(() => {
4136
+ const inputRef = useRef8(null);
4137
+ useEffect11(() => {
3876
4138
  if (isEditing && inputRef.current) {
3877
4139
  inputRef.current.focus();
3878
4140
  inputRef.current.select();
@@ -3910,7 +4172,7 @@ var ThreadItem = ({ thread, isActive, config, onSelect, onRename, onDelete, onAr
3910
4172
  placeholder: config?.labels?.threadNamePlaceholder || "Conversation name"
3911
4173
  }
3912
4174
  ),
3913
- /* @__PURE__ */ jsx24(Button, { size: "sm", variant: "ghost", onClick: handleSaveEdit, children: /* @__PURE__ */ jsx24(Check3, { className: "h-3 w-3" }) }),
4175
+ /* @__PURE__ */ jsx24(Button, { size: "sm", variant: "ghost", onClick: handleSaveEdit, children: /* @__PURE__ */ jsx24(Check4, { className: "h-3 w-3" }) }),
3914
4176
  /* @__PURE__ */ jsx24(Button, { size: "sm", variant: "ghost", onClick: handleCancelEdit, children: /* @__PURE__ */ jsx24(X4, { className: "h-3 w-3" }) })
3915
4177
  ] }) : /* @__PURE__ */ jsxs15(Fragment6, { children: [
3916
4178
  /* @__PURE__ */ jsx24("h4", { className: "font-medium text-sm truncate mb-1", children: thread.title }),
@@ -4043,7 +4305,7 @@ var ThreadManager = ({
4043
4305
  /* @__PURE__ */ jsxs15(CardHeader, { className: "border-b", children: [
4044
4306
  /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between", children: [
4045
4307
  /* @__PURE__ */ jsxs15(CardTitle, { className: "flex items-center gap-2", children: [
4046
- /* @__PURE__ */ jsx24(MessageSquare, { className: "h-5 w-5" }),
4308
+ /* @__PURE__ */ jsx24(MessageSquare2, { className: "h-5 w-5" }),
4047
4309
  config?.labels?.newChat || "Conversations"
4048
4310
  ] }),
4049
4311
  /* @__PURE__ */ jsx24(Button, { variant: "ghost", size: "icon", onClick: onClose, children: /* @__PURE__ */ jsx24(X4, { className: "h-4 w-4" }) })
@@ -4086,7 +4348,7 @@ var ThreadManager = ({
4086
4348
  /* @__PURE__ */ jsxs15(CardContent, { className: "p-0 flex-1", children: [
4087
4349
  /* @__PURE__ */ jsx24("div", { className: "p-4", children: onCreateThread && /* @__PURE__ */ jsx24(CreateThreadDialog2, { onCreateThread, config }) }),
4088
4350
  /* @__PURE__ */ jsx24(ScrollArea, { className: "h-[calc(100vh-280px)]", children: /* @__PURE__ */ jsx24("div", { className: "px-4 pb-4 space-y-4", children: Object.keys(groupedThreads).length === 0 ? /* @__PURE__ */ jsxs15("div", { className: "text-center py-8 text-muted-foreground", children: [
4089
- /* @__PURE__ */ jsx24(MessageSquare, { className: "h-12 w-12 mx-auto mb-3 opacity-50" }),
4351
+ /* @__PURE__ */ jsx24(MessageSquare2, { className: "h-12 w-12 mx-auto mb-3 opacity-50" }),
4090
4352
  /* @__PURE__ */ jsx24("p", { className: "text-sm", children: searchQuery ? config?.labels?.noThreadsFound || "No conversations found" : config?.labels?.noThreadsYet || "No conversations yet" })
4091
4353
  ] }) : Object.entries(groupedThreads).map(([group, groupThreads]) => /* @__PURE__ */ jsxs15("div", { children: [
4092
4354
  /* @__PURE__ */ jsx24("h3", { className: "text-sm font-medium text-muted-foreground mb-2 px-2", children: group }),
@@ -4106,7 +4368,7 @@ var ThreadManager = ({
4106
4368
  ] }, group)) }) })
4107
4369
  ] })
4108
4370
  ] }) }),
4109
- /* @__PURE__ */ jsx24(AlertDialog, { open: !!deleteThreadId, onOpenChange: () => setDeleteThreadId(null), children: /* @__PURE__ */ jsxs15(AlertDialogContent, { children: [
4371
+ deleteThreadId && /* @__PURE__ */ jsx24(AlertDialog, { open: !!deleteThreadId, onOpenChange: () => setDeleteThreadId(null), children: /* @__PURE__ */ jsxs15(AlertDialogContent, { children: [
4110
4372
  /* @__PURE__ */ jsxs15(AlertDialogHeader, { children: [
4111
4373
  /* @__PURE__ */ jsx24(AlertDialogTitle, { children: config?.labels?.deleteConfirmTitle || "Delete Conversation" }),
4112
4374
  /* @__PURE__ */ jsx24(AlertDialogDescription, { children: config?.labels?.deleteConfirmDescription || "Are you sure you want to delete this conversation? This action cannot be undone." })