@mordn/chat-widget 0.8.1 → 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.js CHANGED
@@ -48,6 +48,7 @@ __export(src_exports, {
48
48
  ToolHeader: () => ToolHeader,
49
49
  ToolInput: () => ToolInput,
50
50
  ToolOutput: () => ToolOutput,
51
+ clearChatStorage: () => clearChatStorage,
51
52
  default: () => ChatWidget_default,
52
53
  fontOptions: () => fontOptions,
53
54
  useChatStorageKey: () => useChatStorageKey,
@@ -592,14 +593,32 @@ var PromptInputBody = ({
592
593
  className,
593
594
  ...props
594
595
  }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn(className, "flex flex-col"), ...props });
596
+ var TEXTAREA_MIN_HEIGHT = 28;
597
+ var TEXTAREA_MAX_HEIGHT = 192;
595
598
  var PromptInputTextarea = import_react2.default.forwardRef(({
596
599
  onChange,
597
600
  onKeyDown: externalOnKeyDown,
598
601
  className,
599
602
  placeholder = "What would you like to know?",
603
+ value,
600
604
  ...props
601
605
  }, ref) => {
602
606
  const attachments = usePromptInputAttachments();
607
+ const innerRef = (0, import_react2.useRef)(null);
608
+ const setRefs = (node) => {
609
+ innerRef.current = node;
610
+ if (typeof ref === "function") ref(node);
611
+ else if (ref) ref.current = node;
612
+ };
613
+ const resize = () => {
614
+ const el = innerRef.current;
615
+ if (!el) return;
616
+ el.style.height = "auto";
617
+ const next = Math.min(el.scrollHeight, TEXTAREA_MAX_HEIGHT);
618
+ el.style.height = `${Math.max(next, TEXTAREA_MIN_HEIGHT)}px`;
619
+ el.style.overflowY = el.scrollHeight > TEXTAREA_MAX_HEIGHT ? "auto" : "hidden";
620
+ };
621
+ (0, import_react2.useLayoutEffect)(resize, [value]);
603
622
  const handleKeyDown = (e) => {
604
623
  externalOnKeyDown?.(e);
605
624
  if (e.defaultPrevented) return;
@@ -639,17 +658,19 @@ var PromptInputTextarea = import_react2.default.forwardRef(({
639
658
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
640
659
  Textarea,
641
660
  {
642
- ref,
661
+ ref: setRefs,
662
+ rows: 1,
663
+ value,
643
664
  className: cn(
644
- "w-full resize-none rounded-none border-none p-3 shadow-none outline-none ring-0",
645
- "field-sizing-content",
646
- "max-h-48 min-h-16",
665
+ "w-full resize-none rounded-none border-none px-3 py-2.5 shadow-none outline-none ring-0",
647
666
  "focus-visible:ring-0 focus-visible:shadow-none focus:ring-0 focus:shadow-none",
648
667
  className
649
668
  ),
669
+ style: { minHeight: TEXTAREA_MIN_HEIGHT, maxHeight: TEXTAREA_MAX_HEIGHT, overflowY: "hidden" },
650
670
  name: "message",
651
671
  onChange: (e) => {
652
672
  onChange?.(e);
673
+ resize();
653
674
  },
654
675
  onKeyDown: handleKeyDown,
655
676
  onPaste: handlePaste,
@@ -659,30 +680,6 @@ var PromptInputTextarea = import_react2.default.forwardRef(({
659
680
  );
660
681
  });
661
682
  PromptInputTextarea.displayName = "PromptInputTextarea";
662
- var PromptInputToolbar = ({
663
- className,
664
- ...props
665
- }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
666
- "div",
667
- {
668
- className: cn("flex items-center justify-between p-1", className),
669
- ...props
670
- }
671
- );
672
- var PromptInputTools = ({
673
- className,
674
- ...props
675
- }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
676
- "div",
677
- {
678
- className: cn(
679
- "flex items-center gap-1",
680
- "[&_button:first-child]:rounded-bl-xl",
681
- className
682
- ),
683
- ...props
684
- }
685
- );
686
683
  var PromptInputButton = ({
687
684
  variant = "ghost",
688
685
  className,
@@ -1923,24 +1920,38 @@ function StarterMessageItem({
1923
1920
  var import_react10 = require("react");
1924
1921
  var import_jsx_runtime22 = require("react/jsx-runtime");
1925
1922
  var ChatStorageContext = (0, import_react10.createContext)({
1926
- storageKeyPrefix: ""
1923
+ storageKeyPrefix: null
1927
1924
  });
1928
1925
  function ChatStorageProvider({
1929
1926
  children,
1930
- userId
1927
+ userId,
1928
+ agentId
1931
1929
  }) {
1932
- const storageKeyPrefix = userId || "";
1930
+ const storageKeyPrefix = userId && agentId ? `${encodeURIComponent(agentId)}|${encodeURIComponent(userId)}` : null;
1933
1931
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ChatStorageContext.Provider, { value: { storageKeyPrefix }, children });
1934
1932
  }
1935
1933
  function useChatStorageKey() {
1936
1934
  return (0, import_react10.useContext)(ChatStorageContext);
1937
1935
  }
1936
+ function clearChatStorage(opts) {
1937
+ if (typeof window === "undefined" || !window.localStorage) return;
1938
+ const scopedPrefix = opts?.agentId && opts?.userId ? `chat-${encodeURIComponent(opts.agentId)}|${encodeURIComponent(opts.userId)}-` : null;
1939
+ const toRemove = [];
1940
+ for (let i = 0; i < localStorage.length; i++) {
1941
+ const key = localStorage.key(i);
1942
+ if (!key) continue;
1943
+ if (scopedPrefix ? key.startsWith(scopedPrefix) : key.startsWith("chat-")) {
1944
+ toRemove.push(key);
1945
+ }
1946
+ }
1947
+ toRemove.forEach((key) => localStorage.removeItem(key));
1948
+ }
1938
1949
 
1939
1950
  // src/components/interface.tsx
1940
1951
  var import_jsx_runtime23 = require("react/jsx-runtime");
1941
1952
  function ChatInterface({ id, initialMessages, config, onClose, headerActions } = {}) {
1942
1953
  const { storageKeyPrefix } = useChatStorageKey();
1943
- const storageKey = (key) => storageKeyPrefix ? `chat-${storageKeyPrefix}-${key}` : `chat-${key}`;
1954
+ const storageKey = (key) => storageKeyPrefix ? `chat-${storageKeyPrefix}-${key}` : null;
1944
1955
  const themeMode = config?.theme?.mode || "light";
1945
1956
  const [input, setInput] = (0, import_react11.useState)("");
1946
1957
  const inputRef = (0, import_react11.useRef)(null);
@@ -1972,9 +1983,12 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1972
1983
  const { messages, sendMessage, status, setMessages, stop, regenerate, error, clearError } = (0, import_react13.useChat)({
1973
1984
  id: activeTabId || "temp-id",
1974
1985
  transport: new import_ai.DefaultChatTransport({
1975
- api: "/api/chat",
1986
+ api: `${config?.apiBase ?? "/api/chat"}`,
1976
1987
  headers: {
1977
- "X-User-Id": config?.userId || ""
1988
+ "X-User-Id": config?.userId || "",
1989
+ // Extra headers the host injects (e.g. the dashboard playground sends
1990
+ // its unsaved draft model/system-prompt for an owner-authed preview).
1991
+ ...config?.extraHeaders ?? {}
1978
1992
  }
1979
1993
  }),
1980
1994
  // Throttle UI updates to 200ms to prevent hanging during streaming
@@ -1998,7 +2012,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1998
2012
  formData.append("file", fileObj);
1999
2013
  formData.append("conversationId", activeTabId || "default");
2000
2014
  formData.append("userId", config?.userId || "demo-user");
2001
- const uploadResponse = await fetch("/api/chat/upload", {
2015
+ const uploadResponse = await fetch(`${config?.apiBase ?? "/api/chat"}/upload`, {
2002
2016
  method: "POST",
2003
2017
  body: formData
2004
2018
  });
@@ -2062,8 +2076,11 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2062
2076
  PromptInputButton,
2063
2077
  {
2064
2078
  variant: "ghost",
2079
+ size: "icon",
2080
+ className: "size-9 rounded-full text-muted-foreground",
2081
+ "aria-label": "Attach files",
2065
2082
  onClick: () => attachments.openFileDialog(),
2066
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react12.PlusIcon, { className: "size-4" })
2083
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react12.PaperclipIcon, { className: "size-4 -rotate-45" })
2067
2084
  }
2068
2085
  );
2069
2086
  };
@@ -2073,7 +2090,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2073
2090
  return;
2074
2091
  }
2075
2092
  try {
2076
- const response = await fetch(`/api/chat/history/${conversationId}?userId=${config.userId}`);
2093
+ const response = await fetch(`${config?.apiBase ?? "/api/chat"}/history/${conversationId}?userId=${config.userId}`);
2077
2094
  if (response.ok) {
2078
2095
  const data = await response.json();
2079
2096
  const loadedMessages = data.messages || [];
@@ -2132,10 +2149,20 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2132
2149
  const startNewConversation = (0, import_react11.useCallback)(() => {
2133
2150
  createNewTab();
2134
2151
  }, [createNewTab]);
2152
+ const prevPrefixRef = (0, import_react11.useRef)(storageKeyPrefix);
2135
2153
  (0, import_react11.useEffect)(() => {
2136
- return () => {
2137
- };
2138
- }, []);
2154
+ const prev = prevPrefixRef.current;
2155
+ if (prev && prev !== storageKeyPrefix) {
2156
+ const stalePrefix = `chat-${prev}-`;
2157
+ const toRemove = [];
2158
+ for (let i = 0; i < localStorage.length; i++) {
2159
+ const k = localStorage.key(i);
2160
+ if (k && k.startsWith(stalePrefix)) toRemove.push(k);
2161
+ }
2162
+ toRemove.forEach((k) => localStorage.removeItem(k));
2163
+ }
2164
+ prevPrefixRef.current = storageKeyPrefix;
2165
+ }, [storageKeyPrefix]);
2139
2166
  const switchToTab = async (tabId) => {
2140
2167
  const targetTab = tabs.find((tab) => tab.id === tabId);
2141
2168
  if (!targetTab) return;
@@ -2166,11 +2193,13 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2166
2193
  } else {
2167
2194
  setTabs(filteredTabs);
2168
2195
  }
2169
- if (filteredTabs.length > 0) {
2170
- localStorage.setItem(storageKey("tabs"), JSON.stringify(filteredTabs));
2196
+ const tabsKey = storageKey("tabs");
2197
+ if (filteredTabs.length > 0 && tabsKey) {
2198
+ localStorage.setItem(tabsKey, JSON.stringify(filteredTabs));
2171
2199
  if (tabId === activeTabId) {
2172
2200
  const newActiveTab = filteredTabs[0];
2173
- localStorage.setItem(storageKey("active-tab-id"), newActiveTab.id);
2201
+ const activeKey = storageKey("active-tab-id");
2202
+ if (activeKey) localStorage.setItem(activeKey, newActiveTab.id);
2174
2203
  }
2175
2204
  }
2176
2205
  };
@@ -2181,7 +2210,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2181
2210
  }
2182
2211
  setLoadingHistory(true);
2183
2212
  try {
2184
- const response = await fetch(`/api/chat/history?userId=${config.userId}`);
2213
+ const response = await fetch(`${config?.apiBase ?? "/api/chat"}/history?userId=${config.userId}`);
2185
2214
  if (response.ok) {
2186
2215
  const data = await response.json();
2187
2216
  setConversations(data.conversations || []);
@@ -2210,29 +2239,38 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2210
2239
  (0, import_react11.useEffect)(() => {
2211
2240
  if (tabs.length > 0) {
2212
2241
  const timeoutId = setTimeout(() => {
2213
- localStorage.setItem(storageKey("tabs"), JSON.stringify(tabs));
2214
- localStorage.setItem(storageKey("active-tab-id"), activeTabId);
2242
+ const tabsKey = storageKey("tabs");
2243
+ const activeKey = storageKey("active-tab-id");
2244
+ if (tabsKey) localStorage.setItem(tabsKey, JSON.stringify(tabs));
2245
+ if (activeKey) localStorage.setItem(activeKey, activeTabId);
2215
2246
  }, 500);
2216
2247
  return () => clearTimeout(timeoutId);
2217
2248
  }
2218
- }, [tabs, activeTabId, storageKey]);
2249
+ }, [tabs, activeTabId, storageKeyPrefix]);
2219
2250
  (0, import_react11.useEffect)(() => {
2220
2251
  if (hasInitialized.current) return;
2252
+ const startCleanTab = () => {
2253
+ const initialTabId = `chat-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
2254
+ setTabs([{ id: initialTabId, title: "New Chat", isActive: true }]);
2255
+ setActiveTabId(initialTabId);
2256
+ setInitialTabCreated(true);
2257
+ setIsInitializing(false);
2258
+ };
2259
+ if (!storageKeyPrefix) {
2260
+ if (!initialTabCreated && tabs.length === 0) startCleanTab();
2261
+ return;
2262
+ }
2221
2263
  const loadInitialTabs = () => {
2222
- const savedTabs = localStorage.getItem(storageKey("tabs"));
2223
- const savedActiveTabId = localStorage.getItem(storageKey("active-tab-id"));
2264
+ const savedTabs = localStorage.getItem(`chat-${storageKeyPrefix}-tabs`);
2265
+ const savedActiveTabId = localStorage.getItem(`chat-${storageKeyPrefix}-active-tab-id`);
2224
2266
  if (savedTabs && savedTabs !== "[]") {
2225
2267
  const parsedTabs = JSON.parse(savedTabs);
2226
2268
  setTabs(parsedTabs);
2227
2269
  const activeId = savedActiveTabId || parsedTabs[0]?.id;
2228
2270
  setActiveTabId(activeId);
2229
2271
  setInitialTabCreated(true);
2230
- } else if (!initialTabCreated && tabs.length === 0) {
2231
- const initialTabId = `chat-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
2232
- setTabs([{ id: initialTabId, title: "New Chat", isActive: true }]);
2233
- setActiveTabId(initialTabId);
2234
- setInitialTabCreated(true);
2235
- setIsInitializing(false);
2272
+ } else if (tabs.length === 0) {
2273
+ startCleanTab();
2236
2274
  }
2237
2275
  };
2238
2276
  try {
@@ -2242,11 +2280,12 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2242
2280
  setIsInitializing(false);
2243
2281
  }
2244
2282
  hasInitialized.current = true;
2245
- }, []);
2283
+ }, [storageKeyPrefix]);
2246
2284
  const hasLoadedInitialMessages = (0, import_react11.useRef)(false);
2247
2285
  (0, import_react11.useEffect)(() => {
2248
2286
  if (hasLoadedInitialMessages.current) return;
2249
2287
  if (!config?.userId) return;
2288
+ if (!storageKeyPrefix) return;
2250
2289
  if (!activeTabId) return;
2251
2290
  (async () => {
2252
2291
  try {
@@ -2256,7 +2295,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2256
2295
  setIsInitializing(false);
2257
2296
  }
2258
2297
  })();
2259
- }, [config?.userId, activeTabId]);
2298
+ }, [config?.userId, activeTabId, storageKeyPrefix]);
2260
2299
  (0, import_react11.useEffect)(() => {
2261
2300
  if (isInitializing) return;
2262
2301
  if (activeTabId && tabs.length > 0 && activeTabId !== lastSyncedTabId.current) {
@@ -2713,7 +2752,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2713
2752
  }
2714
2753
  ),
2715
2754
  inputPlugins.panel,
2716
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
2755
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2717
2756
  PromptInput,
2718
2757
  {
2719
2758
  onSubmit: handleSubmit,
@@ -2734,31 +2773,31 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2734
2773
  setUploadError("Too many files attached.");
2735
2774
  }
2736
2775
  },
2737
- children: [
2738
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(PromptInputBody, { children: [
2739
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PromptInputAttachments, { children: (attachment) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PromptInputAttachment, { data: attachment }) }),
2776
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(PromptInputBody, { children: [
2777
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PromptInputAttachments, { children: (attachment) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PromptInputAttachment, { data: attachment }) }),
2778
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-end gap-1.5 px-2 py-2", children: [
2779
+ config?.features?.fileUpload === true && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(AttachButton, {}),
2740
2780
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2741
2781
  PromptInputTextarea,
2742
2782
  {
2743
2783
  ref: inputRef,
2744
2784
  onChange: (e) => setInput(e.target.value),
2745
2785
  onKeyDown: inputPlugins.onKeyDown,
2746
- value: input
2786
+ value: input,
2787
+ className: "min-h-0 flex-1 px-1 py-1.5 leading-7"
2747
2788
  }
2748
- )
2749
- ] }),
2750
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(PromptInputToolbar, { children: [
2751
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PromptInputTools, { children: config?.features?.fileUpload === true && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(AttachButton, {}) }),
2789
+ ),
2752
2790
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2753
2791
  PromptInputSubmit,
2754
2792
  {
2793
+ className: "size-9 rounded-full p-0 [&_svg]:size-4",
2755
2794
  disabled: status === "streaming" || status === "submitted" ? false : !input,
2756
2795
  status,
2757
2796
  onStop: stop
2758
2797
  }
2759
2798
  )
2760
2799
  ] })
2761
- ]
2800
+ ] })
2762
2801
  }
2763
2802
  )
2764
2803
  ] })
@@ -2809,6 +2848,10 @@ function toHslTripletIfHex(value) {
2809
2848
  var import_jsx_runtime24 = require("react/jsx-runtime");
2810
2849
  function ChatWidget({
2811
2850
  userId,
2851
+ agentId,
2852
+ apiBase,
2853
+ extraHeaders,
2854
+ widgetId,
2812
2855
  conversationId,
2813
2856
  initialMessages,
2814
2857
  className,
@@ -2826,6 +2869,7 @@ function ChatWidget({
2826
2869
  inputPlugins,
2827
2870
  toolRenderers
2828
2871
  }) {
2872
+ const effectiveAgentId = agentId ?? widgetId;
2829
2873
  const layout = display?.layout || "popup";
2830
2874
  const isControlled = open !== void 0;
2831
2875
  const showToggleButton = !isControlled && display?.showToggleButton !== false;
@@ -2894,6 +2938,8 @@ function ChatWidget({
2894
2938
  }, [isResizing]);
2895
2939
  const config = (0, import_react14.useMemo)(() => ({
2896
2940
  userId,
2941
+ apiBase: apiBase ?? "/api/chat",
2942
+ extraHeaders,
2897
2943
  model,
2898
2944
  systemPrompt,
2899
2945
  temperature,
@@ -2902,11 +2948,11 @@ function ChatWidget({
2902
2948
  starterPrompts,
2903
2949
  inputPlugins,
2904
2950
  toolRenderers
2905
- }), [userId, model, systemPrompt, temperature, theme, features, starterPrompts, inputPlugins, toolRenderers]);
2951
+ }), [userId, apiBase, extraHeaders, model, systemPrompt, temperature, theme, features, starterPrompts, inputPlugins, toolRenderers]);
2906
2952
  const togglePosition = display?.toggleButtonPosition || { bottom: "24px", right: "24px" };
2907
2953
  const themeClass = theme?.mode === "dark" ? "dark" : "";
2908
2954
  if (layout === "inline") {
2909
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ChatStorageProvider, { userId, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2955
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ChatStorageProvider, { userId, agentId: effectiveAgentId, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2910
2956
  "div",
2911
2957
  {
2912
2958
  ref: containerRef,
@@ -2926,7 +2972,7 @@ function ChatWidget({
2926
2972
  ) });
2927
2973
  }
2928
2974
  if (layout === "page") {
2929
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ChatStorageProvider, { userId, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2975
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ChatStorageProvider, { userId, agentId: effectiveAgentId, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2930
2976
  "div",
2931
2977
  {
2932
2978
  ref: containerRef,
@@ -2945,7 +2991,7 @@ function ChatWidget({
2945
2991
  }
2946
2992
  ) });
2947
2993
  }
2948
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(ChatStorageProvider, { userId, children: [
2994
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(ChatStorageProvider, { userId, agentId: effectiveAgentId, children: [
2949
2995
  showToggleButton && !isOpen && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2950
2996
  "button",
2951
2997
  {
@@ -3042,7 +3088,6 @@ var MODELS = [
3042
3088
  value: "google/gemini-2.5-pro"
3043
3089
  }
3044
3090
  ];
3045
- var DEFAULT_MODEL = MODELS[0].value;
3046
3091
 
3047
3092
  // src/hooks/use-chat-theme.ts
3048
3093
  function hexToHSL(hex) {
@@ -3107,13 +3152,13 @@ var defaultConversationStarters = [
3107
3152
  { text: "What features does this product offer?", enabled: true },
3108
3153
  { text: "Tell me about your capabilities", enabled: true }
3109
3154
  ];
3110
- var defaultModel = DEFAULT_MODEL;
3155
+ var defaultModel = MODELS[0].value;
3111
3156
  var defaultSystemPrompt = "You are a helpful AI assistant.";
3112
3157
  var defaultTemperature = 0.7;
3113
3158
  var defaultThemeMode = "light";
3114
3159
  function useChatTheme() {
3115
3160
  const { storageKeyPrefix } = useChatStorageKey();
3116
- const keyPrefix = storageKeyPrefix ? `chat-${storageKeyPrefix}-` : "chat-";
3161
+ const keyPrefix = storageKeyPrefix ? `chat-${storageKeyPrefix}-` : null;
3117
3162
  const [theme, setTheme] = (0, import_react15.useState)(defaultTheme);
3118
3163
  const [conversationStarters, setConversationStarters] = (0, import_react15.useState)(defaultConversationStarters);
3119
3164
  const [model, setModel] = (0, import_react15.useState)(defaultModel);
@@ -3121,6 +3166,7 @@ function useChatTheme() {
3121
3166
  const [temperature, setTemperature] = (0, import_react15.useState)(defaultTemperature);
3122
3167
  const [themeMode, setThemeMode] = (0, import_react15.useState)(defaultThemeMode);
3123
3168
  (0, import_react15.useEffect)(() => {
3169
+ if (!keyPrefix) return;
3124
3170
  const savedTheme = localStorage.getItem(`${keyPrefix}theme`);
3125
3171
  if (savedTheme) {
3126
3172
  try {
@@ -3209,7 +3255,7 @@ function useChatTheme() {
3209
3255
  };
3210
3256
  }, [keyPrefix]);
3211
3257
  (0, import_react15.useEffect)(() => {
3212
- localStorage.setItem(`${keyPrefix}theme`, JSON.stringify(theme));
3258
+ if (keyPrefix) localStorage.setItem(`${keyPrefix}theme`, JSON.stringify(theme));
3213
3259
  const root = document.documentElement;
3214
3260
  if (themeMode === "light") {
3215
3261
  root.style.setProperty("--chat-primary", hexToHSL(theme.lightPrimary));
@@ -3225,23 +3271,23 @@ function useChatTheme() {
3225
3271
  window.dispatchEvent(new CustomEvent("chat-theme-change", { detail: theme }));
3226
3272
  }, [theme, themeMode, keyPrefix]);
3227
3273
  (0, import_react15.useEffect)(() => {
3228
- localStorage.setItem(`${keyPrefix}conversation-starters`, JSON.stringify(conversationStarters));
3274
+ if (keyPrefix) localStorage.setItem(`${keyPrefix}conversation-starters`, JSON.stringify(conversationStarters));
3229
3275
  window.dispatchEvent(new CustomEvent("chat-starters-change", { detail: conversationStarters }));
3230
3276
  }, [conversationStarters, keyPrefix]);
3231
3277
  (0, import_react15.useEffect)(() => {
3232
- localStorage.setItem(`${keyPrefix}model`, model);
3278
+ if (keyPrefix) localStorage.setItem(`${keyPrefix}model`, model);
3233
3279
  window.dispatchEvent(new CustomEvent("chat-model-change", { detail: model }));
3234
3280
  }, [model, keyPrefix]);
3235
3281
  (0, import_react15.useEffect)(() => {
3236
- localStorage.setItem(`${keyPrefix}system-prompt`, systemPrompt);
3282
+ if (keyPrefix) localStorage.setItem(`${keyPrefix}system-prompt`, systemPrompt);
3237
3283
  window.dispatchEvent(new CustomEvent("chat-system-prompt-change", { detail: systemPrompt }));
3238
3284
  }, [systemPrompt, keyPrefix]);
3239
3285
  (0, import_react15.useEffect)(() => {
3240
- localStorage.setItem(`${keyPrefix}temperature`, temperature.toString());
3286
+ if (keyPrefix) localStorage.setItem(`${keyPrefix}temperature`, temperature.toString());
3241
3287
  window.dispatchEvent(new CustomEvent("chat-temperature-change", { detail: temperature }));
3242
3288
  }, [temperature, keyPrefix]);
3243
3289
  (0, import_react15.useEffect)(() => {
3244
- localStorage.setItem(`${keyPrefix}theme-mode`, themeMode);
3290
+ if (keyPrefix) localStorage.setItem(`${keyPrefix}theme-mode`, themeMode);
3245
3291
  window.dispatchEvent(new CustomEvent("chat-theme-mode-change", { detail: themeMode }));
3246
3292
  }, [themeMode, keyPrefix]);
3247
3293
  const updateColor = (key, value) => {
@@ -3448,6 +3494,7 @@ function DialogDescription({
3448
3494
  ToolHeader,
3449
3495
  ToolInput,
3450
3496
  ToolOutput,
3497
+ clearChatStorage,
3451
3498
  fontOptions,
3452
3499
  useChatStorageKey,
3453
3500
  useChatTheme