@mordn/chat-widget 0.7.0 → 0.8.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.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
 
4
4
  // src/ChatWidget.tsx
5
- import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo4, useRef as useRef5, useState as useState6 } from "react";
5
+ import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo4, useRef as useRef5, useState as useState7 } from "react";
6
6
 
7
7
  // src/ui/button.tsx
8
8
  import { Slot } from "@radix-ui/react-slot";
@@ -191,10 +191,13 @@ Textarea.displayName = "Textarea";
191
191
 
192
192
  // src/components/prompt-input.tsx
193
193
  import {
194
+ FileIcon,
195
+ FileSpreadsheetIcon,
196
+ FileTextIcon,
194
197
  ImageIcon,
195
198
  Loader2Icon,
196
- PaperclipIcon,
197
199
  PlusIcon,
200
+ PresentationIcon,
198
201
  SendIcon,
199
202
  SquareIcon,
200
203
  XIcon
@@ -229,13 +232,22 @@ function PromptInputAttachment({
229
232
  ...props
230
233
  }) {
231
234
  const attachments = usePromptInputAttachments();
235
+ const isImage = data.mediaType?.startsWith("image/") && !!data.url;
232
236
  return /* @__PURE__ */ jsxs5(
233
237
  "div",
234
238
  {
235
- className: cn("group relative h-14 w-14 rounded-lg border", className),
239
+ className: cn(
240
+ "group relative rounded-lg border",
241
+ // Images keep the square thumbnail. Other files use a wider
242
+ // pill-shaped chip showing icon + filename — without it,
243
+ // non-image attachments rendered as identical paperclip
244
+ // squares with no way to tell them apart.
245
+ isImage ? "h-14 w-14" : "h-14 max-w-[200px]",
246
+ className
247
+ ),
236
248
  ...props,
237
249
  children: [
238
- data.mediaType?.startsWith("image/") && data.url ? /* @__PURE__ */ jsx8(
250
+ isImage ? /* @__PURE__ */ jsx8(
239
251
  "img",
240
252
  {
241
253
  alt: data.filename || "attachment",
@@ -244,7 +256,7 @@ function PromptInputAttachment({
244
256
  src: data.url,
245
257
  width: 56
246
258
  }
247
- ) : /* @__PURE__ */ jsx8("div", { className: "flex size-full items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx8(PaperclipIcon, { className: "size-4" }) }),
259
+ ) : /* @__PURE__ */ jsx8(NonImageChip, { data }),
248
260
  /* @__PURE__ */ jsx8(
249
261
  Button,
250
262
  {
@@ -262,6 +274,34 @@ function PromptInputAttachment({
262
274
  data.id
263
275
  );
264
276
  }
277
+ function NonImageChip({ data }) {
278
+ const { Icon: Icon2, label } = describeFile(data);
279
+ return /* @__PURE__ */ jsxs5("div", { className: "flex size-full items-center gap-2 px-2.5", children: [
280
+ /* @__PURE__ */ jsx8(Icon2, { className: "size-5 flex-shrink-0 text-muted-foreground" }),
281
+ /* @__PURE__ */ jsxs5("div", { className: "min-w-0 flex flex-col leading-tight", children: [
282
+ /* @__PURE__ */ jsx8("span", { className: "text-[12px] font-medium truncate", children: data.filename || "attachment" }),
283
+ /* @__PURE__ */ jsx8("span", { className: "text-[10px] text-muted-foreground uppercase tracking-wide", children: label })
284
+ ] })
285
+ ] });
286
+ }
287
+ function describeFile(data) {
288
+ const mt = (data.mediaType || "").toLowerCase();
289
+ const ext = (data.filename || "").toLowerCase().split(".").pop() || "";
290
+ if (mt === "application/pdf" || ext === "pdf") return { Icon: FileTextIcon, label: "PDF" };
291
+ if (mt.includes("spreadsheet") || mt.includes("excel") || ext === "xlsx" || ext === "xls" || ext === "csv" || ext === "tsv") {
292
+ return { Icon: FileSpreadsheetIcon, label: ext.toUpperCase() || "Spreadsheet" };
293
+ }
294
+ if (mt.includes("presentation") || mt.includes("powerpoint") || ext === "pptx" || ext === "ppt") {
295
+ return { Icon: PresentationIcon, label: ext.toUpperCase() || "Slides" };
296
+ }
297
+ if (mt.includes("wordprocessing") || mt.includes("msword") || ext === "docx" || ext === "doc") {
298
+ return { Icon: FileTextIcon, label: ext.toUpperCase() || "Doc" };
299
+ }
300
+ if (mt.startsWith("text/") || ext === "txt" || ext === "md" || ext === "json") {
301
+ return { Icon: FileTextIcon, label: ext.toUpperCase() || "Text" };
302
+ }
303
+ return { Icon: FileIcon, label: ext.toUpperCase() || "File" };
304
+ }
265
305
  function PromptInputAttachments({
266
306
  className,
267
307
  children,
@@ -326,10 +366,18 @@ var PromptInput = ({
326
366
  if (!accept || accept.trim() === "") {
327
367
  return true;
328
368
  }
329
- if (accept.includes("image/*")) {
330
- return f.type.startsWith("image/");
331
- }
332
- return true;
369
+ const tokens = accept.split(",").map((t) => t.trim().toLowerCase()).filter(Boolean);
370
+ const fileType = (f.type || "").toLowerCase();
371
+ const fileName = f.name.toLowerCase();
372
+ return tokens.some((token) => {
373
+ if (token === "*/*") return true;
374
+ if (token.startsWith(".")) return fileName.endsWith(token);
375
+ if (token.endsWith("/*")) {
376
+ const prefix = token.slice(0, -1);
377
+ return fileType.startsWith(prefix);
378
+ }
379
+ return fileType === token;
380
+ });
333
381
  },
334
382
  [accept]
335
383
  );
@@ -631,6 +679,8 @@ var PromptInputSubmit = ({
631
679
  variant = "default",
632
680
  size = "icon",
633
681
  status,
682
+ onStop,
683
+ onClick,
634
684
  children,
635
685
  ...props
636
686
  }) => {
@@ -642,13 +692,22 @@ var PromptInputSubmit = ({
642
692
  } else if (status === "error") {
643
693
  Icon2 = /* @__PURE__ */ jsx8(XIcon, { className: "size-4" });
644
694
  }
695
+ const isStopping = status === "streaming" && !!onStop;
645
696
  return /* @__PURE__ */ jsx8(
646
697
  Button,
647
698
  {
648
699
  className: cn("gap-1.5 rounded-lg", className),
649
700
  size,
650
- type: "submit",
701
+ type: isStopping ? "button" : "submit",
651
702
  variant,
703
+ onClick: (e) => {
704
+ if (isStopping) {
705
+ e.preventDefault();
706
+ onStop();
707
+ }
708
+ onClick?.(e);
709
+ },
710
+ "aria-label": isStopping ? "Stop generating" : void 0,
652
711
  ...props,
653
712
  children: children ?? Icon2
654
713
  }
@@ -656,62 +715,87 @@ var PromptInputSubmit = ({
656
715
  };
657
716
 
658
717
  // src/components/message-attachments.tsx
659
- import { PaperclipIcon as PaperclipIcon2 } from "lucide-react";
660
- import { jsx as jsx9 } from "react/jsx-runtime";
718
+ import {
719
+ FileIcon as FileIcon2,
720
+ FileSpreadsheetIcon as FileSpreadsheetIcon2,
721
+ FileTextIcon as FileTextIcon2,
722
+ PresentationIcon as PresentationIcon2
723
+ } from "lucide-react";
724
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
725
+ function openAttachment(attachment) {
726
+ if (attachment.url.startsWith("data:")) {
727
+ const w = window.open("", "_blank");
728
+ if (w) {
729
+ w.document.write(
730
+ `<html><head><title>${attachment.filename}</title></head><body style="margin:0;padding:20px;background:#f5f5f5;display:flex;justify-content:center;align-items:center;min-height:100vh;"><img src="${attachment.url}" alt="${attachment.filename}" style="max-width:100%;max-height:100%;object-fit:contain;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,0.15);" /></body></html>`
731
+ );
732
+ w.document.close();
733
+ }
734
+ return;
735
+ }
736
+ window.open(attachment.url, "_blank");
737
+ }
738
+ function describeFile2(att) {
739
+ const mt = (att.mediaType || "").toLowerCase();
740
+ const ext = (att.filename || "").toLowerCase().split(".").pop() || "";
741
+ if (mt === "application/pdf" || ext === "pdf") return { Icon: FileTextIcon2, label: "PDF" };
742
+ if (mt.includes("spreadsheet") || mt.includes("excel") || ext === "xlsx" || ext === "xls" || ext === "csv" || ext === "tsv") {
743
+ return { Icon: FileSpreadsheetIcon2, label: ext.toUpperCase() || "Spreadsheet" };
744
+ }
745
+ if (mt.includes("presentation") || mt.includes("powerpoint") || ext === "pptx" || ext === "ppt") {
746
+ return { Icon: PresentationIcon2, label: ext.toUpperCase() || "Slides" };
747
+ }
748
+ if (mt.includes("wordprocessing") || mt.includes("msword") || ext === "docx" || ext === "doc") {
749
+ return { Icon: FileTextIcon2, label: ext.toUpperCase() || "Doc" };
750
+ }
751
+ if (mt.startsWith("text/") || ext === "txt" || ext === "md" || ext === "json") {
752
+ return { Icon: FileTextIcon2, label: ext.toUpperCase() || "Text" };
753
+ }
754
+ return { Icon: FileIcon2, label: ext.toUpperCase() || "File" };
755
+ }
661
756
  function MessageAttachments({ attachments, className }) {
662
757
  if (!attachments || attachments.length === 0) {
663
758
  return null;
664
759
  }
665
- const handleAttachmentClick = (attachment) => {
666
- if (attachment.url.startsWith("data:")) {
667
- const newWindow = window.open("", "_blank");
668
- if (newWindow) {
669
- newWindow.document.write(`
670
- <html>
671
- <head><title>${attachment.filename}</title></head>
672
- <body style="margin:0; padding:20px; background:#f5f5f5; display:flex; justify-content:center; align-items:center; min-height:100vh;">
673
- <img src="${attachment.url}" alt="${attachment.filename}" style="max-width:100%; max-height:100%; object-fit:contain; border-radius:8px; box-shadow:0 4px 12px rgba(0,0,0,0.15);" />
674
- </body>
675
- </html>
676
- `);
677
- newWindow.document.close();
678
- }
679
- } else if (attachment.url.startsWith("blob:")) {
680
- window.open(attachment.url, "_blank");
681
- } else if (attachment.url.startsWith("http")) {
682
- window.open(attachment.url, "_blank");
683
- } else {
684
- window.open(attachment.url, "_blank");
685
- }
686
- };
687
- return /* @__PURE__ */ jsx9("div", { className: cn("flex flex-wrap gap-2", className), children: attachments.map((attachment, index) => /* @__PURE__ */ jsx9(
688
- "div",
689
- {
690
- className: "group relative h-14 w-14 rounded-lg",
691
- children: attachment.mediaType.startsWith("image/") ? /* @__PURE__ */ jsx9(
760
+ return /* @__PURE__ */ jsx9("div", { className: cn("flex flex-wrap gap-2", className), children: attachments.map((attachment, index) => {
761
+ const isImage = attachment.mediaType.startsWith("image/");
762
+ if (isImage) {
763
+ return /* @__PURE__ */ jsx9("div", { className: "group relative h-14 w-14 rounded-lg", children: /* @__PURE__ */ jsx9(
692
764
  "img",
693
765
  {
694
766
  src: attachment.url,
695
767
  alt: attachment.filename,
696
768
  className: "size-full rounded-lg object-cover cursor-pointer hover:opacity-80 transition-opacity",
697
- onClick: () => handleAttachmentClick(attachment)
769
+ onClick: () => openAttachment(attachment)
698
770
  }
699
- ) : /* @__PURE__ */ jsx9(
700
- "div",
701
- {
702
- className: "flex size-full items-center justify-center text-muted-foreground cursor-pointer hover:bg-secondary/50 rounded-lg transition-colors",
703
- onClick: () => handleAttachmentClick(attachment),
704
- children: /* @__PURE__ */ jsx9(PaperclipIcon2, { className: "size-4" })
705
- }
706
- )
707
- },
708
- index
709
- )) });
771
+ ) }, index);
772
+ }
773
+ const { Icon: Icon2, label } = describeFile2(attachment);
774
+ return /* @__PURE__ */ jsxs6(
775
+ "button",
776
+ {
777
+ type: "button",
778
+ onClick: () => openAttachment(attachment),
779
+ className: cn(
780
+ "group flex items-center gap-2 px-2.5 h-14 rounded-lg border max-w-[220px]",
781
+ "hover:bg-[hsl(var(--chat-text)/0.04)] transition-colors text-left cursor-pointer"
782
+ ),
783
+ children: [
784
+ /* @__PURE__ */ jsx9(Icon2, { className: "size-5 flex-shrink-0 text-muted-foreground" }),
785
+ /* @__PURE__ */ jsxs6("div", { className: "min-w-0 flex flex-col leading-tight", children: [
786
+ /* @__PURE__ */ jsx9("span", { className: "text-[12px] font-medium truncate", children: attachment.filename }),
787
+ /* @__PURE__ */ jsx9("span", { className: "text-[10px] text-muted-foreground uppercase tracking-wide", children: label })
788
+ ] })
789
+ ]
790
+ },
791
+ index
792
+ );
793
+ }) });
710
794
  }
711
795
 
712
796
  // src/components/input-plugin-popover.tsx
713
797
  import { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
714
- import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
798
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
715
799
  var FETCH_DEBOUNCE_MS = 120;
716
800
  function useInputPlugins({ textareaRef, value, setValue, plugins }) {
717
801
  const [active, setActive] = useState2(null);
@@ -882,7 +966,7 @@ function PluginPanel({ plugin, items, loading, highlight, onHover, onSelect }) {
882
966
  viewport.scrollTop += btnRect.bottom - viewRect.bottom;
883
967
  }
884
968
  }, [highlight]);
885
- return /* @__PURE__ */ jsxs6(
969
+ return /* @__PURE__ */ jsxs7(
886
970
  "div",
887
971
  {
888
972
  role: "listbox",
@@ -930,8 +1014,8 @@ function PluginPanel({ plugin, items, loading, highlight, onHover, onSelect }) {
930
1014
  {
931
1015
  ref: viewportRef,
932
1016
  className: "max-h-[200px] overflow-y-auto",
933
- children: /* @__PURE__ */ jsx10("div", { className: "py-1", children: items.map((item, idx) => /* @__PURE__ */ jsxs6("div", { children: [
934
- /* @__PURE__ */ jsxs6(
1017
+ children: /* @__PURE__ */ jsx10("div", { className: "py-1", children: items.map((item, idx) => /* @__PURE__ */ jsxs7("div", { children: [
1018
+ /* @__PURE__ */ jsxs7(
935
1019
  "button",
936
1020
  {
937
1021
  ref: (el) => {
@@ -986,9 +1070,136 @@ function PluginPanel({ plugin, items, loading, highlight, onHover, onSelect }) {
986
1070
  );
987
1071
  }
988
1072
 
1073
+ // src/components/chat-error-banner.tsx
1074
+ import { AlertTriangleIcon, XIcon as XIcon2 } from "lucide-react";
1075
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1076
+ function ChatErrorBanner({
1077
+ error,
1078
+ canRetry = true,
1079
+ onRetry,
1080
+ onDismiss
1081
+ }) {
1082
+ if (!error) return null;
1083
+ const friendly = friendlyErrorMessage(error);
1084
+ return /* @__PURE__ */ jsxs8(
1085
+ "div",
1086
+ {
1087
+ role: "alert",
1088
+ className: "flex items-start gap-2 px-3 py-2 mb-2 rounded-lg text-[13px]",
1089
+ style: {
1090
+ backgroundColor: "hsl(var(--chat-text)/0.04)",
1091
+ border: "1px solid var(--chat-divider)"
1092
+ },
1093
+ title: error.message,
1094
+ children: [
1095
+ /* @__PURE__ */ jsx11(
1096
+ AlertTriangleIcon,
1097
+ {
1098
+ className: "size-4 mt-0.5 flex-shrink-0",
1099
+ style: { color: "hsl(var(--chat-text)/0.6)" }
1100
+ }
1101
+ ),
1102
+ /* @__PURE__ */ jsx11("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx11("span", { style: { color: "hsl(var(--chat-text)/0.85)" }, children: friendly }) }),
1103
+ canRetry && onRetry && /* @__PURE__ */ jsx11(
1104
+ "button",
1105
+ {
1106
+ type: "button",
1107
+ onClick: onRetry,
1108
+ className: "text-[12px] font-medium underline-offset-2 hover:underline",
1109
+ style: { color: "hsl(var(--chat-text)/0.85)" },
1110
+ children: "Try again"
1111
+ }
1112
+ ),
1113
+ onDismiss && /* @__PURE__ */ jsx11(
1114
+ "button",
1115
+ {
1116
+ type: "button",
1117
+ onClick: onDismiss,
1118
+ "aria-label": "Dismiss",
1119
+ className: "flex-shrink-0 -mr-1 -mt-0.5 p-1 rounded hover:bg-[hsl(var(--chat-text)/0.06)] transition-colors",
1120
+ style: { color: "hsl(var(--chat-text)/0.5)" },
1121
+ children: /* @__PURE__ */ jsx11(XIcon2, { className: "size-3.5" })
1122
+ }
1123
+ )
1124
+ ]
1125
+ }
1126
+ );
1127
+ }
1128
+ function friendlyErrorMessage(error) {
1129
+ const raw = error.message ?? "";
1130
+ if (/abort/i.test(raw)) return "Stopped.";
1131
+ if (/network|fetch|disconnect|ECONN/i.test(raw)) {
1132
+ return "Connection issue. Check your network and try again.";
1133
+ }
1134
+ if (/rate.?limit|429/i.test(raw)) {
1135
+ return "You're sending messages too fast. Wait a moment and try again.";
1136
+ }
1137
+ if (/timeout/i.test(raw)) return "The response took too long.";
1138
+ return "Something went wrong while generating the response.";
1139
+ }
1140
+
1141
+ // src/components/message-actions.tsx
1142
+ import { useState as useState3 } from "react";
1143
+ import { CheckIcon as CheckIcon3, CopyIcon, RotateCcwIcon } from "lucide-react";
1144
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1145
+ function MessageActions({
1146
+ text,
1147
+ onRegenerate,
1148
+ regenerateDisabled,
1149
+ className
1150
+ }) {
1151
+ const [copied, setCopied] = useState3(false);
1152
+ const handleCopy = async () => {
1153
+ if (!text) return;
1154
+ try {
1155
+ await navigator.clipboard.writeText(text);
1156
+ setCopied(true);
1157
+ setTimeout(() => setCopied(false), 1500);
1158
+ } catch {
1159
+ }
1160
+ };
1161
+ return /* @__PURE__ */ jsxs9(
1162
+ "div",
1163
+ {
1164
+ className: cn(
1165
+ "flex items-center gap-1 mt-1.5 -ml-1.5",
1166
+ // Pulled left a touch so the icons line up with the message
1167
+ // text edge instead of its padding box.
1168
+ className
1169
+ ),
1170
+ children: [
1171
+ /* @__PURE__ */ jsx12(ActionButton, { onClick: handleCopy, ariaLabel: "Copy message", children: copied ? /* @__PURE__ */ jsx12(CheckIcon3, { className: "size-3.5" }) : /* @__PURE__ */ jsx12(CopyIcon, { className: "size-3.5" }) }),
1172
+ onRegenerate && /* @__PURE__ */ jsx12(
1173
+ ActionButton,
1174
+ {
1175
+ onClick: onRegenerate,
1176
+ disabled: regenerateDisabled,
1177
+ ariaLabel: "Regenerate response",
1178
+ children: /* @__PURE__ */ jsx12(RotateCcwIcon, { className: "size-3.5" })
1179
+ }
1180
+ )
1181
+ ]
1182
+ }
1183
+ );
1184
+ }
1185
+ function ActionButton({ onClick, disabled, ariaLabel, children }) {
1186
+ return /* @__PURE__ */ jsx12(
1187
+ "button",
1188
+ {
1189
+ type: "button",
1190
+ onClick,
1191
+ disabled,
1192
+ "aria-label": ariaLabel,
1193
+ className: "p-1.5 rounded-md transition-colors hover:bg-[hsl(var(--chat-text)/0.06)] disabled:opacity-40 disabled:cursor-not-allowed",
1194
+ style: { color: "hsl(var(--chat-text)/0.55)" },
1195
+ children
1196
+ }
1197
+ );
1198
+ }
1199
+
989
1200
  // src/components/interface.tsx
990
- import { useState as useState5, useEffect as useEffect5, useRef as useRef4, useMemo as useMemo3, useCallback as useCallback4 } from "react";
991
- import { HistoryIcon, MessageSquareIcon, SearchIcon, ChevronRightIcon as ChevronRightIcon2, PlusIcon as PlusIcon2, XIcon as XIcon2 } from "lucide-react";
1201
+ import { useState as useState6, useEffect as useEffect5, useRef as useRef4, useMemo as useMemo3, useCallback as useCallback4 } from "react";
1202
+ import { HistoryIcon, MessageSquareIcon, SearchIcon, ChevronRightIcon as ChevronRightIcon2, PlusIcon as PlusIcon2, XIcon as XIcon3 } from "lucide-react";
992
1203
  import { Fragment as Fragment5 } from "react";
993
1204
  import { useChat } from "@ai-sdk/react";
994
1205
  import { DefaultChatTransport } from "ai";
@@ -1032,11 +1243,11 @@ function useCodeBlockAutoScroll(isStreaming) {
1032
1243
  }
1033
1244
 
1034
1245
  // src/components/response.tsx
1035
- import { jsx as jsx11 } from "react/jsx-runtime";
1246
+ import { jsx as jsx13 } from "react/jsx-runtime";
1036
1247
  var Response = memo(
1037
1248
  ({ className, isStreaming = false, ...props }) => {
1038
1249
  const containerRef = useCodeBlockAutoScroll(isStreaming);
1039
- return /* @__PURE__ */ jsx11("div", { ref: containerRef, children: /* @__PURE__ */ jsx11(
1250
+ return /* @__PURE__ */ jsx13("div", { ref: containerRef, children: /* @__PURE__ */ jsx13(
1040
1251
  Streamdown,
1041
1252
  {
1042
1253
  className: cn(
@@ -1053,16 +1264,16 @@ Response.displayName = "Response";
1053
1264
 
1054
1265
  // src/ui/collapsible.tsx
1055
1266
  import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
1056
- import { jsx as jsx12 } from "react/jsx-runtime";
1267
+ import { jsx as jsx14 } from "react/jsx-runtime";
1057
1268
  function Collapsible({
1058
1269
  ...props
1059
1270
  }) {
1060
- return /* @__PURE__ */ jsx12(CollapsiblePrimitive.Root, { "data-slot": "collapsible", ...props });
1271
+ return /* @__PURE__ */ jsx14(CollapsiblePrimitive.Root, { "data-slot": "collapsible", ...props });
1061
1272
  }
1062
1273
  function CollapsibleTrigger2({
1063
1274
  ...props
1064
1275
  }) {
1065
- return /* @__PURE__ */ jsx12(
1276
+ return /* @__PURE__ */ jsx14(
1066
1277
  CollapsiblePrimitive.CollapsibleTrigger,
1067
1278
  {
1068
1279
  "data-slot": "collapsible-trigger",
@@ -1073,7 +1284,7 @@ function CollapsibleTrigger2({
1073
1284
  function CollapsibleContent2({
1074
1285
  ...props
1075
1286
  }) {
1076
- return /* @__PURE__ */ jsx12(
1287
+ return /* @__PURE__ */ jsx14(
1077
1288
  CollapsiblePrimitive.CollapsibleContent,
1078
1289
  {
1079
1290
  "data-slot": "collapsible-content",
@@ -1084,8 +1295,8 @@ function CollapsibleContent2({
1084
1295
 
1085
1296
  // src/components/sources.tsx
1086
1297
  import { BookIcon, ChevronDownIcon as ChevronDownIcon2 } from "lucide-react";
1087
- import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
1088
- var Sources = ({ className, ...props }) => /* @__PURE__ */ jsx13(
1298
+ import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
1299
+ var Sources = ({ className, ...props }) => /* @__PURE__ */ jsx15(
1089
1300
  Collapsible,
1090
1301
  {
1091
1302
  className: cn("not-prose mb-4 text-primary text-xs", className),
@@ -1097,25 +1308,25 @@ var SourcesTrigger = ({
1097
1308
  count,
1098
1309
  children,
1099
1310
  ...props
1100
- }) => /* @__PURE__ */ jsx13(
1311
+ }) => /* @__PURE__ */ jsx15(
1101
1312
  CollapsibleTrigger2,
1102
1313
  {
1103
1314
  className: cn("flex items-center gap-2", className),
1104
1315
  ...props,
1105
- children: children ?? /* @__PURE__ */ jsxs7(Fragment3, { children: [
1106
- /* @__PURE__ */ jsxs7("p", { className: "font-medium", children: [
1316
+ children: children ?? /* @__PURE__ */ jsxs10(Fragment3, { children: [
1317
+ /* @__PURE__ */ jsxs10("p", { className: "font-medium", children: [
1107
1318
  "Used ",
1108
1319
  count,
1109
1320
  " sources"
1110
1321
  ] }),
1111
- /* @__PURE__ */ jsx13(ChevronDownIcon2, { className: "h-4 w-4" })
1322
+ /* @__PURE__ */ jsx15(ChevronDownIcon2, { className: "h-4 w-4" })
1112
1323
  ] })
1113
1324
  }
1114
1325
  );
1115
1326
  var SourcesContent = ({
1116
1327
  className,
1117
1328
  ...props
1118
- }) => /* @__PURE__ */ jsx13(
1329
+ }) => /* @__PURE__ */ jsx15(
1119
1330
  CollapsibleContent2,
1120
1331
  {
1121
1332
  className: cn(
@@ -1126,7 +1337,7 @@ var SourcesContent = ({
1126
1337
  ...props
1127
1338
  }
1128
1339
  );
1129
- var Source = ({ href, title, children, ...props }) => /* @__PURE__ */ jsx13(
1340
+ var Source = ({ href, title, children, ...props }) => /* @__PURE__ */ jsx15(
1130
1341
  "a",
1131
1342
  {
1132
1343
  className: "flex items-center gap-2",
@@ -1134,9 +1345,9 @@ var Source = ({ href, title, children, ...props }) => /* @__PURE__ */ jsx13(
1134
1345
  rel: "noreferrer",
1135
1346
  target: "_blank",
1136
1347
  ...props,
1137
- children: children ?? /* @__PURE__ */ jsxs7(Fragment3, { children: [
1138
- /* @__PURE__ */ jsx13(BookIcon, { className: "h-4 w-4" }),
1139
- /* @__PURE__ */ jsx13("span", { className: "block font-medium", children: title })
1348
+ children: children ?? /* @__PURE__ */ jsxs10(Fragment3, { children: [
1349
+ /* @__PURE__ */ jsx15(BookIcon, { className: "h-4 w-4" }),
1350
+ /* @__PURE__ */ jsx15("span", { className: "block font-medium", children: title })
1140
1351
  ] })
1141
1352
  }
1142
1353
  );
@@ -1144,8 +1355,8 @@ var Source = ({ href, title, children, ...props }) => /* @__PURE__ */ jsx13(
1144
1355
  // src/components/reasoning.tsx
1145
1356
  import { useControllableState } from "@radix-ui/react-use-controllable-state";
1146
1357
  import { BrainIcon, ChevronDownIcon as ChevronDownIcon3 } from "lucide-react";
1147
- import { createContext as createContext2, memo as memo2, useContext as useContext2, useEffect as useEffect4, useState as useState3 } from "react";
1148
- import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
1358
+ import { createContext as createContext2, memo as memo2, useContext as useContext2, useEffect as useEffect4, useState as useState4 } from "react";
1359
+ import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
1149
1360
  var ReasoningContext = createContext2(null);
1150
1361
  var useReasoning = () => {
1151
1362
  const context = useContext2(ReasoningContext);
@@ -1176,8 +1387,8 @@ var Reasoning = memo2(
1176
1387
  prop: durationProp,
1177
1388
  defaultProp: void 0
1178
1389
  });
1179
- const [hasAutoClosed, setHasAutoClosed] = useState3(false);
1180
- const [startTime, setStartTime] = useState3(null);
1390
+ const [hasAutoClosed, setHasAutoClosed] = useState4(false);
1391
+ const [startTime, setStartTime] = useState4(null);
1181
1392
  useEffect4(() => {
1182
1393
  if (isStreaming) {
1183
1394
  if (startTime === null) {
@@ -1200,11 +1411,11 @@ var Reasoning = memo2(
1200
1411
  const handleOpenChange = (newOpen) => {
1201
1412
  setIsOpen(newOpen);
1202
1413
  };
1203
- return /* @__PURE__ */ jsx14(
1414
+ return /* @__PURE__ */ jsx16(
1204
1415
  ReasoningContext.Provider,
1205
1416
  {
1206
1417
  value: { isStreaming, isOpen, setIsOpen, duration },
1207
- children: /* @__PURE__ */ jsx14(
1418
+ children: /* @__PURE__ */ jsx16(
1208
1419
  Collapsible,
1209
1420
  {
1210
1421
  className: cn("not-prose", className),
@@ -1220,15 +1431,15 @@ var Reasoning = memo2(
1220
1431
  );
1221
1432
  var getThinkingMessage = (isStreaming, duration) => {
1222
1433
  if (isStreaming) {
1223
- return /* @__PURE__ */ jsx14(Fragment4, { children: "Thinking..." });
1434
+ return /* @__PURE__ */ jsx16(Fragment4, { children: "Thinking..." });
1224
1435
  }
1225
1436
  if (duration === void 0) {
1226
- return /* @__PURE__ */ jsx14(Fragment4, { children: "Thought process" });
1437
+ return /* @__PURE__ */ jsx16(Fragment4, { children: "Thought process" });
1227
1438
  }
1228
1439
  if (duration === 0) {
1229
- return /* @__PURE__ */ jsx14(Fragment4, { children: "Thought process" });
1440
+ return /* @__PURE__ */ jsx16(Fragment4, { children: "Thought process" });
1230
1441
  }
1231
- return /* @__PURE__ */ jsxs8(Fragment4, { children: [
1442
+ return /* @__PURE__ */ jsxs11(Fragment4, { children: [
1232
1443
  "Thought for ",
1233
1444
  duration,
1234
1445
  " seconds"
@@ -1237,7 +1448,7 @@ var getThinkingMessage = (isStreaming, duration) => {
1237
1448
  var ReasoningTrigger = memo2(
1238
1449
  ({ className, children, ...props }) => {
1239
1450
  const { isStreaming, isOpen, duration } = useReasoning();
1240
- return /* @__PURE__ */ jsx14(
1451
+ return /* @__PURE__ */ jsx16(
1241
1452
  CollapsibleTrigger2,
1242
1453
  {
1243
1454
  className: cn(
@@ -1245,10 +1456,10 @@ var ReasoningTrigger = memo2(
1245
1456
  className
1246
1457
  ),
1247
1458
  ...props,
1248
- children: children ?? /* @__PURE__ */ jsxs8(Fragment4, { children: [
1249
- /* @__PURE__ */ jsx14(BrainIcon, { className: "size-4 flex-shrink-0" }),
1459
+ children: children ?? /* @__PURE__ */ jsxs11(Fragment4, { children: [
1460
+ /* @__PURE__ */ jsx16(BrainIcon, { className: "size-4 flex-shrink-0" }),
1250
1461
  getThinkingMessage(isStreaming, duration),
1251
- /* @__PURE__ */ jsx14(
1462
+ /* @__PURE__ */ jsx16(
1252
1463
  ChevronDownIcon3,
1253
1464
  {
1254
1465
  className: cn(
@@ -1263,7 +1474,7 @@ var ReasoningTrigger = memo2(
1263
1474
  }
1264
1475
  );
1265
1476
  var ReasoningContent = memo2(
1266
- ({ className, children, ...props }) => /* @__PURE__ */ jsx14(
1477
+ ({ className, children, ...props }) => /* @__PURE__ */ jsx16(
1267
1478
  CollapsibleContent2,
1268
1479
  {
1269
1480
  className: cn(
@@ -1272,7 +1483,7 @@ var ReasoningContent = memo2(
1272
1483
  className
1273
1484
  ),
1274
1485
  ...props,
1275
- children: /* @__PURE__ */ jsx14(Response, { className: "grid gap-2", children })
1486
+ children: /* @__PURE__ */ jsx16(Response, { className: "grid gap-2", children })
1276
1487
  }
1277
1488
  )
1278
1489
  );
@@ -1281,8 +1492,8 @@ ReasoningTrigger.displayName = "ReasoningTrigger";
1281
1492
  ReasoningContent.displayName = "ReasoningContent";
1282
1493
 
1283
1494
  // src/components/loader.tsx
1284
- import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
1285
- var LoaderIcon = ({ size = 16 }) => /* @__PURE__ */ jsxs9(
1495
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
1496
+ var LoaderIcon = ({ size = 16 }) => /* @__PURE__ */ jsxs12(
1286
1497
  "svg",
1287
1498
  {
1288
1499
  height: size,
@@ -1291,10 +1502,10 @@ var LoaderIcon = ({ size = 16 }) => /* @__PURE__ */ jsxs9(
1291
1502
  viewBox: "0 0 16 16",
1292
1503
  width: size,
1293
1504
  children: [
1294
- /* @__PURE__ */ jsx15("title", { children: "Loader" }),
1295
- /* @__PURE__ */ jsxs9("g", { clipPath: "url(#clip0_2393_1490)", children: [
1296
- /* @__PURE__ */ jsx15("path", { d: "M8 0V4", stroke: "currentColor", strokeWidth: "1.5" }),
1297
- /* @__PURE__ */ jsx15(
1505
+ /* @__PURE__ */ jsx17("title", { children: "Loader" }),
1506
+ /* @__PURE__ */ jsxs12("g", { clipPath: "url(#clip0_2393_1490)", children: [
1507
+ /* @__PURE__ */ jsx17("path", { d: "M8 0V4", stroke: "currentColor", strokeWidth: "1.5" }),
1508
+ /* @__PURE__ */ jsx17(
1298
1509
  "path",
1299
1510
  {
1300
1511
  d: "M8 16V12",
@@ -1303,7 +1514,7 @@ var LoaderIcon = ({ size = 16 }) => /* @__PURE__ */ jsxs9(
1303
1514
  strokeWidth: "1.5"
1304
1515
  }
1305
1516
  ),
1306
- /* @__PURE__ */ jsx15(
1517
+ /* @__PURE__ */ jsx17(
1307
1518
  "path",
1308
1519
  {
1309
1520
  d: "M3.29773 1.52783L5.64887 4.7639",
@@ -1312,7 +1523,7 @@ var LoaderIcon = ({ size = 16 }) => /* @__PURE__ */ jsxs9(
1312
1523
  strokeWidth: "1.5"
1313
1524
  }
1314
1525
  ),
1315
- /* @__PURE__ */ jsx15(
1526
+ /* @__PURE__ */ jsx17(
1316
1527
  "path",
1317
1528
  {
1318
1529
  d: "M12.7023 1.52783L10.3511 4.7639",
@@ -1321,7 +1532,7 @@ var LoaderIcon = ({ size = 16 }) => /* @__PURE__ */ jsxs9(
1321
1532
  strokeWidth: "1.5"
1322
1533
  }
1323
1534
  ),
1324
- /* @__PURE__ */ jsx15(
1535
+ /* @__PURE__ */ jsx17(
1325
1536
  "path",
1326
1537
  {
1327
1538
  d: "M12.7023 14.472L10.3511 11.236",
@@ -1330,7 +1541,7 @@ var LoaderIcon = ({ size = 16 }) => /* @__PURE__ */ jsxs9(
1330
1541
  strokeWidth: "1.5"
1331
1542
  }
1332
1543
  ),
1333
- /* @__PURE__ */ jsx15(
1544
+ /* @__PURE__ */ jsx17(
1334
1545
  "path",
1335
1546
  {
1336
1547
  d: "M3.29773 14.472L5.64887 11.236",
@@ -1339,7 +1550,7 @@ var LoaderIcon = ({ size = 16 }) => /* @__PURE__ */ jsxs9(
1339
1550
  strokeWidth: "1.5"
1340
1551
  }
1341
1552
  ),
1342
- /* @__PURE__ */ jsx15(
1553
+ /* @__PURE__ */ jsx17(
1343
1554
  "path",
1344
1555
  {
1345
1556
  d: "M15.6085 5.52783L11.8043 6.7639",
@@ -1348,7 +1559,7 @@ var LoaderIcon = ({ size = 16 }) => /* @__PURE__ */ jsxs9(
1348
1559
  strokeWidth: "1.5"
1349
1560
  }
1350
1561
  ),
1351
- /* @__PURE__ */ jsx15(
1562
+ /* @__PURE__ */ jsx17(
1352
1563
  "path",
1353
1564
  {
1354
1565
  d: "M0.391602 10.472L4.19583 9.23598",
@@ -1357,7 +1568,7 @@ var LoaderIcon = ({ size = 16 }) => /* @__PURE__ */ jsxs9(
1357
1568
  strokeWidth: "1.5"
1358
1569
  }
1359
1570
  ),
1360
- /* @__PURE__ */ jsx15(
1571
+ /* @__PURE__ */ jsx17(
1361
1572
  "path",
1362
1573
  {
1363
1574
  d: "M15.6085 10.4722L11.8043 9.2361",
@@ -1366,7 +1577,7 @@ var LoaderIcon = ({ size = 16 }) => /* @__PURE__ */ jsxs9(
1366
1577
  strokeWidth: "1.5"
1367
1578
  }
1368
1579
  ),
1369
- /* @__PURE__ */ jsx15(
1580
+ /* @__PURE__ */ jsx17(
1370
1581
  "path",
1371
1582
  {
1372
1583
  d: "M0.391602 5.52783L4.19583 6.7639",
@@ -1376,11 +1587,11 @@ var LoaderIcon = ({ size = 16 }) => /* @__PURE__ */ jsxs9(
1376
1587
  }
1377
1588
  )
1378
1589
  ] }),
1379
- /* @__PURE__ */ jsx15("defs", { children: /* @__PURE__ */ jsx15("clipPath", { id: "clip0_2393_1490", children: /* @__PURE__ */ jsx15("rect", { fill: "white", height: "16", width: "16" }) }) })
1590
+ /* @__PURE__ */ jsx17("defs", { children: /* @__PURE__ */ jsx17("clipPath", { id: "clip0_2393_1490", children: /* @__PURE__ */ jsx17("rect", { fill: "white", height: "16", width: "16" }) }) })
1380
1591
  ]
1381
1592
  }
1382
1593
  );
1383
- var Loader = ({ className, size = 16, ...props }) => /* @__PURE__ */ jsx15(
1594
+ var Loader = ({ className, size = 16, ...props }) => /* @__PURE__ */ jsx17(
1384
1595
  "div",
1385
1596
  {
1386
1597
  className: cn(
@@ -1388,14 +1599,14 @@ var Loader = ({ className, size = 16, ...props }) => /* @__PURE__ */ jsx15(
1388
1599
  className
1389
1600
  ),
1390
1601
  ...props,
1391
- children: /* @__PURE__ */ jsx15(LoaderIcon, { size })
1602
+ children: /* @__PURE__ */ jsx17(LoaderIcon, { size })
1392
1603
  }
1393
1604
  );
1394
1605
 
1395
1606
  // src/ui/badge.tsx
1396
1607
  import { Slot as Slot2 } from "@radix-ui/react-slot";
1397
1608
  import { cva as cva3 } from "class-variance-authority";
1398
- import { jsx as jsx16 } from "react/jsx-runtime";
1609
+ import { jsx as jsx18 } from "react/jsx-runtime";
1399
1610
  var badgeVariants = cva3(
1400
1611
  "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
1401
1612
  {
@@ -1419,7 +1630,7 @@ function Badge({
1419
1630
  ...props
1420
1631
  }) {
1421
1632
  const Comp = asChild ? Slot2 : "span";
1422
- return /* @__PURE__ */ jsx16(
1633
+ return /* @__PURE__ */ jsx18(
1423
1634
  Comp,
1424
1635
  {
1425
1636
  "data-slot": "badge",
@@ -1441,14 +1652,14 @@ import {
1441
1652
  import { isValidElement } from "react";
1442
1653
 
1443
1654
  // src/components/code-block.tsx
1444
- import { CheckIcon as CheckIcon3, CopyIcon } from "lucide-react";
1445
- import { createContext as createContext3, useContext as useContext3, useState as useState4 } from "react";
1655
+ import { CheckIcon as CheckIcon4, CopyIcon as CopyIcon2 } from "lucide-react";
1656
+ import { createContext as createContext3, useContext as useContext3, useState as useState5 } from "react";
1446
1657
  import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
1447
1658
  import {
1448
1659
  oneDark,
1449
1660
  oneLight
1450
1661
  } from "react-syntax-highlighter/dist/esm/styles/prism";
1451
- import { jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
1662
+ import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
1452
1663
  var CodeBlockContext = createContext3({
1453
1664
  code: ""
1454
1665
  });
@@ -1459,7 +1670,7 @@ var CodeBlock = ({
1459
1670
  className,
1460
1671
  children,
1461
1672
  ...props
1462
- }) => /* @__PURE__ */ jsx17(CodeBlockContext.Provider, { value: { code }, children: /* @__PURE__ */ jsx17(
1673
+ }) => /* @__PURE__ */ jsx19(CodeBlockContext.Provider, { value: { code }, children: /* @__PURE__ */ jsx19(
1463
1674
  "div",
1464
1675
  {
1465
1676
  className: cn(
@@ -1467,8 +1678,8 @@ var CodeBlock = ({
1467
1678
  className
1468
1679
  ),
1469
1680
  ...props,
1470
- children: /* @__PURE__ */ jsxs10("div", { className: "relative max-h-96 overflow-y-auto", children: [
1471
- /* @__PURE__ */ jsx17(
1681
+ children: /* @__PURE__ */ jsxs13("div", { className: "relative max-h-96 overflow-y-auto", children: [
1682
+ /* @__PURE__ */ jsx19(
1472
1683
  SyntaxHighlighter,
1473
1684
  {
1474
1685
  className: "overflow-hidden dark:hidden",
@@ -1494,7 +1705,7 @@ var CodeBlock = ({
1494
1705
  children: code
1495
1706
  }
1496
1707
  ),
1497
- /* @__PURE__ */ jsx17(
1708
+ /* @__PURE__ */ jsx19(
1498
1709
  SyntaxHighlighter,
1499
1710
  {
1500
1711
  className: "hidden overflow-hidden dark:block",
@@ -1520,36 +1731,42 @@ var CodeBlock = ({
1520
1731
  children: code
1521
1732
  }
1522
1733
  ),
1523
- children && /* @__PURE__ */ jsx17("div", { className: "absolute top-2 right-2 flex items-center gap-2", children })
1734
+ children && /* @__PURE__ */ jsx19("div", { className: "absolute top-2 right-2 flex items-center gap-2", children })
1524
1735
  ] })
1525
1736
  }
1526
1737
  ) });
1527
1738
 
1528
1739
  // src/components/tool.tsx
1529
- import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
1530
- var Tool = ({ className, ...props }) => /* @__PURE__ */ jsx18(
1740
+ import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
1741
+ var Tool = ({ className, ...props }) => /* @__PURE__ */ jsx20(
1531
1742
  Collapsible,
1532
1743
  {
1533
1744
  className: cn("not-prose w-full rounded-md border border-[var(--chat-divider)]", className),
1534
1745
  ...props
1535
1746
  }
1536
1747
  );
1748
+ var STATUS_LABELS = {
1749
+ "input-streaming": "Pending",
1750
+ "input-available": "Running",
1751
+ "output-available": "Completed",
1752
+ "output-error": "Error",
1753
+ "approval-requested": "Awaiting approval",
1754
+ "approval-responded": "Approved",
1755
+ "output-denied": "Denied"
1756
+ };
1757
+ var STATUS_ICONS = {
1758
+ "input-streaming": /* @__PURE__ */ jsx20(CircleIcon2, { className: "size-4" }),
1759
+ "input-available": /* @__PURE__ */ jsx20(ClockIcon, { className: "size-4 animate-pulse" }),
1760
+ "output-available": /* @__PURE__ */ jsx20(CheckCircleIcon, { className: "size-4 text-green-600" }),
1761
+ "output-error": /* @__PURE__ */ jsx20(XCircleIcon, { className: "size-4 text-red-600" }),
1762
+ "approval-requested": /* @__PURE__ */ jsx20(ClockIcon, { className: "size-4 text-amber-600" }),
1763
+ "approval-responded": /* @__PURE__ */ jsx20(CheckCircleIcon, { className: "size-4 text-amber-600" }),
1764
+ "output-denied": /* @__PURE__ */ jsx20(XCircleIcon, { className: "size-4 text-muted-foreground" })
1765
+ };
1537
1766
  var getStatusBadge = (status) => {
1538
- const labels = {
1539
- "input-streaming": "Pending",
1540
- "input-available": "Running",
1541
- "output-available": "Completed",
1542
- "output-error": "Error"
1543
- };
1544
- const icons = {
1545
- "input-streaming": /* @__PURE__ */ jsx18(CircleIcon2, { className: "size-4" }),
1546
- "input-available": /* @__PURE__ */ jsx18(ClockIcon, { className: "size-4 animate-pulse" }),
1547
- "output-available": /* @__PURE__ */ jsx18(CheckCircleIcon, { className: "size-4 text-green-600" }),
1548
- "output-error": /* @__PURE__ */ jsx18(XCircleIcon, { className: "size-4 text-red-600" })
1549
- };
1550
- return /* @__PURE__ */ jsxs11(Badge, { className: "gap-1.5 rounded-full text-xs", variant: "secondary", children: [
1551
- icons[status],
1552
- labels[status]
1767
+ return /* @__PURE__ */ jsxs14(Badge, { className: "gap-1.5 rounded-full text-xs", variant: "secondary", children: [
1768
+ STATUS_ICONS[status],
1769
+ STATUS_LABELS[status]
1553
1770
  ] });
1554
1771
  };
1555
1772
  var ToolHeader = ({
@@ -1559,7 +1776,7 @@ var ToolHeader = ({
1559
1776
  toolName,
1560
1777
  state,
1561
1778
  ...props
1562
- }) => /* @__PURE__ */ jsxs11(
1779
+ }) => /* @__PURE__ */ jsxs14(
1563
1780
  CollapsibleTrigger2,
1564
1781
  {
1565
1782
  className: cn(
@@ -1568,16 +1785,16 @@ var ToolHeader = ({
1568
1785
  ),
1569
1786
  ...props,
1570
1787
  children: [
1571
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
1572
- /* @__PURE__ */ jsx18(WrenchIcon, { className: "size-4 text-muted-foreground" }),
1573
- /* @__PURE__ */ jsx18("span", { className: "font-medium text-sm", children: title ?? toolName ?? type.split("-").slice(1).join("-") }),
1788
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2", children: [
1789
+ /* @__PURE__ */ jsx20(WrenchIcon, { className: "size-4 text-muted-foreground" }),
1790
+ /* @__PURE__ */ jsx20("span", { className: "font-medium text-sm", children: title ?? toolName ?? type.split("-").slice(1).join("-") }),
1574
1791
  getStatusBadge(state)
1575
1792
  ] }),
1576
- /* @__PURE__ */ jsx18(ChevronDownIcon4, { className: "size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" })
1793
+ /* @__PURE__ */ jsx20(ChevronDownIcon4, { className: "size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" })
1577
1794
  ]
1578
1795
  }
1579
1796
  );
1580
- var ToolContent = ({ className, ...props }) => /* @__PURE__ */ jsx18(
1797
+ var ToolContent = ({ className, ...props }) => /* @__PURE__ */ jsx20(
1581
1798
  CollapsibleContent2,
1582
1799
  {
1583
1800
  className: cn(
@@ -1587,9 +1804,9 @@ var ToolContent = ({ className, ...props }) => /* @__PURE__ */ jsx18(
1587
1804
  ...props
1588
1805
  }
1589
1806
  );
1590
- var ToolInput = ({ className, input, ...props }) => /* @__PURE__ */ jsxs11("div", { className: cn("space-y-2 overflow-hidden p-2", className), ...props, children: [
1591
- /* @__PURE__ */ jsx18("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: "Parameters" }),
1592
- /* @__PURE__ */ jsx18("div", { className: "rounded-md bg-muted/50", children: /* @__PURE__ */ jsx18(CodeBlock, { code: JSON.stringify(input, null, 2), language: "json" }) })
1807
+ var ToolInput = ({ className, input, ...props }) => /* @__PURE__ */ jsxs14("div", { className: cn("space-y-2 overflow-hidden p-2", className), ...props, children: [
1808
+ /* @__PURE__ */ jsx20("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: "Parameters" }),
1809
+ /* @__PURE__ */ jsx20("div", { className: "rounded-md bg-muted/50", children: /* @__PURE__ */ jsx20(CodeBlock, { code: JSON.stringify(input, null, 2), language: "json" }) })
1593
1810
  ] });
1594
1811
  var ToolOutput = ({
1595
1812
  className,
@@ -1600,15 +1817,15 @@ var ToolOutput = ({
1600
1817
  if (!(output || errorText)) {
1601
1818
  return null;
1602
1819
  }
1603
- let Output = /* @__PURE__ */ jsx18("div", { children: output });
1820
+ let Output = /* @__PURE__ */ jsx20("div", { children: output });
1604
1821
  if (typeof output === "object" && !isValidElement(output)) {
1605
- Output = /* @__PURE__ */ jsx18(CodeBlock, { code: JSON.stringify(output, null, 2), language: "json" });
1822
+ Output = /* @__PURE__ */ jsx20(CodeBlock, { code: JSON.stringify(output, null, 2), language: "json" });
1606
1823
  } else if (typeof output === "string") {
1607
- Output = /* @__PURE__ */ jsx18(CodeBlock, { code: output, language: "json" });
1824
+ Output = /* @__PURE__ */ jsx20(CodeBlock, { code: output, language: "json" });
1608
1825
  }
1609
- return /* @__PURE__ */ jsxs11("div", { className: cn("space-y-2 p-2", className), ...props, children: [
1610
- /* @__PURE__ */ jsx18("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: errorText ? "Error" : "Result" }),
1611
- /* @__PURE__ */ jsxs11(
1826
+ return /* @__PURE__ */ jsxs14("div", { className: cn("space-y-2 p-2", className), ...props, children: [
1827
+ /* @__PURE__ */ jsx20("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: errorText ? "Error" : "Result" }),
1828
+ /* @__PURE__ */ jsxs14(
1612
1829
  "div",
1613
1830
  {
1614
1831
  className: cn(
@@ -1616,7 +1833,7 @@ var ToolOutput = ({
1616
1833
  errorText ? "bg-destructive/10 text-destructive" : "bg-muted/50 text-foreground"
1617
1834
  ),
1618
1835
  children: [
1619
- errorText && /* @__PURE__ */ jsx18("div", { children: errorText }),
1836
+ errorText && /* @__PURE__ */ jsx20("div", { children: errorText }),
1620
1837
  Output
1621
1838
  ]
1622
1839
  }
@@ -1625,7 +1842,7 @@ var ToolOutput = ({
1625
1842
  };
1626
1843
 
1627
1844
  // src/components/suggestion2.tsx
1628
- import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
1845
+ import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
1629
1846
  function StarterMessages({
1630
1847
  className,
1631
1848
  prompts,
@@ -1633,7 +1850,7 @@ function StarterMessages({
1633
1850
  ...props
1634
1851
  }) {
1635
1852
  if (prompts.length === 0) return null;
1636
- return /* @__PURE__ */ jsx19(
1853
+ return /* @__PURE__ */ jsx21(
1637
1854
  "div",
1638
1855
  {
1639
1856
  className: cn(
@@ -1641,8 +1858,8 @@ function StarterMessages({
1641
1858
  className
1642
1859
  ),
1643
1860
  ...props,
1644
- children: prompts.map((prompt, index) => /* @__PURE__ */ jsxs12("div", { children: [
1645
- /* @__PURE__ */ jsx19(
1861
+ children: prompts.map((prompt, index) => /* @__PURE__ */ jsxs15("div", { children: [
1862
+ /* @__PURE__ */ jsx21(
1646
1863
  StarterMessageItem,
1647
1864
  {
1648
1865
  prompt,
@@ -1652,7 +1869,7 @@ function StarterMessages({
1652
1869
  index < prompts.length - 1 && // 1px-tall element used as a divider — same --chat-divider token
1653
1870
  // every other separator in the widget uses, so consumers only
1654
1871
  // need to override one variable to recolour all of them.
1655
- /* @__PURE__ */ jsx19("div", { className: "h-px mx-3", style: { backgroundColor: "var(--chat-divider)" } })
1872
+ /* @__PURE__ */ jsx21("div", { className: "h-px mx-3", style: { backgroundColor: "var(--chat-divider)" } })
1656
1873
  ] }, index))
1657
1874
  }
1658
1875
  );
@@ -1663,7 +1880,7 @@ function StarterMessageItem({
1663
1880
  onClick,
1664
1881
  ...props
1665
1882
  }) {
1666
- return /* @__PURE__ */ jsxs12(
1883
+ return /* @__PURE__ */ jsxs15(
1667
1884
  "button",
1668
1885
  {
1669
1886
  type: "button",
@@ -1678,8 +1895,8 @@ function StarterMessageItem({
1678
1895
  ),
1679
1896
  ...props,
1680
1897
  children: [
1681
- /* @__PURE__ */ jsx19("span", { className: "text-[13px] text-[hsl(var(--chat-text)/0.7)]", children: prompt.title }),
1682
- prompt.subtitle && /* @__PURE__ */ jsx19("span", { className: "block text-[11px] text-[hsl(var(--chat-text)/0.4)] mt-0.5", children: prompt.subtitle })
1898
+ /* @__PURE__ */ jsx21("span", { className: "text-[13px] text-[hsl(var(--chat-text)/0.7)]", children: prompt.title }),
1899
+ prompt.subtitle && /* @__PURE__ */ jsx21("span", { className: "block text-[11px] text-[hsl(var(--chat-text)/0.4)] mt-0.5", children: prompt.subtitle })
1683
1900
  ]
1684
1901
  }
1685
1902
  );
@@ -1687,7 +1904,7 @@ function StarterMessageItem({
1687
1904
 
1688
1905
  // src/contexts/chat-storage-context.tsx
1689
1906
  import { createContext as createContext4, useContext as useContext4 } from "react";
1690
- import { jsx as jsx20 } from "react/jsx-runtime";
1907
+ import { jsx as jsx22 } from "react/jsx-runtime";
1691
1908
  var ChatStorageContext = createContext4({
1692
1909
  storageKeyPrefix: ""
1693
1910
  });
@@ -1696,19 +1913,19 @@ function ChatStorageProvider({
1696
1913
  userId
1697
1914
  }) {
1698
1915
  const storageKeyPrefix = userId || "";
1699
- return /* @__PURE__ */ jsx20(ChatStorageContext.Provider, { value: { storageKeyPrefix }, children });
1916
+ return /* @__PURE__ */ jsx22(ChatStorageContext.Provider, { value: { storageKeyPrefix }, children });
1700
1917
  }
1701
1918
  function useChatStorageKey() {
1702
1919
  return useContext4(ChatStorageContext);
1703
1920
  }
1704
1921
 
1705
1922
  // src/components/interface.tsx
1706
- import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
1923
+ import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
1707
1924
  function ChatInterface({ id, initialMessages, config, onClose, headerActions } = {}) {
1708
1925
  const { storageKeyPrefix } = useChatStorageKey();
1709
1926
  const storageKey = (key) => storageKeyPrefix ? `chat-${storageKeyPrefix}-${key}` : `chat-${key}`;
1710
1927
  const themeMode = config?.theme?.mode || "light";
1711
- const [input, setInput] = useState5("");
1928
+ const [input, setInput] = useState6("");
1712
1929
  const inputRef = useRef4(null);
1713
1930
  const inputPlugins = useInputPlugins({
1714
1931
  textareaRef: inputRef,
@@ -1716,26 +1933,26 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1716
1933
  setValue: setInput,
1717
1934
  plugins: config?.inputPlugins
1718
1935
  });
1719
- const [showHistory, setShowHistory] = useState5(false);
1720
- const [conversations, setConversations] = useState5([]);
1721
- const [loadingHistory, setLoadingHistory] = useState5(false);
1722
- const [historyLoaded, setHistoryLoaded] = useState5(false);
1723
- const [searchQuery, setSearchQuery] = useState5("");
1724
- const [uploadError, setUploadError] = useState5(null);
1936
+ const [showHistory, setShowHistory] = useState6(false);
1937
+ const [conversations, setConversations] = useState6([]);
1938
+ const [loadingHistory, setLoadingHistory] = useState6(false);
1939
+ const [historyLoaded, setHistoryLoaded] = useState6(false);
1940
+ const [searchQuery, setSearchQuery] = useState6("");
1941
+ const [uploadError, setUploadError] = useState6(null);
1725
1942
  useEffect5(() => {
1726
1943
  if (uploadError) {
1727
1944
  const timeoutId = setTimeout(() => setUploadError(null), 5e3);
1728
1945
  return () => clearTimeout(timeoutId);
1729
1946
  }
1730
1947
  }, [uploadError]);
1731
- const [tabs, setTabs] = useState5([]);
1732
- const [activeTabId, setActiveTabId] = useState5("");
1733
- const [initialTabCreated, setInitialTabCreated] = useState5(false);
1734
- const [isInitializing, setIsInitializing] = useState5(true);
1735
- const [isLoadingMessages, setIsLoadingMessages] = useState5(false);
1948
+ const [tabs, setTabs] = useState6([]);
1949
+ const [activeTabId, setActiveTabId] = useState6("");
1950
+ const [initialTabCreated, setInitialTabCreated] = useState6(false);
1951
+ const [isInitializing, setIsInitializing] = useState6(true);
1952
+ const [isLoadingMessages, setIsLoadingMessages] = useState6(false);
1736
1953
  const lastSyncedTabId = useRef4("");
1737
1954
  const hasInitialized = useRef4(false);
1738
- const { messages, sendMessage, status, setMessages } = useChat({
1955
+ const { messages, sendMessage, status, setMessages, stop, regenerate, error, clearError } = useChat({
1739
1956
  id: activeTabId || "temp-id",
1740
1957
  transport: new DefaultChatTransport({
1741
1958
  api: "/api/chat",
@@ -1782,8 +1999,8 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1782
1999
  mediaType: uploadResult.mediaType,
1783
2000
  size: uploadResult.size
1784
2001
  };
1785
- } catch (error) {
1786
- console.error(`Error uploading ${file.filename}:`, error);
2002
+ } catch (error2) {
2003
+ console.error(`Error uploading ${file.filename}:`, error2);
1787
2004
  return null;
1788
2005
  }
1789
2006
  });
@@ -1800,10 +2017,10 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1800
2017
  setUploadError(warnMsg);
1801
2018
  console.warn(warnMsg);
1802
2019
  }
1803
- } catch (error) {
2020
+ } catch (error2) {
1804
2021
  const errorMsg = "Error uploading files. Please try again.";
1805
2022
  setUploadError(errorMsg);
1806
- console.error("Error in file upload process:", error);
2023
+ console.error("Error in file upload process:", error2);
1807
2024
  return;
1808
2025
  }
1809
2026
  }
@@ -1824,12 +2041,12 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1824
2041
  };
1825
2042
  const AttachButton = () => {
1826
2043
  const attachments = usePromptInputAttachments();
1827
- return /* @__PURE__ */ jsx21(
2044
+ return /* @__PURE__ */ jsx23(
1828
2045
  PromptInputButton,
1829
2046
  {
1830
2047
  variant: "ghost",
1831
2048
  onClick: () => attachments.openFileDialog(),
1832
- children: /* @__PURE__ */ jsx21(PlusIcon2, { className: "size-4" })
2049
+ children: /* @__PURE__ */ jsx23(PlusIcon2, { className: "size-4" })
1833
2050
  }
1834
2051
  );
1835
2052
  };
@@ -1852,8 +2069,8 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1852
2069
  } else {
1853
2070
  console.error("Error loading messages:", response.status, response.statusText);
1854
2071
  }
1855
- } catch (error) {
1856
- console.error("Error loading conversation:", error);
2072
+ } catch (error2) {
2073
+ console.error("Error loading conversation:", error2);
1857
2074
  }
1858
2075
  };
1859
2076
  const generateUniqueTabId = () => {
@@ -1957,8 +2174,8 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1957
2174
  const errorText = await response.text();
1958
2175
  console.error("[ChatInterface] Error response:", errorText);
1959
2176
  }
1960
- } catch (error) {
1961
- console.error("[ChatInterface] Error fetching chat history:", error);
2177
+ } catch (error2) {
2178
+ console.error("[ChatInterface] Error fetching chat history:", error2);
1962
2179
  } finally {
1963
2180
  setLoadingHistory(false);
1964
2181
  }
@@ -2091,22 +2308,27 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2091
2308
  const renderMessages = () => messages.map((message, index) => {
2092
2309
  const sourceParts = message.parts?.filter((part) => part.type === "source-url") || [];
2093
2310
  const fileParts = message.parts?.filter((part) => part.type === "file") || [];
2094
- return /* @__PURE__ */ jsxs13("div", { className: index > 0 ? "mt-6" : "", children: [
2095
- message.role === "assistant" && sourceParts.length > 0 && /* @__PURE__ */ jsxs13(Sources, { children: [
2096
- /* @__PURE__ */ jsx21(SourcesTrigger, { count: sourceParts.length }),
2097
- sourceParts.map((part, i) => /* @__PURE__ */ jsx21(SourcesContent, { children: /* @__PURE__ */ jsx21(
2311
+ const isLastMessage = index === messages.length - 1;
2312
+ const isStreamingThisMessage = isLastMessage && message.role === "assistant" && status !== "ready";
2313
+ const showActions = message.role === "assistant" && !isStreamingThisMessage;
2314
+ const showRegenerate = showActions && isLastMessage && status === "ready";
2315
+ const messageText = showActions ? (message.parts ?? []).filter((p) => p.type === "text").map((p) => p.text).join("\n\n") : "";
2316
+ return /* @__PURE__ */ jsxs16("div", { className: index > 0 ? "mt-6" : "", children: [
2317
+ message.role === "assistant" && sourceParts.length > 0 && /* @__PURE__ */ jsxs16(Sources, { children: [
2318
+ /* @__PURE__ */ jsx23(SourcesTrigger, { count: sourceParts.length }),
2319
+ /* @__PURE__ */ jsx23(SourcesContent, { children: sourceParts.map((part, i) => /* @__PURE__ */ jsx23(
2098
2320
  Source,
2099
2321
  {
2100
2322
  href: part.url,
2101
2323
  title: part.url
2102
2324
  },
2103
- `${message.id}-${i}`
2104
- ) }, `${message.id}-${i}`))
2325
+ `${message.id}-source-${i}`
2326
+ )) })
2105
2327
  ] }),
2106
- fileParts.length > 0 && /* @__PURE__ */ jsx21("div", { className: cn(
2328
+ fileParts.length > 0 && /* @__PURE__ */ jsx23("div", { className: cn(
2107
2329
  "flex mb-1",
2108
2330
  message.role === "user" ? "justify-end" : "justify-start"
2109
- ), children: /* @__PURE__ */ jsx21(
2331
+ ), children: /* @__PURE__ */ jsx23(
2110
2332
  MessageAttachments,
2111
2333
  {
2112
2334
  attachments: fileParts.map((part) => ({
@@ -2117,14 +2339,14 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2117
2339
  }))
2118
2340
  }
2119
2341
  ) }),
2120
- message.parts ? /* @__PURE__ */ jsx21("div", { className: "space-y-2", children: message.parts.map((part, i) => {
2342
+ message.parts ? /* @__PURE__ */ jsx23("div", { className: "space-y-2", children: message.parts.map((part, i) => {
2121
2343
  switch (part.type) {
2122
2344
  case "text":
2123
2345
  const isTextStreaming = status === "streaming" && i === message.parts.length - 1 && message.id === messages.at(-1)?.id;
2124
- return /* @__PURE__ */ jsx21(Fragment5, { children: /* @__PURE__ */ jsx21(Message, { from: message.role, children: /* @__PURE__ */ jsx21(MessageContent, { children: /* @__PURE__ */ jsx21(Response, { isStreaming: isTextStreaming, children: part.text }) }) }) }, `${message.id}-${i}`);
2346
+ return /* @__PURE__ */ jsx23(Fragment5, { children: /* @__PURE__ */ jsx23(Message, { from: message.role, children: /* @__PURE__ */ jsx23(MessageContent, { children: /* @__PURE__ */ jsx23(Response, { isStreaming: isTextStreaming, children: part.text }) }) }) }, `${message.id}-${i}`);
2125
2347
  case "reasoning":
2126
2348
  const isCurrentlyStreaming = status === "streaming" && i === message.parts.length - 1 && message.id === messages.at(-1)?.id;
2127
- return /* @__PURE__ */ jsxs13(
2349
+ return /* @__PURE__ */ jsxs16(
2128
2350
  Reasoning,
2129
2351
  {
2130
2352
  className: "w-full",
@@ -2132,8 +2354,8 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2132
2354
  defaultOpen: false,
2133
2355
  open: isCurrentlyStreaming ? true : void 0,
2134
2356
  children: [
2135
- /* @__PURE__ */ jsx21(ReasoningTrigger, {}),
2136
- /* @__PURE__ */ jsx21(ReasoningContent, { children: part.text })
2357
+ /* @__PURE__ */ jsx23(ReasoningTrigger, {}),
2358
+ /* @__PURE__ */ jsx23(ReasoningContent, { children: part.text })
2137
2359
  ]
2138
2360
  },
2139
2361
  `${message.id}-${i}`
@@ -2141,8 +2363,24 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2141
2363
  default:
2142
2364
  if (part.type.startsWith("tool-") || part.type === "dynamic-tool") {
2143
2365
  const toolPart = part;
2144
- return /* @__PURE__ */ jsxs13(Tool, { children: [
2145
- /* @__PURE__ */ jsx21(
2366
+ const resolvedToolName = toolPart.toolName ?? (part.type.startsWith("tool-") ? part.type.slice(5) : "");
2367
+ const customRenderer = config?.toolRenderers?.[resolvedToolName];
2368
+ if (customRenderer) {
2369
+ const rendered = customRenderer({
2370
+ type: part.type,
2371
+ toolName: resolvedToolName,
2372
+ toolCallId: toolPart.toolCallId,
2373
+ state: toolPart.state,
2374
+ input: toolPart.input,
2375
+ output: toolPart.output,
2376
+ errorText: toolPart.errorText
2377
+ });
2378
+ if (rendered !== null && rendered !== void 0) {
2379
+ return /* @__PURE__ */ jsx23(Fragment5, { children: rendered }, `${message.id}-${i}`);
2380
+ }
2381
+ }
2382
+ return /* @__PURE__ */ jsxs16(Tool, { children: [
2383
+ /* @__PURE__ */ jsx23(
2146
2384
  ToolHeader,
2147
2385
  {
2148
2386
  type: part.type,
@@ -2150,9 +2388,9 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2150
2388
  state: toolPart.state
2151
2389
  }
2152
2390
  ),
2153
- /* @__PURE__ */ jsxs13(ToolContent, { children: [
2154
- /* @__PURE__ */ jsx21(ToolInput, { input: toolPart.input }),
2155
- /* @__PURE__ */ jsx21(ToolOutput, { output: toolPart.output, errorText: toolPart.errorText })
2391
+ /* @__PURE__ */ jsxs16(ToolContent, { children: [
2392
+ /* @__PURE__ */ jsx23(ToolInput, { input: toolPart.input }),
2393
+ /* @__PURE__ */ jsx23(ToolOutput, { output: toolPart.output, errorText: toolPart.errorText })
2156
2394
  ] })
2157
2395
  ] }, `${message.id}-${i}`);
2158
2396
  }
@@ -2160,7 +2398,14 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2160
2398
  }
2161
2399
  }) }) : (
2162
2400
  /* Handle standard AI SDK messages with content or text property */
2163
- /* @__PURE__ */ jsx21(Fragment5, { children: /* @__PURE__ */ jsx21(Message, { from: message.role, children: /* @__PURE__ */ jsx21(MessageContent, { children: /* @__PURE__ */ jsx21(Response, { children: message.content || message.text }) }) }) }, `${message.id}-content`)
2401
+ /* @__PURE__ */ jsx23(Fragment5, { children: /* @__PURE__ */ jsx23(Message, { from: message.role, children: /* @__PURE__ */ jsx23(MessageContent, { children: /* @__PURE__ */ jsx23(Response, { children: message.content || message.text }) }) }) }, `${message.id}-content`)
2402
+ ),
2403
+ showActions && /* @__PURE__ */ jsx23(
2404
+ MessageActions,
2405
+ {
2406
+ text: messageText,
2407
+ onRegenerate: showRegenerate && regenerate ? () => regenerate() : void 0
2408
+ }
2164
2409
  )
2165
2410
  ] }, message.id);
2166
2411
  });
@@ -2188,8 +2433,8 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2188
2433
  setActiveTabId(selectedConversationId);
2189
2434
  await loadConversation(selectedConversationId);
2190
2435
  setShowHistory(false);
2191
- } catch (error) {
2192
- console.error("Error loading conversation:", error);
2436
+ } catch (error2) {
2437
+ console.error("Error loading conversation:", error2);
2193
2438
  }
2194
2439
  };
2195
2440
  const dropdownRef = useRef4(null);
@@ -2206,7 +2451,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2206
2451
  document.removeEventListener("mousedown", handleClickOutside);
2207
2452
  };
2208
2453
  }, [showHistory]);
2209
- return /* @__PURE__ */ jsx21("div", { className: cn("w-full h-full flex flex-col bg-white dark:bg-gray-900 overflow-hidden ring-1 ring-black/[0.02] dark:ring-white/[0.03]", themeMode === "dark" && "dark"), children: /* @__PURE__ */ jsxs13(
2454
+ return /* @__PURE__ */ jsx23("div", { className: cn("w-full h-full flex flex-col bg-white dark:bg-gray-900 overflow-hidden ring-1 ring-black/[0.02] dark:ring-white/[0.03]", themeMode === "dark" && "dark"), children: /* @__PURE__ */ jsxs16(
2210
2455
  "div",
2211
2456
  {
2212
2457
  className: cn(
@@ -2214,11 +2459,11 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2214
2459
  themeMode === "dark" && "dark"
2215
2460
  ),
2216
2461
  children: [
2217
- /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 px-3 py-2 border-b backdrop-blur-sm relative z-20", style: {
2462
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2 px-3 py-2 border-b backdrop-blur-sm relative z-20", style: {
2218
2463
  borderColor: "var(--chat-divider)",
2219
2464
  backgroundColor: "var(--chat-header-bg)"
2220
2465
  }, children: [
2221
- /* @__PURE__ */ jsx21("div", { className: "flex items-center gap-1 flex-1 min-w-0 overflow-x-auto scrollbar-hide py-0.5 scroll-smooth", children: tabs.map((tab, index) => /* @__PURE__ */ jsxs13(
2466
+ /* @__PURE__ */ jsx23("div", { className: "flex items-center gap-1 flex-1 min-w-0 overflow-x-auto scrollbar-hide py-0.5 scroll-smooth", children: tabs.map((tab, index) => /* @__PURE__ */ jsxs16(
2222
2467
  "div",
2223
2468
  {
2224
2469
  className: "relative flex items-center gap-1.5 px-3 py-1.5 rounded-lg cursor-pointer transition-all duration-150 group flex-shrink-0 min-w-0",
@@ -2241,8 +2486,8 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2241
2486
  switchToTab(tab.id);
2242
2487
  },
2243
2488
  children: [
2244
- /* @__PURE__ */ jsx21("span", { className: "truncate max-w-28 text-[13px] font-medium transition-colors", children: tab.title }),
2245
- tabs.length > 1 && /* @__PURE__ */ jsx21(
2489
+ /* @__PURE__ */ jsx23("span", { className: "truncate max-w-28 text-[13px] font-medium transition-colors", children: tab.title }),
2490
+ tabs.length > 1 && /* @__PURE__ */ jsx23(
2246
2491
  "button",
2247
2492
  {
2248
2493
  onClick: (e) => {
@@ -2261,15 +2506,15 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2261
2506
  e.currentTarget.style.opacity = tab.isActive ? "0.6" : "0";
2262
2507
  e.currentTarget.style.backgroundColor = "transparent";
2263
2508
  },
2264
- children: /* @__PURE__ */ jsx21(XIcon2, { className: "h-3 w-3", strokeWidth: 2.5 })
2509
+ children: /* @__PURE__ */ jsx23(XIcon3, { className: "h-3 w-3", strokeWidth: 2.5 })
2265
2510
  }
2266
2511
  )
2267
2512
  ]
2268
2513
  },
2269
2514
  tab.id
2270
2515
  )) }),
2271
- /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-0.5 flex-shrink-0", children: [
2272
- /* @__PURE__ */ jsx21(
2516
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-0.5 flex-shrink-0", children: [
2517
+ /* @__PURE__ */ jsx23(
2273
2518
  "button",
2274
2519
  {
2275
2520
  onClick: createNewTab,
@@ -2286,11 +2531,11 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2286
2531
  e.currentTarget.style.backgroundColor = "transparent";
2287
2532
  },
2288
2533
  title: "New Chat",
2289
- children: /* @__PURE__ */ jsx21(PlusIcon2, { className: "h-4 w-4", strokeWidth: 2 })
2534
+ children: /* @__PURE__ */ jsx23(PlusIcon2, { className: "h-4 w-4", strokeWidth: 2 })
2290
2535
  }
2291
2536
  ),
2292
- /* @__PURE__ */ jsxs13("div", { className: "relative", ref: dropdownRef, children: [
2293
- /* @__PURE__ */ jsx21(
2537
+ /* @__PURE__ */ jsxs16("div", { className: "relative", ref: dropdownRef, children: [
2538
+ /* @__PURE__ */ jsx23(
2294
2539
  "button",
2295
2540
  {
2296
2541
  onClick: () => setShowHistory(!showHistory),
@@ -2312,17 +2557,17 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2312
2557
  }
2313
2558
  },
2314
2559
  title: "Chat History",
2315
- children: /* @__PURE__ */ jsx21(HistoryIcon, { className: "h-4 w-4", strokeWidth: 2 })
2560
+ children: /* @__PURE__ */ jsx23(HistoryIcon, { className: "h-4 w-4", strokeWidth: 2 })
2316
2561
  }
2317
2562
  ),
2318
- showHistory && /* @__PURE__ */ jsxs13("div", { className: "absolute right-0 top-full mt-1.5 w-72 rounded-xl shadow-[0_4px_24px_rgba(0,0,0,0.08)] dark:shadow-[0_4px_24px_rgba(0,0,0,0.3)] z-50 animate-in fade-in slide-in-from-top-1 duration-150 overflow-hidden", style: {
2563
+ showHistory && /* @__PURE__ */ jsxs16("div", { className: "absolute right-0 top-full mt-1.5 w-72 rounded-xl shadow-[0_4px_24px_rgba(0,0,0,0.08)] dark:shadow-[0_4px_24px_rgba(0,0,0,0.3)] z-50 animate-in fade-in slide-in-from-top-1 duration-150 overflow-hidden", style: {
2319
2564
  backgroundColor: "hsl(var(--chat-background))",
2320
2565
  border: `1px solid ${"var(--chat-divider)"}`
2321
2566
  }, children: [
2322
- /* @__PURE__ */ jsx21("div", { className: "p-2.5 border-b", style: {
2567
+ /* @__PURE__ */ jsx23("div", { className: "p-2.5 border-b", style: {
2323
2568
  borderColor: "var(--chat-divider)",
2324
2569
  backgroundColor: "var(--chat-overlay)"
2325
- }, children: /* @__PURE__ */ jsx21("div", { className: "relative", children: /* @__PURE__ */ jsx21(
2570
+ }, children: /* @__PURE__ */ jsx23("div", { className: "relative", children: /* @__PURE__ */ jsx23(
2326
2571
  "input",
2327
2572
  {
2328
2573
  type: "text",
@@ -2337,25 +2582,25 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2337
2582
  }
2338
2583
  }
2339
2584
  ) }) }),
2340
- /* @__PURE__ */ jsx21("div", { className: "max-h-[300px] overflow-y-auto ai-assistant-scrollbar", children: loadingHistory ? /* @__PURE__ */ jsx21("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx21("div", { className: "text-[13px]", style: { color: "hsl(var(--chat-text-muted))" }, children: "Loading..." }) }) : conversations.length === 0 ? /* @__PURE__ */ jsxs13("div", { className: "flex flex-col items-center justify-center py-12 px-4 text-center", children: [
2341
- /* @__PURE__ */ jsx21("div", { className: "w-12 h-12 rounded-full flex items-center justify-center mb-3", style: {
2585
+ /* @__PURE__ */ jsx23("div", { className: "max-h-[300px] overflow-y-auto ai-assistant-scrollbar", children: loadingHistory ? /* @__PURE__ */ jsx23("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx23("div", { className: "text-[13px]", style: { color: "hsl(var(--chat-text-muted))" }, children: "Loading..." }) }) : conversations.length === 0 ? /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-center justify-center py-12 px-4 text-center", children: [
2586
+ /* @__PURE__ */ jsx23("div", { className: "w-12 h-12 rounded-full flex items-center justify-center mb-3", style: {
2342
2587
  backgroundColor: "hsl(var(--chat-surface))"
2343
- }, children: /* @__PURE__ */ jsx21(MessageSquareIcon, { className: "h-5 w-5", style: { color: "hsl(var(--chat-text-subtle))" }, strokeWidth: 2 }) }),
2344
- /* @__PURE__ */ jsx21("p", { className: "text-[13px] font-medium mb-0.5", style: { color: "hsl(var(--chat-text))" }, children: "No Conversations" }),
2345
- /* @__PURE__ */ jsx21("p", { className: "text-[12px]", style: { color: "hsl(var(--chat-text-muted))" }, children: "Start a new chat to begin" })
2346
- ] }) : groupedConversations.length === 0 ? /* @__PURE__ */ jsxs13("div", { className: "flex flex-col items-center justify-center py-12 px-4 text-center", children: [
2347
- /* @__PURE__ */ jsx21("div", { className: "w-12 h-12 rounded-full flex items-center justify-center mb-3", style: {
2588
+ }, children: /* @__PURE__ */ jsx23(MessageSquareIcon, { className: "h-5 w-5", style: { color: "hsl(var(--chat-text-subtle))" }, strokeWidth: 2 }) }),
2589
+ /* @__PURE__ */ jsx23("p", { className: "text-[13px] font-medium mb-0.5", style: { color: "hsl(var(--chat-text))" }, children: "No Conversations" }),
2590
+ /* @__PURE__ */ jsx23("p", { className: "text-[12px]", style: { color: "hsl(var(--chat-text-muted))" }, children: "Start a new chat to begin" })
2591
+ ] }) : groupedConversations.length === 0 ? /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-center justify-center py-12 px-4 text-center", children: [
2592
+ /* @__PURE__ */ jsx23("div", { className: "w-12 h-12 rounded-full flex items-center justify-center mb-3", style: {
2348
2593
  backgroundColor: "hsl(var(--chat-surface))"
2349
- }, children: /* @__PURE__ */ jsx21(SearchIcon, { className: "h-5 w-5", style: { color: "hsl(var(--chat-text-subtle))" }, strokeWidth: 2 }) }),
2350
- /* @__PURE__ */ jsx21("p", { className: "text-[13px] font-medium mb-0.5", style: { color: "hsl(var(--chat-text))" }, children: "No Results" }),
2351
- /* @__PURE__ */ jsx21("p", { className: "text-[12px]", style: { color: "hsl(var(--chat-text-muted))" }, children: "Try a different search" })
2352
- ] }) : /* @__PURE__ */ jsx21("div", { className: "py-0.5", children: groupedConversations.map(([groupName, groupConversations]) => /* @__PURE__ */ jsxs13("div", { className: "mb-0.5", children: [
2353
- /* @__PURE__ */ jsx21("div", { className: "px-2.5 py-1 sticky top-0 backdrop-blur-sm z-10", style: {
2594
+ }, children: /* @__PURE__ */ jsx23(SearchIcon, { className: "h-5 w-5", style: { color: "hsl(var(--chat-text-subtle))" }, strokeWidth: 2 }) }),
2595
+ /* @__PURE__ */ jsx23("p", { className: "text-[13px] font-medium mb-0.5", style: { color: "hsl(var(--chat-text))" }, children: "No Results" }),
2596
+ /* @__PURE__ */ jsx23("p", { className: "text-[12px]", style: { color: "hsl(var(--chat-text-muted))" }, children: "Try a different search" })
2597
+ ] }) : /* @__PURE__ */ jsx23("div", { className: "py-0.5", children: groupedConversations.map(([groupName, groupConversations]) => /* @__PURE__ */ jsxs16("div", { className: "mb-0.5", children: [
2598
+ /* @__PURE__ */ jsx23("div", { className: "px-2.5 py-1 sticky top-0 backdrop-blur-sm z-10", style: {
2354
2599
  backgroundColor: "var(--chat-header-bg-strong)"
2355
- }, children: /* @__PURE__ */ jsx21("h3", { className: "text-[10px] font-semibold uppercase tracking-wide", style: { color: "hsl(var(--chat-text-muted))" }, children: groupName }) }),
2356
- /* @__PURE__ */ jsx21("div", { className: "px-1 space-y-0.5", children: groupConversations.map((conversation) => {
2600
+ }, children: /* @__PURE__ */ jsx23("h3", { className: "text-[10px] font-semibold uppercase tracking-wide", style: { color: "hsl(var(--chat-text-muted))" }, children: groupName }) }),
2601
+ /* @__PURE__ */ jsx23("div", { className: "px-1 space-y-0.5", children: groupConversations.map((conversation) => {
2357
2602
  const isActiveConversation = activeTabId === conversation.id;
2358
- return /* @__PURE__ */ jsx21(
2603
+ return /* @__PURE__ */ jsx23(
2359
2604
  "button",
2360
2605
  {
2361
2606
  className: "w-full px-2 py-1 rounded-md transition-all duration-150 text-left group relative",
@@ -2373,12 +2618,12 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2373
2618
  }
2374
2619
  },
2375
2620
  onClick: () => handleSelectConversation(conversation.id, conversation.title),
2376
- children: /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1.5", children: [
2377
- /* @__PURE__ */ jsx21("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx21("p", { className: "text-[12px] line-clamp-1 transition-colors leading-tight", style: {
2621
+ children: /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-1.5", children: [
2622
+ /* @__PURE__ */ jsx23("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx23("p", { className: "text-[12px] line-clamp-1 transition-colors leading-tight", style: {
2378
2623
  fontWeight: isActiveConversation ? 500 : 400,
2379
2624
  color: isActiveConversation ? "hsl(var(--chat-text))" : "hsl(var(--chat-text-strong))"
2380
2625
  }, children: conversation.title }) }),
2381
- /* @__PURE__ */ jsx21(
2626
+ /* @__PURE__ */ jsx23(
2382
2627
  ChevronRightIcon2,
2383
2628
  {
2384
2629
  className: "h-3 w-3 transition-all duration-150 flex-shrink-0",
@@ -2398,7 +2643,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2398
2643
  ] })
2399
2644
  ] }),
2400
2645
  headerActions,
2401
- onClose && /* @__PURE__ */ jsx21(
2646
+ onClose && /* @__PURE__ */ jsx23(
2402
2647
  "button",
2403
2648
  {
2404
2649
  onClick: onClose,
@@ -2415,21 +2660,21 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2415
2660
  e.currentTarget.style.backgroundColor = "transparent";
2416
2661
  },
2417
2662
  title: "Close Chat",
2418
- children: /* @__PURE__ */ jsx21(XIcon2, { className: "h-4 w-4", strokeWidth: 2 })
2663
+ children: /* @__PURE__ */ jsx23(XIcon3, { className: "h-4 w-4", strokeWidth: 2 })
2419
2664
  }
2420
2665
  )
2421
2666
  ] })
2422
2667
  ] }),
2423
- /* @__PURE__ */ jsxs13(Conversation, { className: "flex-1 max-w-full ai-assistant-scrollbar", children: [
2424
- /* @__PURE__ */ jsxs13(ConversationContent, { className: "max-w-[96%] mx-auto py-6", children: [
2668
+ /* @__PURE__ */ jsxs16(Conversation, { className: "flex-1 max-w-full ai-assistant-scrollbar", children: [
2669
+ /* @__PURE__ */ jsxs16(ConversationContent, { className: "max-w-[96%] mx-auto py-6", children: [
2425
2670
  renderMessages(),
2426
- status === "submitted" && /* @__PURE__ */ jsx21("div", { className: "mt-6", children: /* @__PURE__ */ jsx21(Message, { from: "assistant", children: /* @__PURE__ */ jsx21(MessageContent, { children: /* @__PURE__ */ jsx21(Loader, { size: 16 }) }) }) })
2671
+ status === "submitted" && /* @__PURE__ */ jsx23("div", { className: "mt-6", children: /* @__PURE__ */ jsx23(Message, { from: "assistant", children: /* @__PURE__ */ jsx23(MessageContent, { children: /* @__PURE__ */ jsx23(Loader, { size: 16 }) }) }) })
2427
2672
  ] }),
2428
- /* @__PURE__ */ jsx21(ConversationScrollButton, {})
2673
+ /* @__PURE__ */ jsx23(ConversationScrollButton, {})
2429
2674
  ] }),
2430
- /* @__PURE__ */ jsxs13("div", { className: "px-5 pb-5", children: [
2431
- uploadError && /* @__PURE__ */ jsx21("div", { className: "mb-3 px-4 py-3 bg-red-50 dark:bg-red-900/20 border border-red-200/60 dark:border-red-800/60 rounded-2xl text-sm text-red-700 dark:text-red-400 shadow-sm", children: uploadError }),
2432
- isInitializing || isLoadingMessages ? /* @__PURE__ */ jsx21("div", { className: "flex items-center justify-center py-8", role: "status", "aria-label": "Loading conversation", children: /* @__PURE__ */ jsx21("div", { className: "h-4 w-4 rounded-full border-2 border-current border-t-transparent animate-spin", style: { color: "hsl(var(--chat-text-muted))" } }) }) : messages.length === 0 && status !== "submitted" && config?.starterPrompts && /* @__PURE__ */ jsx21(
2675
+ /* @__PURE__ */ jsxs16("div", { className: "px-5 pb-5", children: [
2676
+ uploadError && /* @__PURE__ */ jsx23("div", { className: "mb-3 px-4 py-3 bg-red-50 dark:bg-red-900/20 border border-red-200/60 dark:border-red-800/60 rounded-2xl text-sm text-red-700 dark:text-red-400 shadow-sm", children: uploadError }),
2677
+ isInitializing || isLoadingMessages ? /* @__PURE__ */ jsx23("div", { className: "flex items-center justify-center py-8", role: "status", "aria-label": "Loading conversation", children: /* @__PURE__ */ jsx23("div", { className: "h-4 w-4 rounded-full border-2 border-current border-t-transparent animate-spin", style: { color: "hsl(var(--chat-text-muted))" } }) }) : messages.length === 0 && status !== "submitted" && config?.starterPrompts && /* @__PURE__ */ jsx23(
2433
2678
  StarterMessages,
2434
2679
  {
2435
2680
  prompts: config.starterPrompts,
@@ -2438,25 +2683,67 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2438
2683
  }
2439
2684
  }
2440
2685
  ),
2686
+ /* @__PURE__ */ jsx23(
2687
+ ChatErrorBanner,
2688
+ {
2689
+ error: error ?? null,
2690
+ canRetry: messages.some((m) => m.role === "user"),
2691
+ onRetry: () => {
2692
+ clearError?.();
2693
+ regenerate?.();
2694
+ },
2695
+ onDismiss: clearError
2696
+ }
2697
+ ),
2441
2698
  inputPlugins.panel,
2442
- /* @__PURE__ */ jsxs13(PromptInput, { onSubmit: handleSubmit, globalDrop: true, multiple: true, accept: "image/*", children: [
2443
- /* @__PURE__ */ jsxs13(PromptInputBody, { children: [
2444
- /* @__PURE__ */ jsx21(PromptInputAttachments, { children: (attachment) => /* @__PURE__ */ jsx21(PromptInputAttachment, { data: attachment }) }),
2445
- /* @__PURE__ */ jsx21(
2446
- PromptInputTextarea,
2447
- {
2448
- ref: inputRef,
2449
- onChange: (e) => setInput(e.target.value),
2450
- onKeyDown: inputPlugins.onKeyDown,
2451
- value: input
2699
+ /* @__PURE__ */ jsxs16(
2700
+ PromptInput,
2701
+ {
2702
+ onSubmit: handleSubmit,
2703
+ globalDrop: true,
2704
+ multiple: true,
2705
+ accept: config?.features?.fileUploadAccept ?? "image/*",
2706
+ maxFileSize: config?.features?.fileUploadMaxBytes,
2707
+ onError: (err) => {
2708
+ if (err.code === "max_file_size") {
2709
+ setUploadError(
2710
+ config?.features?.fileUploadMaxBytes ? `File too large (max ${Math.floor(
2711
+ config.features.fileUploadMaxBytes / 1024 / 1024
2712
+ )} MB).` : "File too large."
2713
+ );
2714
+ } else if (err.code === "accept") {
2715
+ setUploadError("That file type is not supported.");
2716
+ } else if (err.code === "max_files") {
2717
+ setUploadError("Too many files attached.");
2452
2718
  }
2453
- )
2454
- ] }),
2455
- /* @__PURE__ */ jsxs13(PromptInputToolbar, { children: [
2456
- /* @__PURE__ */ jsx21(PromptInputTools, { children: config?.features?.fileUpload === true && /* @__PURE__ */ jsx21(AttachButton, {}) }),
2457
- /* @__PURE__ */ jsx21(PromptInputSubmit, { disabled: !input, status })
2458
- ] })
2459
- ] })
2719
+ },
2720
+ children: [
2721
+ /* @__PURE__ */ jsxs16(PromptInputBody, { children: [
2722
+ /* @__PURE__ */ jsx23(PromptInputAttachments, { children: (attachment) => /* @__PURE__ */ jsx23(PromptInputAttachment, { data: attachment }) }),
2723
+ /* @__PURE__ */ jsx23(
2724
+ PromptInputTextarea,
2725
+ {
2726
+ ref: inputRef,
2727
+ onChange: (e) => setInput(e.target.value),
2728
+ onKeyDown: inputPlugins.onKeyDown,
2729
+ value: input
2730
+ }
2731
+ )
2732
+ ] }),
2733
+ /* @__PURE__ */ jsxs16(PromptInputToolbar, { children: [
2734
+ /* @__PURE__ */ jsx23(PromptInputTools, { children: config?.features?.fileUpload === true && /* @__PURE__ */ jsx23(AttachButton, {}) }),
2735
+ /* @__PURE__ */ jsx23(
2736
+ PromptInputSubmit,
2737
+ {
2738
+ disabled: status === "streaming" || status === "submitted" ? false : !input,
2739
+ status,
2740
+ onStop: stop
2741
+ }
2742
+ )
2743
+ ] })
2744
+ ]
2745
+ }
2746
+ )
2460
2747
  ] })
2461
2748
  ]
2462
2749
  }
@@ -2502,7 +2789,7 @@ function toHslTripletIfHex(value) {
2502
2789
  }
2503
2790
 
2504
2791
  // src/ChatWidget.tsx
2505
- import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
2792
+ import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
2506
2793
  function ChatWidget({
2507
2794
  userId,
2508
2795
  conversationId,
@@ -2519,14 +2806,15 @@ function ChatWidget({
2519
2806
  headerActions,
2520
2807
  open,
2521
2808
  onOpenChange,
2522
- inputPlugins
2809
+ inputPlugins,
2810
+ toolRenderers
2523
2811
  }) {
2524
2812
  const layout = display?.layout || "popup";
2525
2813
  const isControlled = open !== void 0;
2526
2814
  const showToggleButton = !isControlled && display?.showToggleButton !== false;
2527
2815
  const resizable = layout === "popup" && display?.resizable !== false;
2528
2816
  const size = display?.size || "default";
2529
- const [internalIsOpen, setInternalIsOpen] = useState6(
2817
+ const [internalIsOpen, setInternalIsOpen] = useState7(
2530
2818
  layout !== "popup" ? true : display?.defaultOpen || false
2531
2819
  );
2532
2820
  const isOpen = isControlled ? open : internalIsOpen;
@@ -2537,7 +2825,7 @@ function ChatWidget({
2537
2825
  setInternalIsOpen(next);
2538
2826
  }
2539
2827
  };
2540
- const [isResizing, setIsResizing] = useState6(false);
2828
+ const [isResizing, setIsResizing] = useState7(false);
2541
2829
  const containerRef = useRef5(null);
2542
2830
  const customStyles = useMemo4(() => {
2543
2831
  const styles = {};
@@ -2595,18 +2883,19 @@ function ChatWidget({
2595
2883
  theme,
2596
2884
  features,
2597
2885
  starterPrompts,
2598
- inputPlugins
2599
- }), [userId, model, systemPrompt, temperature, theme, features, starterPrompts, inputPlugins]);
2886
+ inputPlugins,
2887
+ toolRenderers
2888
+ }), [userId, model, systemPrompt, temperature, theme, features, starterPrompts, inputPlugins, toolRenderers]);
2600
2889
  const togglePosition = display?.toggleButtonPosition || { bottom: "24px", right: "24px" };
2601
2890
  const themeClass = theme?.mode === "dark" ? "dark" : "";
2602
2891
  if (layout === "inline") {
2603
- return /* @__PURE__ */ jsx22(ChatStorageProvider, { userId, children: /* @__PURE__ */ jsx22(
2892
+ return /* @__PURE__ */ jsx24(ChatStorageProvider, { userId, children: /* @__PURE__ */ jsx24(
2604
2893
  "div",
2605
2894
  {
2606
2895
  ref: containerRef,
2607
2896
  className: `chat-widget-container chat-widget-inline chat-widget-content ${themeClass} ${className || ""}`,
2608
2897
  style: customStyles,
2609
- children: /* @__PURE__ */ jsx22(
2898
+ children: /* @__PURE__ */ jsx24(
2610
2899
  ChatInterface,
2611
2900
  {
2612
2901
  id: conversationId,
@@ -2620,13 +2909,13 @@ function ChatWidget({
2620
2909
  ) });
2621
2910
  }
2622
2911
  if (layout === "page") {
2623
- return /* @__PURE__ */ jsx22(ChatStorageProvider, { userId, children: /* @__PURE__ */ jsx22(
2912
+ return /* @__PURE__ */ jsx24(ChatStorageProvider, { userId, children: /* @__PURE__ */ jsx24(
2624
2913
  "div",
2625
2914
  {
2626
2915
  ref: containerRef,
2627
2916
  className: `chat-widget-container chat-widget-page chat-widget-content ${themeClass} ${className || ""}`,
2628
2917
  style: customStyles,
2629
- children: /* @__PURE__ */ jsx22(
2918
+ children: /* @__PURE__ */ jsx24(
2630
2919
  ChatInterface,
2631
2920
  {
2632
2921
  id: conversationId,
@@ -2639,18 +2928,18 @@ function ChatWidget({
2639
2928
  }
2640
2929
  ) });
2641
2930
  }
2642
- return /* @__PURE__ */ jsxs14(ChatStorageProvider, { userId, children: [
2643
- showToggleButton && !isOpen && /* @__PURE__ */ jsx22(
2931
+ return /* @__PURE__ */ jsxs17(ChatStorageProvider, { userId, children: [
2932
+ showToggleButton && !isOpen && /* @__PURE__ */ jsx24(
2644
2933
  "button",
2645
2934
  {
2646
2935
  onClick: () => setIsOpen(true),
2647
2936
  className: "fixed z-50 rounded-full bg-primary text-primary-foreground shadow-lg hover:opacity-90 transition-all p-4",
2648
2937
  style: togglePosition,
2649
2938
  "aria-label": "Open chat",
2650
- children: /* @__PURE__ */ jsx22(MessageCircle, { className: "h-6 w-6" })
2939
+ children: /* @__PURE__ */ jsx24(MessageCircle, { className: "h-6 w-6" })
2651
2940
  }
2652
2941
  ),
2653
- isOpen && /* @__PURE__ */ jsxs14(
2942
+ isOpen && /* @__PURE__ */ jsxs17(
2654
2943
  "div",
2655
2944
  {
2656
2945
  ref: containerRef,
@@ -2659,7 +2948,7 @@ function ChatWidget({
2659
2948
  "data-resizing": isResizing,
2660
2949
  style: customStyles,
2661
2950
  children: [
2662
- resizable && /* @__PURE__ */ jsx22(
2951
+ resizable && /* @__PURE__ */ jsx24(
2663
2952
  "div",
2664
2953
  {
2665
2954
  onMouseDown: handleMouseDown,
@@ -2667,7 +2956,7 @@ function ChatWidget({
2667
2956
  "aria-label": "Resize chat widget"
2668
2957
  }
2669
2958
  ),
2670
- /* @__PURE__ */ jsx22("div", { className: "w-full h-full overflow-hidden", children: /* @__PURE__ */ jsx22(
2959
+ /* @__PURE__ */ jsx24("div", { className: "w-full h-full overflow-hidden", children: /* @__PURE__ */ jsx24(
2671
2960
  ChatInterface,
2672
2961
  {
2673
2962
  id: conversationId,
@@ -2688,7 +2977,7 @@ function ChatWidget({
2688
2977
  var ChatWidget_default = ChatWidget;
2689
2978
 
2690
2979
  // src/hooks/use-chat-theme.ts
2691
- import { useState as useState7, useEffect as useEffect7 } from "react";
2980
+ import { useState as useState8, useEffect as useEffect7 } from "react";
2692
2981
 
2693
2982
  // src/utils/models.ts
2694
2983
  var MODELS = [
@@ -2808,12 +3097,12 @@ var defaultThemeMode = "light";
2808
3097
  function useChatTheme() {
2809
3098
  const { storageKeyPrefix } = useChatStorageKey();
2810
3099
  const keyPrefix = storageKeyPrefix ? `chat-${storageKeyPrefix}-` : "chat-";
2811
- const [theme, setTheme] = useState7(defaultTheme);
2812
- const [conversationStarters, setConversationStarters] = useState7(defaultConversationStarters);
2813
- const [model, setModel] = useState7(defaultModel);
2814
- const [systemPrompt, setSystemPrompt] = useState7(defaultSystemPrompt);
2815
- const [temperature, setTemperature] = useState7(defaultTemperature);
2816
- const [themeMode, setThemeMode] = useState7(defaultThemeMode);
3100
+ const [theme, setTheme] = useState8(defaultTheme);
3101
+ const [conversationStarters, setConversationStarters] = useState8(defaultConversationStarters);
3102
+ const [model, setModel] = useState8(defaultModel);
3103
+ const [systemPrompt, setSystemPrompt] = useState8(defaultSystemPrompt);
3104
+ const [temperature, setTemperature] = useState8(defaultTemperature);
3105
+ const [themeMode, setThemeMode] = useState8(defaultThemeMode);
2817
3106
  useEffect7(() => {
2818
3107
  const savedTheme = localStorage.getItem(`${keyPrefix}theme`);
2819
3108
  if (savedTheme) {
@@ -3004,10 +3293,10 @@ function useChatTheme() {
3004
3293
 
3005
3294
  // src/ui/input.tsx
3006
3295
  import * as React3 from "react";
3007
- import { jsx as jsx23 } from "react/jsx-runtime";
3296
+ import { jsx as jsx25 } from "react/jsx-runtime";
3008
3297
  var Input = React3.forwardRef(
3009
3298
  ({ className, type, ...props }, ref) => {
3010
- return /* @__PURE__ */ jsx23(
3299
+ return /* @__PURE__ */ jsx25(
3011
3300
  "input",
3012
3301
  {
3013
3302
  type,
@@ -3025,23 +3314,23 @@ Input.displayName = "Input";
3025
3314
 
3026
3315
  // src/ui/dialog.tsx
3027
3316
  import * as DialogPrimitive from "@radix-ui/react-dialog";
3028
- import { XIcon as XIcon3 } from "lucide-react";
3029
- import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
3317
+ import { XIcon as XIcon4 } from "lucide-react";
3318
+ import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
3030
3319
  function Dialog({
3031
3320
  ...props
3032
3321
  }) {
3033
- return /* @__PURE__ */ jsx24(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
3322
+ return /* @__PURE__ */ jsx26(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
3034
3323
  }
3035
3324
  function DialogPortal({
3036
3325
  ...props
3037
3326
  }) {
3038
- return /* @__PURE__ */ jsx24(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
3327
+ return /* @__PURE__ */ jsx26(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
3039
3328
  }
3040
3329
  function DialogOverlay({
3041
3330
  className,
3042
3331
  ...props
3043
3332
  }) {
3044
- return /* @__PURE__ */ jsx24(
3333
+ return /* @__PURE__ */ jsx26(
3045
3334
  DialogPrimitive.Overlay,
3046
3335
  {
3047
3336
  "data-slot": "dialog-overlay",
@@ -3059,9 +3348,9 @@ function DialogContent({
3059
3348
  showCloseButton = true,
3060
3349
  ...props
3061
3350
  }) {
3062
- return /* @__PURE__ */ jsxs15(DialogPortal, { "data-slot": "dialog-portal", children: [
3063
- /* @__PURE__ */ jsx24(DialogOverlay, {}),
3064
- /* @__PURE__ */ jsxs15(
3351
+ return /* @__PURE__ */ jsxs18(DialogPortal, { "data-slot": "dialog-portal", children: [
3352
+ /* @__PURE__ */ jsx26(DialogOverlay, {}),
3353
+ /* @__PURE__ */ jsxs18(
3065
3354
  DialogPrimitive.Content,
3066
3355
  {
3067
3356
  "data-slot": "dialog-content",
@@ -3072,14 +3361,14 @@ function DialogContent({
3072
3361
  ...props,
3073
3362
  children: [
3074
3363
  children,
3075
- showCloseButton && /* @__PURE__ */ jsxs15(
3364
+ showCloseButton && /* @__PURE__ */ jsxs18(
3076
3365
  DialogPrimitive.Close,
3077
3366
  {
3078
3367
  "data-slot": "dialog-close",
3079
3368
  className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
3080
3369
  children: [
3081
- /* @__PURE__ */ jsx24(XIcon3, {}),
3082
- /* @__PURE__ */ jsx24("span", { className: "sr-only", children: "Close" })
3370
+ /* @__PURE__ */ jsx26(XIcon4, {}),
3371
+ /* @__PURE__ */ jsx26("span", { className: "sr-only", children: "Close" })
3083
3372
  ]
3084
3373
  }
3085
3374
  )
@@ -3089,7 +3378,7 @@ function DialogContent({
3089
3378
  ] });
3090
3379
  }
3091
3380
  function DialogHeader({ className, ...props }) {
3092
- return /* @__PURE__ */ jsx24(
3381
+ return /* @__PURE__ */ jsx26(
3093
3382
  "div",
3094
3383
  {
3095
3384
  "data-slot": "dialog-header",
@@ -3102,7 +3391,7 @@ function DialogTitle({
3102
3391
  className,
3103
3392
  ...props
3104
3393
  }) {
3105
- return /* @__PURE__ */ jsx24(
3394
+ return /* @__PURE__ */ jsx26(
3106
3395
  DialogPrimitive.Title,
3107
3396
  {
3108
3397
  "data-slot": "dialog-title",
@@ -3115,7 +3404,7 @@ function DialogDescription({
3115
3404
  className,
3116
3405
  ...props
3117
3406
  }) {
3118
- return /* @__PURE__ */ jsx24(
3407
+ return /* @__PURE__ */ jsx26(
3119
3408
  DialogPrimitive.Description,
3120
3409
  {
3121
3410
  "data-slot": "dialog-description",
@@ -3136,6 +3425,11 @@ export {
3136
3425
  Input,
3137
3426
  StarterMessageItem,
3138
3427
  StarterMessages,
3428
+ Tool,
3429
+ ToolContent,
3430
+ ToolHeader,
3431
+ ToolInput,
3432
+ ToolOutput,
3139
3433
  ChatWidget_default as default,
3140
3434
  fontOptions,
3141
3435
  useChatStorageKey,