@mordn/chat-widget 0.9.0 → 0.10.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.mjs CHANGED
@@ -560,14 +560,32 @@ var PromptInputBody = ({
560
560
  className,
561
561
  ...props
562
562
  }) => /* @__PURE__ */ jsx8("div", { className: cn(className, "flex flex-col"), ...props });
563
+ var TEXTAREA_MIN_HEIGHT = 28;
564
+ var TEXTAREA_MAX_HEIGHT = 192;
563
565
  var PromptInputTextarea = React2.forwardRef(({
564
566
  onChange,
565
567
  onKeyDown: externalOnKeyDown,
566
568
  className,
567
569
  placeholder = "What would you like to know?",
570
+ value,
568
571
  ...props
569
572
  }, ref) => {
570
573
  const attachments = usePromptInputAttachments();
574
+ const innerRef = useRef(null);
575
+ const setRefs = (node) => {
576
+ innerRef.current = node;
577
+ if (typeof ref === "function") ref(node);
578
+ else if (ref) ref.current = node;
579
+ };
580
+ const resize = () => {
581
+ const el = innerRef.current;
582
+ if (!el) return;
583
+ el.style.height = "auto";
584
+ const next = Math.min(el.scrollHeight, TEXTAREA_MAX_HEIGHT);
585
+ el.style.height = `${Math.max(next, TEXTAREA_MIN_HEIGHT)}px`;
586
+ el.style.overflowY = el.scrollHeight > TEXTAREA_MAX_HEIGHT ? "auto" : "hidden";
587
+ };
588
+ useLayoutEffect(resize, [value]);
571
589
  const handleKeyDown = (e) => {
572
590
  externalOnKeyDown?.(e);
573
591
  if (e.defaultPrevented) return;
@@ -607,17 +625,19 @@ var PromptInputTextarea = React2.forwardRef(({
607
625
  return /* @__PURE__ */ jsx8(
608
626
  Textarea,
609
627
  {
610
- ref,
628
+ ref: setRefs,
629
+ rows: 1,
630
+ value,
611
631
  className: cn(
612
- "w-full resize-none rounded-none border-none p-3 shadow-none outline-none ring-0",
613
- "field-sizing-content",
614
- "max-h-48 min-h-16",
632
+ "w-full resize-none rounded-none border-none px-3 py-2.5 shadow-none outline-none ring-0",
615
633
  "focus-visible:ring-0 focus-visible:shadow-none focus:ring-0 focus:shadow-none",
616
634
  className
617
635
  ),
636
+ style: { minHeight: TEXTAREA_MIN_HEIGHT, maxHeight: TEXTAREA_MAX_HEIGHT, overflowY: "hidden" },
618
637
  name: "message",
619
638
  onChange: (e) => {
620
639
  onChange?.(e);
640
+ resize();
621
641
  },
622
642
  onKeyDown: handleKeyDown,
623
643
  onPaste: handlePaste,
@@ -627,30 +647,6 @@ var PromptInputTextarea = React2.forwardRef(({
627
647
  );
628
648
  });
629
649
  PromptInputTextarea.displayName = "PromptInputTextarea";
630
- var PromptInputToolbar = ({
631
- className,
632
- ...props
633
- }) => /* @__PURE__ */ jsx8(
634
- "div",
635
- {
636
- className: cn("flex items-center justify-between p-1", className),
637
- ...props
638
- }
639
- );
640
- var PromptInputTools = ({
641
- className,
642
- ...props
643
- }) => /* @__PURE__ */ jsx8(
644
- "div",
645
- {
646
- className: cn(
647
- "flex items-center gap-1",
648
- "[&_button:first-child]:rounded-bl-xl",
649
- className
650
- ),
651
- ...props
652
- }
653
- );
654
650
  var PromptInputButton = ({
655
651
  variant = "ghost",
656
652
  className,
@@ -1199,7 +1195,7 @@ function ActionButton({ onClick, disabled, ariaLabel, children }) {
1199
1195
 
1200
1196
  // src/components/interface.tsx
1201
1197
  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";
1198
+ import { HistoryIcon, MessageSquareIcon, SearchIcon, ChevronRightIcon as ChevronRightIcon2, PaperclipIcon as PaperclipIcon2, PlusIcon as PlusIcon2, XIcon as XIcon3 } from "lucide-react";
1203
1199
  import { Fragment as Fragment5 } from "react";
1204
1200
  import { useChat } from "@ai-sdk/react";
1205
1201
  import { DefaultChatTransport } from "ai";
@@ -1906,24 +1902,38 @@ function StarterMessageItem({
1906
1902
  import { createContext as createContext4, useContext as useContext4 } from "react";
1907
1903
  import { jsx as jsx22 } from "react/jsx-runtime";
1908
1904
  var ChatStorageContext = createContext4({
1909
- storageKeyPrefix: ""
1905
+ storageKeyPrefix: null
1910
1906
  });
1911
1907
  function ChatStorageProvider({
1912
1908
  children,
1913
- userId
1909
+ userId,
1910
+ agentId
1914
1911
  }) {
1915
- const storageKeyPrefix = userId || "";
1912
+ const storageKeyPrefix = userId && agentId ? `${encodeURIComponent(agentId)}|${encodeURIComponent(userId)}` : null;
1916
1913
  return /* @__PURE__ */ jsx22(ChatStorageContext.Provider, { value: { storageKeyPrefix }, children });
1917
1914
  }
1918
1915
  function useChatStorageKey() {
1919
1916
  return useContext4(ChatStorageContext);
1920
1917
  }
1918
+ function clearChatStorage(opts) {
1919
+ if (typeof window === "undefined" || !window.localStorage) return;
1920
+ const scopedPrefix = opts?.agentId && opts?.userId ? `chat-${encodeURIComponent(opts.agentId)}|${encodeURIComponent(opts.userId)}-` : null;
1921
+ const toRemove = [];
1922
+ for (let i = 0; i < localStorage.length; i++) {
1923
+ const key = localStorage.key(i);
1924
+ if (!key) continue;
1925
+ if (scopedPrefix ? key.startsWith(scopedPrefix) : key.startsWith("chat-")) {
1926
+ toRemove.push(key);
1927
+ }
1928
+ }
1929
+ toRemove.forEach((key) => localStorage.removeItem(key));
1930
+ }
1921
1931
 
1922
1932
  // src/components/interface.tsx
1923
1933
  import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
1924
1934
  function ChatInterface({ id, initialMessages, config, onClose, headerActions } = {}) {
1925
1935
  const { storageKeyPrefix } = useChatStorageKey();
1926
- const storageKey = (key) => storageKeyPrefix ? `chat-${storageKeyPrefix}-${key}` : `chat-${key}`;
1936
+ const storageKey = (key) => storageKeyPrefix ? `chat-${storageKeyPrefix}-${key}` : null;
1927
1937
  const themeMode = config?.theme?.mode || "light";
1928
1938
  const [input, setInput] = useState6("");
1929
1939
  const inputRef = useRef4(null);
@@ -1955,9 +1965,12 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1955
1965
  const { messages, sendMessage, status, setMessages, stop, regenerate, error, clearError } = useChat({
1956
1966
  id: activeTabId || "temp-id",
1957
1967
  transport: new DefaultChatTransport({
1958
- api: "/api/chat",
1968
+ api: `${config?.apiBase ?? "/api/chat"}`,
1959
1969
  headers: {
1960
- "X-User-Id": config?.userId || ""
1970
+ "X-User-Id": config?.userId || "",
1971
+ // Extra headers the host injects (e.g. the dashboard playground sends
1972
+ // its unsaved draft model/system-prompt for an owner-authed preview).
1973
+ ...config?.extraHeaders ?? {}
1961
1974
  }
1962
1975
  }),
1963
1976
  // Throttle UI updates to 200ms to prevent hanging during streaming
@@ -1981,7 +1994,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1981
1994
  formData.append("file", fileObj);
1982
1995
  formData.append("conversationId", activeTabId || "default");
1983
1996
  formData.append("userId", config?.userId || "demo-user");
1984
- const uploadResponse = await fetch("/api/chat/upload", {
1997
+ const uploadResponse = await fetch(`${config?.apiBase ?? "/api/chat"}/upload`, {
1985
1998
  method: "POST",
1986
1999
  body: formData
1987
2000
  });
@@ -2045,8 +2058,11 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2045
2058
  PromptInputButton,
2046
2059
  {
2047
2060
  variant: "ghost",
2061
+ size: "icon",
2062
+ className: "size-9 rounded-full text-muted-foreground",
2063
+ "aria-label": "Attach files",
2048
2064
  onClick: () => attachments.openFileDialog(),
2049
- children: /* @__PURE__ */ jsx23(PlusIcon2, { className: "size-4" })
2065
+ children: /* @__PURE__ */ jsx23(PaperclipIcon2, { className: "size-4 -rotate-45" })
2050
2066
  }
2051
2067
  );
2052
2068
  };
@@ -2056,7 +2072,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2056
2072
  return;
2057
2073
  }
2058
2074
  try {
2059
- const response = await fetch(`/api/chat/history/${conversationId}?userId=${config.userId}`);
2075
+ const response = await fetch(`${config?.apiBase ?? "/api/chat"}/history/${conversationId}?userId=${config.userId}`);
2060
2076
  if (response.ok) {
2061
2077
  const data = await response.json();
2062
2078
  const loadedMessages = data.messages || [];
@@ -2115,10 +2131,20 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2115
2131
  const startNewConversation = useCallback4(() => {
2116
2132
  createNewTab();
2117
2133
  }, [createNewTab]);
2134
+ const prevPrefixRef = useRef4(storageKeyPrefix);
2118
2135
  useEffect5(() => {
2119
- return () => {
2120
- };
2121
- }, []);
2136
+ const prev = prevPrefixRef.current;
2137
+ if (prev && prev !== storageKeyPrefix) {
2138
+ const stalePrefix = `chat-${prev}-`;
2139
+ const toRemove = [];
2140
+ for (let i = 0; i < localStorage.length; i++) {
2141
+ const k = localStorage.key(i);
2142
+ if (k && k.startsWith(stalePrefix)) toRemove.push(k);
2143
+ }
2144
+ toRemove.forEach((k) => localStorage.removeItem(k));
2145
+ }
2146
+ prevPrefixRef.current = storageKeyPrefix;
2147
+ }, [storageKeyPrefix]);
2122
2148
  const switchToTab = async (tabId) => {
2123
2149
  const targetTab = tabs.find((tab) => tab.id === tabId);
2124
2150
  if (!targetTab) return;
@@ -2149,11 +2175,13 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2149
2175
  } else {
2150
2176
  setTabs(filteredTabs);
2151
2177
  }
2152
- if (filteredTabs.length > 0) {
2153
- localStorage.setItem(storageKey("tabs"), JSON.stringify(filteredTabs));
2178
+ const tabsKey = storageKey("tabs");
2179
+ if (filteredTabs.length > 0 && tabsKey) {
2180
+ localStorage.setItem(tabsKey, JSON.stringify(filteredTabs));
2154
2181
  if (tabId === activeTabId) {
2155
2182
  const newActiveTab = filteredTabs[0];
2156
- localStorage.setItem(storageKey("active-tab-id"), newActiveTab.id);
2183
+ const activeKey = storageKey("active-tab-id");
2184
+ if (activeKey) localStorage.setItem(activeKey, newActiveTab.id);
2157
2185
  }
2158
2186
  }
2159
2187
  };
@@ -2164,7 +2192,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2164
2192
  }
2165
2193
  setLoadingHistory(true);
2166
2194
  try {
2167
- const response = await fetch(`/api/chat/history?userId=${config.userId}`);
2195
+ const response = await fetch(`${config?.apiBase ?? "/api/chat"}/history?userId=${config.userId}`);
2168
2196
  if (response.ok) {
2169
2197
  const data = await response.json();
2170
2198
  setConversations(data.conversations || []);
@@ -2193,29 +2221,38 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2193
2221
  useEffect5(() => {
2194
2222
  if (tabs.length > 0) {
2195
2223
  const timeoutId = setTimeout(() => {
2196
- localStorage.setItem(storageKey("tabs"), JSON.stringify(tabs));
2197
- localStorage.setItem(storageKey("active-tab-id"), activeTabId);
2224
+ const tabsKey = storageKey("tabs");
2225
+ const activeKey = storageKey("active-tab-id");
2226
+ if (tabsKey) localStorage.setItem(tabsKey, JSON.stringify(tabs));
2227
+ if (activeKey) localStorage.setItem(activeKey, activeTabId);
2198
2228
  }, 500);
2199
2229
  return () => clearTimeout(timeoutId);
2200
2230
  }
2201
- }, [tabs, activeTabId, storageKey]);
2231
+ }, [tabs, activeTabId, storageKeyPrefix]);
2202
2232
  useEffect5(() => {
2203
2233
  if (hasInitialized.current) return;
2234
+ const startCleanTab = () => {
2235
+ const initialTabId = `chat-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
2236
+ setTabs([{ id: initialTabId, title: "New Chat", isActive: true }]);
2237
+ setActiveTabId(initialTabId);
2238
+ setInitialTabCreated(true);
2239
+ setIsInitializing(false);
2240
+ };
2241
+ if (!storageKeyPrefix) {
2242
+ if (!initialTabCreated && tabs.length === 0) startCleanTab();
2243
+ return;
2244
+ }
2204
2245
  const loadInitialTabs = () => {
2205
- const savedTabs = localStorage.getItem(storageKey("tabs"));
2206
- const savedActiveTabId = localStorage.getItem(storageKey("active-tab-id"));
2246
+ const savedTabs = localStorage.getItem(`chat-${storageKeyPrefix}-tabs`);
2247
+ const savedActiveTabId = localStorage.getItem(`chat-${storageKeyPrefix}-active-tab-id`);
2207
2248
  if (savedTabs && savedTabs !== "[]") {
2208
2249
  const parsedTabs = JSON.parse(savedTabs);
2209
2250
  setTabs(parsedTabs);
2210
2251
  const activeId = savedActiveTabId || parsedTabs[0]?.id;
2211
2252
  setActiveTabId(activeId);
2212
2253
  setInitialTabCreated(true);
2213
- } else if (!initialTabCreated && tabs.length === 0) {
2214
- const initialTabId = `chat-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
2215
- setTabs([{ id: initialTabId, title: "New Chat", isActive: true }]);
2216
- setActiveTabId(initialTabId);
2217
- setInitialTabCreated(true);
2218
- setIsInitializing(false);
2254
+ } else if (tabs.length === 0) {
2255
+ startCleanTab();
2219
2256
  }
2220
2257
  };
2221
2258
  try {
@@ -2225,11 +2262,12 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2225
2262
  setIsInitializing(false);
2226
2263
  }
2227
2264
  hasInitialized.current = true;
2228
- }, []);
2265
+ }, [storageKeyPrefix]);
2229
2266
  const hasLoadedInitialMessages = useRef4(false);
2230
2267
  useEffect5(() => {
2231
2268
  if (hasLoadedInitialMessages.current) return;
2232
2269
  if (!config?.userId) return;
2270
+ if (!storageKeyPrefix) return;
2233
2271
  if (!activeTabId) return;
2234
2272
  (async () => {
2235
2273
  try {
@@ -2239,7 +2277,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2239
2277
  setIsInitializing(false);
2240
2278
  }
2241
2279
  })();
2242
- }, [config?.userId, activeTabId]);
2280
+ }, [config?.userId, activeTabId, storageKeyPrefix]);
2243
2281
  useEffect5(() => {
2244
2282
  if (isInitializing) return;
2245
2283
  if (activeTabId && tabs.length > 0 && activeTabId !== lastSyncedTabId.current) {
@@ -2696,7 +2734,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2696
2734
  }
2697
2735
  ),
2698
2736
  inputPlugins.panel,
2699
- /* @__PURE__ */ jsxs16(
2737
+ /* @__PURE__ */ jsx23(
2700
2738
  PromptInput,
2701
2739
  {
2702
2740
  onSubmit: handleSubmit,
@@ -2717,31 +2755,31 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2717
2755
  setUploadError("Too many files attached.");
2718
2756
  }
2719
2757
  },
2720
- children: [
2721
- /* @__PURE__ */ jsxs16(PromptInputBody, { children: [
2722
- /* @__PURE__ */ jsx23(PromptInputAttachments, { children: (attachment) => /* @__PURE__ */ jsx23(PromptInputAttachment, { data: attachment }) }),
2758
+ children: /* @__PURE__ */ jsxs16(PromptInputBody, { children: [
2759
+ /* @__PURE__ */ jsx23(PromptInputAttachments, { children: (attachment) => /* @__PURE__ */ jsx23(PromptInputAttachment, { data: attachment }) }),
2760
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-end gap-1.5 px-2 py-2", children: [
2761
+ config?.features?.fileUpload === true && /* @__PURE__ */ jsx23(AttachButton, {}),
2723
2762
  /* @__PURE__ */ jsx23(
2724
2763
  PromptInputTextarea,
2725
2764
  {
2726
2765
  ref: inputRef,
2727
2766
  onChange: (e) => setInput(e.target.value),
2728
2767
  onKeyDown: inputPlugins.onKeyDown,
2729
- value: input
2768
+ value: input,
2769
+ className: "min-h-0 flex-1 px-1 py-1.5 leading-7"
2730
2770
  }
2731
- )
2732
- ] }),
2733
- /* @__PURE__ */ jsxs16(PromptInputToolbar, { children: [
2734
- /* @__PURE__ */ jsx23(PromptInputTools, { children: config?.features?.fileUpload === true && /* @__PURE__ */ jsx23(AttachButton, {}) }),
2771
+ ),
2735
2772
  /* @__PURE__ */ jsx23(
2736
2773
  PromptInputSubmit,
2737
2774
  {
2775
+ className: "size-9 rounded-full p-0 [&_svg]:size-4",
2738
2776
  disabled: status === "streaming" || status === "submitted" ? false : !input,
2739
2777
  status,
2740
2778
  onStop: stop
2741
2779
  }
2742
2780
  )
2743
2781
  ] })
2744
- ]
2782
+ ] })
2745
2783
  }
2746
2784
  )
2747
2785
  ] })
@@ -2792,6 +2830,10 @@ function toHslTripletIfHex(value) {
2792
2830
  import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
2793
2831
  function ChatWidget({
2794
2832
  userId,
2833
+ agentId,
2834
+ apiBase,
2835
+ extraHeaders,
2836
+ widgetId,
2795
2837
  conversationId,
2796
2838
  initialMessages,
2797
2839
  className,
@@ -2809,6 +2851,7 @@ function ChatWidget({
2809
2851
  inputPlugins,
2810
2852
  toolRenderers
2811
2853
  }) {
2854
+ const effectiveAgentId = agentId ?? widgetId;
2812
2855
  const layout = display?.layout || "popup";
2813
2856
  const isControlled = open !== void 0;
2814
2857
  const showToggleButton = !isControlled && display?.showToggleButton !== false;
@@ -2877,6 +2920,8 @@ function ChatWidget({
2877
2920
  }, [isResizing]);
2878
2921
  const config = useMemo4(() => ({
2879
2922
  userId,
2923
+ apiBase: apiBase ?? "/api/chat",
2924
+ extraHeaders,
2880
2925
  model,
2881
2926
  systemPrompt,
2882
2927
  temperature,
@@ -2885,11 +2930,11 @@ function ChatWidget({
2885
2930
  starterPrompts,
2886
2931
  inputPlugins,
2887
2932
  toolRenderers
2888
- }), [userId, model, systemPrompt, temperature, theme, features, starterPrompts, inputPlugins, toolRenderers]);
2933
+ }), [userId, apiBase, extraHeaders, model, systemPrompt, temperature, theme, features, starterPrompts, inputPlugins, toolRenderers]);
2889
2934
  const togglePosition = display?.toggleButtonPosition || { bottom: "24px", right: "24px" };
2890
2935
  const themeClass = theme?.mode === "dark" ? "dark" : "";
2891
2936
  if (layout === "inline") {
2892
- return /* @__PURE__ */ jsx24(ChatStorageProvider, { userId, children: /* @__PURE__ */ jsx24(
2937
+ return /* @__PURE__ */ jsx24(ChatStorageProvider, { userId, agentId: effectiveAgentId, children: /* @__PURE__ */ jsx24(
2893
2938
  "div",
2894
2939
  {
2895
2940
  ref: containerRef,
@@ -2909,7 +2954,7 @@ function ChatWidget({
2909
2954
  ) });
2910
2955
  }
2911
2956
  if (layout === "page") {
2912
- return /* @__PURE__ */ jsx24(ChatStorageProvider, { userId, children: /* @__PURE__ */ jsx24(
2957
+ return /* @__PURE__ */ jsx24(ChatStorageProvider, { userId, agentId: effectiveAgentId, children: /* @__PURE__ */ jsx24(
2913
2958
  "div",
2914
2959
  {
2915
2960
  ref: containerRef,
@@ -2928,7 +2973,7 @@ function ChatWidget({
2928
2973
  }
2929
2974
  ) });
2930
2975
  }
2931
- return /* @__PURE__ */ jsxs17(ChatStorageProvider, { userId, children: [
2976
+ return /* @__PURE__ */ jsxs17(ChatStorageProvider, { userId, agentId: effectiveAgentId, children: [
2932
2977
  showToggleButton && !isOpen && /* @__PURE__ */ jsx24(
2933
2978
  "button",
2934
2979
  {
@@ -3025,7 +3070,6 @@ var MODELS = [
3025
3070
  value: "google/gemini-2.5-pro"
3026
3071
  }
3027
3072
  ];
3028
- var DEFAULT_MODEL = MODELS[0].value;
3029
3073
 
3030
3074
  // src/hooks/use-chat-theme.ts
3031
3075
  function hexToHSL(hex) {
@@ -3090,13 +3134,13 @@ var defaultConversationStarters = [
3090
3134
  { text: "What features does this product offer?", enabled: true },
3091
3135
  { text: "Tell me about your capabilities", enabled: true }
3092
3136
  ];
3093
- var defaultModel = DEFAULT_MODEL;
3137
+ var defaultModel = MODELS[0].value;
3094
3138
  var defaultSystemPrompt = "You are a helpful AI assistant.";
3095
3139
  var defaultTemperature = 0.7;
3096
3140
  var defaultThemeMode = "light";
3097
3141
  function useChatTheme() {
3098
3142
  const { storageKeyPrefix } = useChatStorageKey();
3099
- const keyPrefix = storageKeyPrefix ? `chat-${storageKeyPrefix}-` : "chat-";
3143
+ const keyPrefix = storageKeyPrefix ? `chat-${storageKeyPrefix}-` : null;
3100
3144
  const [theme, setTheme] = useState8(defaultTheme);
3101
3145
  const [conversationStarters, setConversationStarters] = useState8(defaultConversationStarters);
3102
3146
  const [model, setModel] = useState8(defaultModel);
@@ -3104,6 +3148,7 @@ function useChatTheme() {
3104
3148
  const [temperature, setTemperature] = useState8(defaultTemperature);
3105
3149
  const [themeMode, setThemeMode] = useState8(defaultThemeMode);
3106
3150
  useEffect7(() => {
3151
+ if (!keyPrefix) return;
3107
3152
  const savedTheme = localStorage.getItem(`${keyPrefix}theme`);
3108
3153
  if (savedTheme) {
3109
3154
  try {
@@ -3192,7 +3237,7 @@ function useChatTheme() {
3192
3237
  };
3193
3238
  }, [keyPrefix]);
3194
3239
  useEffect7(() => {
3195
- localStorage.setItem(`${keyPrefix}theme`, JSON.stringify(theme));
3240
+ if (keyPrefix) localStorage.setItem(`${keyPrefix}theme`, JSON.stringify(theme));
3196
3241
  const root = document.documentElement;
3197
3242
  if (themeMode === "light") {
3198
3243
  root.style.setProperty("--chat-primary", hexToHSL(theme.lightPrimary));
@@ -3208,23 +3253,23 @@ function useChatTheme() {
3208
3253
  window.dispatchEvent(new CustomEvent("chat-theme-change", { detail: theme }));
3209
3254
  }, [theme, themeMode, keyPrefix]);
3210
3255
  useEffect7(() => {
3211
- localStorage.setItem(`${keyPrefix}conversation-starters`, JSON.stringify(conversationStarters));
3256
+ if (keyPrefix) localStorage.setItem(`${keyPrefix}conversation-starters`, JSON.stringify(conversationStarters));
3212
3257
  window.dispatchEvent(new CustomEvent("chat-starters-change", { detail: conversationStarters }));
3213
3258
  }, [conversationStarters, keyPrefix]);
3214
3259
  useEffect7(() => {
3215
- localStorage.setItem(`${keyPrefix}model`, model);
3260
+ if (keyPrefix) localStorage.setItem(`${keyPrefix}model`, model);
3216
3261
  window.dispatchEvent(new CustomEvent("chat-model-change", { detail: model }));
3217
3262
  }, [model, keyPrefix]);
3218
3263
  useEffect7(() => {
3219
- localStorage.setItem(`${keyPrefix}system-prompt`, systemPrompt);
3264
+ if (keyPrefix) localStorage.setItem(`${keyPrefix}system-prompt`, systemPrompt);
3220
3265
  window.dispatchEvent(new CustomEvent("chat-system-prompt-change", { detail: systemPrompt }));
3221
3266
  }, [systemPrompt, keyPrefix]);
3222
3267
  useEffect7(() => {
3223
- localStorage.setItem(`${keyPrefix}temperature`, temperature.toString());
3268
+ if (keyPrefix) localStorage.setItem(`${keyPrefix}temperature`, temperature.toString());
3224
3269
  window.dispatchEvent(new CustomEvent("chat-temperature-change", { detail: temperature }));
3225
3270
  }, [temperature, keyPrefix]);
3226
3271
  useEffect7(() => {
3227
- localStorage.setItem(`${keyPrefix}theme-mode`, themeMode);
3272
+ if (keyPrefix) localStorage.setItem(`${keyPrefix}theme-mode`, themeMode);
3228
3273
  window.dispatchEvent(new CustomEvent("chat-theme-mode-change", { detail: themeMode }));
3229
3274
  }, [themeMode, keyPrefix]);
3230
3275
  const updateColor = (key, value) => {
@@ -3430,6 +3475,7 @@ export {
3430
3475
  ToolHeader,
3431
3476
  ToolInput,
3432
3477
  ToolOutput,
3478
+ clearChatStorage,
3433
3479
  ChatWidget_default as default,
3434
3480
  fontOptions,
3435
3481
  useChatStorageKey,