@yushaw/sanqian-chat 0.2.3 → 0.2.6

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.
@@ -31,16 +31,23 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var renderer_exports = {};
32
32
  __export(renderer_exports, {
33
33
  AlertBanner: () => AlertBanner,
34
+ AttachButton: () => AttachButton,
34
35
  ChatInput: () => ChatInput,
35
36
  CompactChat: () => CompactChat,
36
37
  FloatingChat: () => FloatingChat,
37
38
  HistoryList: () => HistoryList,
39
+ HistoryModal: () => HistoryModal,
38
40
  HitlCard: () => HitlCard,
39
41
  I18nProvider: () => I18nProvider,
40
42
  IntermediateSteps: () => IntermediateSteps,
41
43
  MarkdownRenderer: () => MarkdownRenderer,
42
44
  MessageBubble: () => MessageBubble,
43
45
  MessageList: () => MessageList,
46
+ ModeToggleButton: () => ModeToggleButton,
47
+ PanelControls: () => PanelControls,
48
+ PanelHeaderButtons: () => PanelHeaderButtons,
49
+ PanelResizer: () => PanelResizer,
50
+ Resizer: () => Resizer,
44
51
  SanqianChat: () => SanqianChat,
45
52
  SanqianChatMessage: () => SanqianChatMessage,
46
53
  SanqianMessageList: () => SanqianMessageList,
@@ -56,7 +63,9 @@ __export(renderer_exports, {
56
63
  ensureFullChatStyles: () => ensureFullChatStyles,
57
64
  getTranslations: () => getTranslations,
58
65
  resolveChatStrings: () => resolveChatStrings,
66
+ useAttachState: () => useAttachState,
59
67
  useChat: () => useChat,
68
+ useChatPanel: () => useChatPanel,
60
69
  useChatStyles: () => useChatStyles,
61
70
  useConnection: () => useConnection,
62
71
  useConversations: () => useConversations,
@@ -933,7 +942,14 @@ var CHAT_UI_STRINGS = {
933
942
  hitlApprovalRequest: "Approval Request",
934
943
  hitlInputRequest: "Input Request",
935
944
  hitlApprovalRequired: "Approval Required",
936
- hitlInputRequired: "Input Required"
945
+ hitlInputRequired: "Input Required",
946
+ // ChatPanel strings
947
+ attachWindow: "Dock",
948
+ detachWindow: "Undock",
949
+ floatWindow: "Float",
950
+ embedWindow: "Embed",
951
+ collapseSidebar: "Collapse",
952
+ history: "History"
937
953
  },
938
954
  zh: {
939
955
  inputPlaceholder: "\u8F93\u5165\u6D88\u606F...",
@@ -983,7 +999,14 @@ var CHAT_UI_STRINGS = {
983
999
  hitlApprovalRequest: "\u9700\u8981\u5BA1\u6279",
984
1000
  hitlInputRequest: "\u9700\u8981\u8F93\u5165",
985
1001
  hitlApprovalRequired: "\u9700\u8981\u5BA1\u6279",
986
- hitlInputRequired: "\u9700\u8981\u8F93\u5165"
1002
+ hitlInputRequired: "\u9700\u8981\u8F93\u5165",
1003
+ // ChatPanel strings
1004
+ attachWindow: "\u5438\u9644",
1005
+ detachWindow: "\u5206\u79BB",
1006
+ floatWindow: "\u6D6E\u52A8",
1007
+ embedWindow: "\u5D4C\u5165",
1008
+ collapseSidebar: "\u6536\u8D77",
1009
+ history: "\u5386\u53F2"
987
1010
  }
988
1011
  };
989
1012
  function resolveChatStrings(locale = "en", overrides) {
@@ -1027,6 +1050,12 @@ var toTranslations = (flat) => ({
1027
1050
  untitled: flat.conversationUntitled,
1028
1051
  delete: flat.delete,
1029
1052
  deleteConfirm: flat.conversationDeleteConfirm
1053
+ },
1054
+ panel: {
1055
+ attachWindow: flat.attachWindow,
1056
+ detachWindow: flat.detachWindow,
1057
+ floatWindow: flat.floatWindow,
1058
+ embedWindow: flat.embedWindow
1030
1059
  }
1031
1060
  });
1032
1061
  var I18nContext = (0, import_react3.createContext)(null);
@@ -1064,7 +1093,8 @@ function I18nProvider({
1064
1093
  input: { ...base.input, ...custom.input },
1065
1094
  message: { ...base.message, ...custom.message },
1066
1095
  connection: { ...base.connection, ...custom.connection },
1067
- conversation: { ...base.conversation, ...custom.conversation }
1096
+ conversation: { ...base.conversation, ...custom.conversation },
1097
+ panel: { ...base.panel, ...custom.panel }
1068
1098
  };
1069
1099
  }, [locale, customTranslations]);
1070
1100
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(I18nContext.Provider, { value: { locale, setLocale, t }, children });
@@ -1500,6 +1530,43 @@ code {
1500
1530
  animation: chat-fade-in 0.2s ease-out;
1501
1531
  }
1502
1532
 
1533
+ /* Modal animations */
1534
+ @keyframes chat-modal-fade-in {
1535
+ from { opacity: 0; }
1536
+ to { opacity: 1; }
1537
+ }
1538
+
1539
+ @keyframes chat-modal-fade-out {
1540
+ from { opacity: 1; }
1541
+ to { opacity: 0; }
1542
+ }
1543
+
1544
+ @keyframes chat-modal-slide-in {
1545
+ from { opacity: 0; transform: scale(0.95); }
1546
+ to { opacity: 1; transform: scale(1); }
1547
+ }
1548
+
1549
+ @keyframes chat-modal-slide-out {
1550
+ from { opacity: 1; transform: scale(1); }
1551
+ to { opacity: 0; transform: scale(0.95); }
1552
+ }
1553
+
1554
+ .chat-modal-backdrop {
1555
+ animation: chat-modal-fade-in 0.15s ease-out forwards;
1556
+ }
1557
+
1558
+ .chat-modal-backdrop.chat-modal-closing {
1559
+ animation: chat-modal-fade-out 0.12s ease-in forwards;
1560
+ }
1561
+
1562
+ .chat-modal-content {
1563
+ animation: chat-modal-slide-in 0.15s ease-out forwards;
1564
+ }
1565
+
1566
+ .chat-modal-content.chat-modal-closing {
1567
+ animation: chat-modal-slide-out 0.12s ease-in forwards;
1568
+ }
1569
+
1503
1570
  /* ========================================
1504
1571
  Prose Overrides
1505
1572
  ======================================== */
@@ -5041,6 +5108,136 @@ function useResolvedUiConfig(config) {
5041
5108
  }, [ipcConfig, config]);
5042
5109
  }
5043
5110
 
5111
+ // src/renderer/hooks/useChatPanel.ts
5112
+ var import_react10 = require("react");
5113
+ var getChatPanelApi = () => {
5114
+ return window.chatPanel;
5115
+ };
5116
+ function useChatPanel() {
5117
+ const [mode, setModeState] = (0, import_react10.useState)("embedded");
5118
+ const [visible, setVisible] = (0, import_react10.useState)(false);
5119
+ const [width, setWidthState] = (0, import_react10.useState)(360);
5120
+ (0, import_react10.useEffect)(() => {
5121
+ const api = getChatPanelApi();
5122
+ if (!api) {
5123
+ console.warn("[useChatPanel] chatPanel API not available");
5124
+ return;
5125
+ }
5126
+ api.getMode?.().then(setModeState).catch(() => {
5127
+ });
5128
+ api.isVisible?.().then(setVisible).catch(() => {
5129
+ });
5130
+ api.getWidth?.().then(setWidthState).catch(() => {
5131
+ });
5132
+ const unsubMode = api.onModeChanged?.(setModeState);
5133
+ const unsubVisible = api.onVisibilityChanged?.(setVisible);
5134
+ return () => {
5135
+ unsubMode?.();
5136
+ unsubVisible?.();
5137
+ };
5138
+ }, []);
5139
+ const setMode = (0, import_react10.useCallback)(async (newMode) => {
5140
+ const api = getChatPanelApi();
5141
+ if (!api?.setMode) return;
5142
+ await api.setMode(newMode);
5143
+ setModeState(newMode);
5144
+ }, []);
5145
+ const toggleMode = (0, import_react10.useCallback)(async () => {
5146
+ const api = getChatPanelApi();
5147
+ if (!api?.toggleMode) return mode;
5148
+ const newMode = await api.toggleMode();
5149
+ setModeState(newMode);
5150
+ return newMode;
5151
+ }, [mode]);
5152
+ const show = (0, import_react10.useCallback)(async () => {
5153
+ const api = getChatPanelApi();
5154
+ if (!api?.show) return;
5155
+ await api.show();
5156
+ setVisible(true);
5157
+ }, []);
5158
+ const hide = (0, import_react10.useCallback)(async () => {
5159
+ const api = getChatPanelApi();
5160
+ if (!api?.hide) return;
5161
+ await api.hide();
5162
+ setVisible(false);
5163
+ }, []);
5164
+ const toggle = (0, import_react10.useCallback)(async () => {
5165
+ const api = getChatPanelApi();
5166
+ if (!api?.toggle) return;
5167
+ await api.toggle();
5168
+ setVisible((v) => !v);
5169
+ }, []);
5170
+ const setWidth = (0, import_react10.useCallback)(async (newWidth, animate) => {
5171
+ const api = getChatPanelApi();
5172
+ if (!api?.setWidth) return;
5173
+ await api.setWidth(newWidth, animate);
5174
+ setWidthState(newWidth);
5175
+ }, []);
5176
+ const onResizeEnd = (0, import_react10.useCallback)(async () => {
5177
+ const api = getChatPanelApi();
5178
+ if (!api?.onResizeEnd) return;
5179
+ await api.onResizeEnd();
5180
+ }, []);
5181
+ return {
5182
+ mode,
5183
+ visible,
5184
+ width,
5185
+ isEmbedded: mode === "embedded",
5186
+ isFloating: mode === "floating",
5187
+ setMode,
5188
+ toggleMode,
5189
+ show,
5190
+ hide,
5191
+ toggle,
5192
+ setWidth,
5193
+ onResizeEnd
5194
+ };
5195
+ }
5196
+
5197
+ // src/renderer/hooks/useAttachState.ts
5198
+ var import_react11 = require("react");
5199
+ var getChatPanelApi2 = () => {
5200
+ return window.chatPanel;
5201
+ };
5202
+ function useAttachState() {
5203
+ const [state, setState] = (0, import_react11.useState)("unavailable");
5204
+ const [isLoading, setIsLoading] = (0, import_react11.useState)(true);
5205
+ (0, import_react11.useEffect)(() => {
5206
+ const api = getChatPanelApi2();
5207
+ if (!api) {
5208
+ setIsLoading(false);
5209
+ return;
5210
+ }
5211
+ api.getAttachState?.().then((result) => {
5212
+ if (result.success) {
5213
+ setState(result.data);
5214
+ }
5215
+ }).catch(() => {
5216
+ }).finally(() => setIsLoading(false));
5217
+ const unsubscribe = api.onAttachStateChanged?.(setState);
5218
+ return () => {
5219
+ unsubscribe?.();
5220
+ };
5221
+ }, []);
5222
+ const toggle = (0, import_react11.useCallback)(async () => {
5223
+ const api = getChatPanelApi2();
5224
+ if (!api?.toggleAttach) return state;
5225
+ const result = await api.toggleAttach();
5226
+ if (result.success) {
5227
+ setState(result.data);
5228
+ return result.data;
5229
+ }
5230
+ return state;
5231
+ }, [state]);
5232
+ return {
5233
+ state,
5234
+ isAttached: state === "attached",
5235
+ isAvailable: state !== "unavailable",
5236
+ isLoading,
5237
+ toggle
5238
+ };
5239
+ }
5240
+
5044
5241
  // src/core/history.ts
5045
5242
  function safeParseArgs(value) {
5046
5243
  if (!value) return void 0;
@@ -5800,38 +5997,38 @@ function createSdkAdapter(config) {
5800
5997
  var import_browser = require("@yushaw/sanqian-sdk/browser");
5801
5998
 
5802
5999
  // src/renderer/components/MessageList.tsx
5803
- var import_react10 = require("react");
6000
+ var import_react12 = require("react");
5804
6001
  var import_jsx_runtime3 = require("react/jsx-runtime");
5805
6002
  var SCROLL_THRESHOLD = 100;
5806
- var MessageList = (0, import_react10.memo)(function MessageList2({
6003
+ var MessageList = (0, import_react12.memo)(function MessageList2({
5807
6004
  messages,
5808
6005
  className = "",
5809
6006
  renderMessage,
5810
6007
  autoScroll = true,
5811
6008
  scrollBehavior = "smooth"
5812
6009
  }) {
5813
- const containerRef = (0, import_react10.useRef)(null);
5814
- const isNearBottomRef = (0, import_react10.useRef)(true);
5815
- const checkIfNearBottom = (0, import_react10.useCallback)(() => {
6010
+ const containerRef = (0, import_react12.useRef)(null);
6011
+ const isNearBottomRef = (0, import_react12.useRef)(true);
6012
+ const checkIfNearBottom = (0, import_react12.useCallback)(() => {
5816
6013
  const container = containerRef.current;
5817
6014
  if (!container) return true;
5818
6015
  return container.scrollTop <= SCROLL_THRESHOLD;
5819
6016
  }, []);
5820
- const handleScroll = (0, import_react10.useCallback)(() => {
6017
+ const handleScroll = (0, import_react12.useCallback)(() => {
5821
6018
  isNearBottomRef.current = checkIfNearBottom();
5822
6019
  }, [checkIfNearBottom]);
5823
- const scrollToBottom = (0, import_react10.useCallback)(
6020
+ const scrollToBottom = (0, import_react12.useCallback)(
5824
6021
  (behavior = scrollBehavior) => {
5825
6022
  containerRef.current?.scrollTo({ top: 0, behavior });
5826
6023
  },
5827
6024
  [scrollBehavior]
5828
6025
  );
5829
- (0, import_react10.useEffect)(() => {
6026
+ (0, import_react12.useEffect)(() => {
5830
6027
  if (autoScroll && isNearBottomRef.current) {
5831
6028
  scrollToBottom();
5832
6029
  }
5833
6030
  }, [messages, autoScroll, scrollToBottom]);
5834
- (0, import_react10.useEffect)(() => {
6031
+ (0, import_react12.useEffect)(() => {
5835
6032
  scrollToBottom("instant");
5836
6033
  isNearBottomRef.current = true;
5837
6034
  }, [scrollToBottom]);
@@ -5849,9 +6046,9 @@ var MessageList = (0, import_react10.memo)(function MessageList2({
5849
6046
  });
5850
6047
 
5851
6048
  // src/renderer/components/MessageBubble.tsx
5852
- var import_react11 = require("react");
6049
+ var import_react13 = require("react");
5853
6050
  var import_jsx_runtime4 = require("react/jsx-runtime");
5854
- var MessageBubble = (0, import_react11.memo)(function MessageBubble2({
6051
+ var MessageBubble = (0, import_react13.memo)(function MessageBubble2({
5855
6052
  message,
5856
6053
  className = "",
5857
6054
  children,
@@ -5868,20 +6065,20 @@ var MessageBubble = (0, import_react11.memo)(function MessageBubble2({
5868
6065
  });
5869
6066
 
5870
6067
  // src/renderer/components/SanqianChat.tsx
5871
- var import_react22 = require("react");
6068
+ var import_react24 = require("react");
5872
6069
 
5873
6070
  // src/renderer/utils/chatConfig.ts
5874
- var import_react12 = require("react");
6071
+ var import_react14 = require("react");
5875
6072
  var getSystemTheme = () => {
5876
6073
  if (typeof window === "undefined") return "light";
5877
6074
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
5878
6075
  };
5879
6076
  function useResolvedTheme(mode = "auto") {
5880
- const [resolvedTheme, setResolvedTheme] = (0, import_react12.useState)(() => {
6077
+ const [resolvedTheme, setResolvedTheme] = (0, import_react14.useState)(() => {
5881
6078
  if (mode === "auto") return getSystemTheme();
5882
6079
  return mode === "dark" ? "dark" : "light";
5883
6080
  });
5884
- (0, import_react12.useEffect)(() => {
6081
+ (0, import_react14.useEffect)(() => {
5885
6082
  if (mode !== "auto") {
5886
6083
  setResolvedTheme(mode === "dark" ? "dark" : "light");
5887
6084
  return;
@@ -5943,7 +6140,7 @@ function getBaseColors(isDark) {
5943
6140
  };
5944
6141
  }
5945
6142
  function useAccentStyle(accentColor) {
5946
- return (0, import_react12.useMemo)(() => {
6143
+ return (0, import_react14.useMemo)(() => {
5947
6144
  if (!accentColor) return void 0;
5948
6145
  const rgb = parseColorToRgb(accentColor);
5949
6146
  if (!rgb) {
@@ -5985,7 +6182,7 @@ function resolveOnPin(onPin) {
5985
6182
  }
5986
6183
 
5987
6184
  // src/renderer/utils/useChatHeader.tsx
5988
- var import_react13 = require("react");
6185
+ var import_react15 = require("react");
5989
6186
 
5990
6187
  // src/renderer/assets/sanqianLogo.ts
5991
6188
  var SANQIAN_LOGO_DATA_URI = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iTGF5ZXJfMiIgZGF0YS1uYW1lPSJMYXllciAyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MTUuODcgNDI4LjIiPgogIDxnIGlkPSJMYXllcl8xLTIiIGRhdGEtbmFtZT0iTGF5ZXIgMSI+CiAgICA8ZyBpZD0iQzhvaUxXIj4KICAgICAgPGc+CiAgICAgICAgPHBhdGggZD0iTTQwNC45LDE1OC4wM2wxLjk4LTEuMDFjLS4zMSw2LjM1LDEuMDQsMTIuNTYsMS43NCwxOC44Mi41Myw0LjcyLDEuNjIsOC41NywxLjI2LDE0LjY4LTEuMDcsMTguNDEtNy4wOCwzNS45Ni0xMS45OCw1My41bDcuOTUtMTYuNTRjMy43MS0xMi4wOCw2Ljc4LTI0LjI0LDguMDUtMzYuODdsMS45Ny0uMWMtMS43MSw0LjkxLTEuNDQsMTAuNjYtMi4yNiwxNS43NC00LjY3LDI5LjA1LTE3LjgzLDU4LjI3LTM1LjMxLDgxLjY5LTguNzYsMTEuNzMtMTkuNzgsMjEuMzUtMjguNDQsMzIuNTYtMi45OSwzLjg4LTEyLjM4LDcuOTktMTYuMjMsMTAuNTUtMi4wOCwxLjM4LTQuOTQsNS44Ny02LjQ4LDcuMDEtNiw0LjQ1LTE3LjE5LDUuNDMtMjIuMjYsMTEuNDcsMS4xLDEuMTksMy42OS0uNTQsNC45NS0xLjA1LDE1LjQ0LTYuMiwyOC45NC0xMy45Niw0Mi42MS0yMy40LDQuNjMsMS4wNi0uODQsMi4zMS0xLjg5LDMuMDgtNDEuOTYsMzAuNTUtOTAuNDYsNDYuMy0xNDEuOTQsMjcuNjQtMTkuMzEtNy0yNi4yMS0xOC45Ny00MC41NS0yNi40NS0xMy4xLTYuODMtMTUuOTktMTEuNTctMjUuMTgtMjIuNTQtMi45My0zLjUtMTAuNzEtMTEuNDctMTIuNDItMTQuODYtLjU2LTEuMTEtNi4yLTIwLjQ4LTYuMjEtMjEuNi0uMDQtNC4zNSwzLjE0LTkuOTcsMy42My0xNC44NC44LTcuOTMtMi45Ny0xOC45MSwzLTI0LjQ5LjY3LDMuMTQuNzgsNi41NSwxLjkxLDkuNjEuNTEsMS4zNy0uMzYsMS43LDIuMDksMS40LDEuOTQtNC4yNi0uMzYtOS45OS4xNy0xMy4yNSwxLjIxLTcuNDcsOC4zLTIxLjg0LDEzLjMzLTI3Ljc2LDUuMzUtNi4yOSwxNC4xMy0xNC4wOSwyMi41MS0xNC40OWwtMTAsOS40OSw2Ljk5LTEuNWMtMy4wNCw0LjgxLTcuNDUsOC43My0xMC40MSwxMy41OS01LjA2LDguMjktNS44NiwxNy44MS02LjU5LDI3LjQzbDQuMDIsMTkuNDljMi4wOC0uOTQuNTUtNS4wNSwxLjItNy4yOS4yNC0uODMsMi4yNi0zLjA5LDIuNzgtMi43LDMuMiwxNC4wNiwxMC40NSwyNC41NSwyMC40MiwzNC42MSwyNS4xLDI1LjM1LDY0LjA0LDMyLjc4LDk3LjI3LDE5LjU2LDguMDMtMy4xOSwxNS43LTguOTYsMjMuMzItMTIuMTdsLTIsMi45OGgxLjQ5YzE3LjE1LTEyLjY2LDMzLjYzLTI3LjExLDQyLjUzLTQ2Ljk5bDIsLjUxLS4wMyw1LjQ4LDguMy0xNi4yLDkuNy0yNy43OWMuNDUsNy41OS0yLjYxLDE0LjY3LTQuNDQsMjEuODYtLjkyLDMuNjItLjQ1LDUuNzgtMi4zOSwxMC44LTYuNTksMTcuMDgtMTkuMTgsMzMuMzEtMzIuMTYsNDUuODVsMy45OC0uNTFjLS4wMy40Ny4xNywxLjA1LDAsMS40OS0xLjg3LDQuNzItMjQuMzMsMjAuMTQtMjkuNzEsMjMuMy0xMC4zMSw2LjA1LTIxLjY3LDExLjEtMzMuMjcsMTQuMjMtLjE2LDEuODUsMy4yNi45OCw0LjM3Ljg2LDM2LjgtNC4wMiw3NS4yOC0yOS43NCw5NS40NS02MC41NSwxMS40MS0xNy40MywxNi42Ni0zMy4yNCwyMS44Ny01My4xMy44OC0zLjM2LDMuMzUtNi4wOSwyLjMyLTEwLjE5LDEuNjctLjI2LDEuMDcsMi40MSwxLjA0LDMuNTMtLjA5LDIuODUtLjkyLDUuMjMtMS4wOSw3LjkzLS4wNywxLjA4LS42NCwzLjc5LDEuMDMsMy41Mmw0Ljk2LTE5LjU0YzEuNTYtMTcuMzEsMy41NC0zMi4yOS43NS00OS42Ni0xLjAxLTYuMy00LjA2LTEzLjMyLTQuNzItMTkuMy0uMjQtMi4xNy40LTIuNjQsMS4yNS0uMjQuNzcsMi4xNywxLjE5LDQuNTIsMS43Nyw2Ljc1LDEuNzEuMjcsMS4wNy0yLjQuOTEtMy40LS42LTMuNTctMy4xLTEwLjk4LTQuNDQtMTQuNTctMy43OS0xMC4yMS0xMC4zMS0xOS42My0xMy40Ny0zMC4wMSwxLjU0Ljk1LDMuMTksMy43MSw0LjE5LDUuMywxMy4xMywyMC45OCwyMC42OSw0NC4zMiwyNC44Miw2OC43WiIvPgogICAgICAgIDxnPgogICAgICAgICAgPHBhdGggZD0iTTIyMC44OSw0MDYuMDJjLS4yNiwxLjMzLDEuODMsMS42LDIuNzQsMS43NSwzMi4xLDUuMjksNTguMjgsMS41MSw4OC4yNC0xMS4yNmwyOS4wMS0xNS40OGMtNC43Nyw1LjEyLTEyLjEyLDkuNjQtMTguMzMsMTMuMTYtNy4wNCwzLjk5LTE5LjI3LDcuNzItMjQuNjgsMTEuMzItLjQxLjI3LTEuMzIsMS4yNC0uOTksMS41aDUuOTljLTYuNjcsMS40Ny0xMy40OCw0LjgzLTE5Ljk3LDYuNTQtNS4xMywxLjM1LTE3LjY2LDIuMzctMjEuMDQsMy45Ni0uNDYuMjEtMS4yNiwxLjMtLjk4LDEuNTFsNC45OSwxYy0yOC4zLDUuNTktNTcuMTQtLjQ4LTg0LjQ4LTguMDEtMS42LDEuMDUuNzUsMS4xOCwxLjQ1LDEuNTMsMTMuMzMsNi42OSwyOS4yMiwxMC4wNyw0NC4wNCwxMS40OWwtMS4wMSwxLjk4LDUsLjAyYy4yNSwxLjcyLTIuMzcsMS4wNi0zLjQ4Ljk4LTMxLjc4LTIuNDEtNjcuMzktMTYuNTMtOTMuNDMtMzQuNTgtMTcuNDYtMTIuMS0zMS4xNS0yNy4wMy00NS41NC00MS40NWwtMjAuNTMtMzEuOTYtMSwzLjk5Yy0uMTItLjcxLTEuOTktOS4yNC00LjAxLTYuOTguNjksMi43NSwyLjYzLDUuNDQsMy41NCw3Ljk1LjM0Ljk0LDEuMzIsMy4yNS0uNTMsMy4wMy0xMC42OC0yMS44NS0xNy44My00NS45NS0xOS4wNS03MC40NS0uNDItOC40OSwzLjMtNDEuNCw4LjE2LTQ3LjQyLjE3LS4yMSwzLjA2LDEuMTgsMy44Ny0yLjY1bC0xLjk4LS40N2MtLjg1LTUuMDQsMy42NC02LjUyLDUuNjYtOS44MnM5LjM3LTE2LjcsMTAuMzEtMTkuNzFjLjE2LS41MS4yNy0xLjYzLS40OC0xLjQ4LTIuNzUsMi4xOC0zLjgzLDUuNTktNS42Niw4LjM0LS42OCwxLjAyLTIuMDIsMy4xMi0xLjgzLjE4LDExLjc1LTI0LjQ3LDI4LjEzLTQyLjQxLDUwLjY1LTU3LjM1LDUuOTYtMy45NSwxMi44Mi02LjUsMTguMzMtMTEuMTYtOS43My41LTIyLjE4LDQuMzItMzAuOTksOC41LTMuMywxLjU3LTguNTIsNi4wOC0xMS4wNyw2Ljk2LTEuNjQuNTctMy4wOC0uNi01LjIxLjUtMS44LjkzLTEwLjY0LDguNi0xMi43NCwxMC41MS0yNC43OSwyMi41Ni00MS4yNiw1Ny41MS00Niw5MC41MS0xLjYxLjA1LTIuMDUtMy41My0yLjA0LTQuNTMuMDUtNC4wOSwxLjMtMTAuMjksMi4wNS0xNC40NmwtMy44OS4xYy0yLjIsMTEuOTYtNS43OSwyMy41OC01LjEyLDM1Ljg4bC0yLTYuOTljLTEuNDctLjA5LTEuNzYsMy41OS0xLjg3LDQuNjEtMi40NywyMy44NSw2LjI4LDU4LjIxLDE1LjQsODAuMzYsMS4wMiwyLjQ5LDkuMTQsMTcuMjEsOC40OCwxOC4wMS0xLjU5LDEuOTItMi4xNC0xLjQ5LTIuNDctMS45OS0xMy4zNC0yMC4yMi0yMS42Mi00My4xLTI1LjU0LTY3LjAxbC0xLjk4LDEuMDFjLTIuMzYtMTUuMTEtNC45NS0yOS4wNy00LjA1LTQ0LjU0LjMyLTUuNDQsMi42Mi0xMC44NywyLjAzLTE2LjQ2bC0zLjk4LDE2LjUxYy0uOTUsMTAuMzEtLjU5LDIwLjY4LTEuMDEsMzEtLjA1LDEuMjEuNzYsMy43Mi0uOTksMy40OC0yLjAxLTE4LjI0LS41NC0zNi4zMSwzLjI4LTU0LjIsNS42OS0yNi42LDE4LjI4LTU0LjI3LDM2LjE5LTc0LjgxLDEyLjUzLTE0LjM3LDI4LjEyLTI3Ljk5LDQyLjg4LTM4LjY4LDIuMDktMS41MSw1LjA0LTMuOCw3LjMxLTUuMTMsOC4xLTQuNzIsMTcuODQtNS45OSwyNS4zMS0xMS42OC0uNTgtMS4xMS0zLjA2LS4zNi00LjA2LS4wNi00LjkzLDEuNDUtMTIuMTUsNC4wNy0xNi45Miw2LjA4LTUuOTIsMi41LTExLjU0LDUuNzEtMTcsOS4wNmwtMy4wMS0xLjU2YzcuMzEtMy4yNywxMy41My03LjI4LDIxLjAzLTEwLjQ4LDQxLjYzLTE3LjcyLDEwNS4zMi0yMCwxMzcuMzYsMTYuNTMsNy40NSw4LjQ5LDE5LjI1LDIyLjU4LDI1LjA1LDMwLjk5LDEuODgsMi43MiwyLjc5LDUuNzQsMS41NSw4Ljk0aDMuMDJjLS41OC45NC0uOTksNi41Ni0uOCw2Ljg0LjQ0LjY1LDIuOTcuNjQsMy4zOCwyLjY0LjI5LDEuNDMsMS40OSwxNC43LDEuNDMsMTUuOTUtLjAzLjYtMS44MS40Ny0yLjAxLDEuMjUtLjg0LDMuMjcuNDcsMTIuNTEtLjA3LDE2LjY4LS45NSw3LjM0LTYuMTksMTAuMTItOS44MywxNS4yNy0xLjI4LDEuODEtMS45OCw2LjU3LTQuMTUsNy44NC0xLjc3LDEuMDQtNC45NS42NC03LjE4LDEuNjEtMi4zNCwxLjAyLTMuNTEsNi42Ni03Ljc4LDQuOTNsMi45OS0xMWMtMy4zOSw0LjA2LTEzLjU2LDEwLjAzLTEwLjIxLjI4LDEuMzEtMy44MS44NC0zLjI4LDEuNTEtNi41NC44MS0zLjkyLDMuNzktMTIuOTIsMy43MS0xNi4xNi0uMDEtLjQyLTEuOTktLjk4LTIuNy0yLjM2LTQuMDItNy44Mi02LjM1LTE1LjE3LTEyLjY2LTIxLjg3LTExLjMtMTItNDIuMzMtMTguMi01Ny44OS0xNC4xLTE2Ljg4LDQuNDUtNDQuNjUsMjYuNDQtNTEuMyw0Mi43LTgsMTkuNTgtMTUuMTcsMzkuNjctMTIuMyw2MS4zOCw0LjA5LDMwLjg2LDE2LjE2LDUzLjYsMzMuNCw3OC42LDEuNTMsMi4yMiw0LjIxLDMuNTksNS40NCw2LjA1LTMuNzktMS4zNy03Ljc1LTUuOTQtMTAuNTEtOC45OC0xMC45My0xMS45OS0xOS44OS0yNi4yNS0yNi41LTQxLjAxLTMuMDMsMS40LDMuMjksNi43Mi0uOTcsNy45OWwtNy4wMy0xNy45OS0xLjk4LDEuOTljLS40Mi0yLjYtMS4wOC04LjIzLTQuMDItOC40OCw0LjMsMjguMjgsMTIuOTgsNTIuNjYsMzEuMDQsNzQuOTYsMjcuNDgsMzMuOTQsNzIuOTMsNjEuMzIsMTE3LjM1LDYyLjY1bDguNjIsMS44OGgtMjFaIi8+CiAgICAgICAgICA8cGF0aCBkPSJNMjg4LjQ4LDQxLjQzYzE3LDEzLjA0LDI2LjQ2LDI0LjkxLDM2LjU4LDQzLjkyLDE1Ljc5LDI5LjY4LDIyLjc5LDYyLjM3LDE1LjgyLDk1LjY3LTEuNjcuMjYtMS4wOS0yLjQzLTEuMDMtMy41My4yLTMuNDksMS42NC02Ljg3LDEuMDMtMTAuNDdsLTEuNTEuOThjLTIuOCwyMS43Mi0xMC41OSw0NS44NC0yMy4wNSw2My45NS01LjY4LDguMjYtOS44NSwxMC41NS0xNi45NSwxNi4wNS0yLjk1LDIuMjktNi4xOSw4LjE3LTkuNDgsNy41MiwxLjA3LTEuODMsNS44NS0zLjk1LDQuNDktNi41MWwtMTAuNDksNyw4Ljk5LTguNS0xLjQ4LS40OWMtMTguNjIsMTcuMTktNDguNjUsMjkuNDYtNzMuNTEsMTkuNDQtMS42LS42NS0yLjQ1LjEtMS45OS0yLjQ1LDEzLjc2LDYuMTcsMjcuODEsMi4wMyw0MC45Ny0zLjUyLDM2LjAyLTE1LjE5LDU3LjE2LTUzLjQ4LDU2LjkyLTkyLjA5LS4wMi0zLjE5LS41Mi0xMS43LTIuODktMTMuMzksMS44OSwxMC0uMywyMi40Ny0zLjMxLDMyLjIxLS4zMiwxLjA1LS4yNiwzLjAzLTEuNjksMi43OSw5Ljc1LTUxLjA4LTIwLjUyLTEwMC41NC02My43MS0xMjUuOC02LjQ1LTMuNzctMTQuMzUtNS42Ni0xOS41Ni0xMC40OWwtMTguNzQtNi43YzIuMDktLjA3LDQuMTgtLjE0LDYuMjYuMjMsMjAuOTcsMy43NywzOS44NCwxNC4zNiw1OC40NCwyMy41NSwxLjczLjg1LDMuNDUsMS44Myw1LjA0LDIuOSwyLjgyLDEuODgsOC42OSw5LjgxLDkuNzcsMTAuMy40My4yLDEuNjQuMjUsMS40OC0uNDktMzEuNzMtMzkuNzgtODMuNTMtNTguNjMtMTMzLjk5LTUzLjUybDcuOTktMi45OGMtMTguMjUuMjEtMzcuNDcsNC40MS01NC41MiwxMC45Ny0yLjg2LjI4LS44Ny0xLjI5LjE2LTEuODUsMS4yMS0uNjUsMTQuNzItNS4xMiwxMy4zNy02LjEyLTE2LjY3LDMuNjUtMzMuMTIsMTEuNy00Ny41MiwyMC45Ny05LjE1LDUuODktMTUuODIsMTIuMTMtMjMuOTcsMTkuMDItMS4xMi45NS0xLjYzLDIuNDItMy41LDEuOTksMy42My0zLjQyLDQuMzEtNy41Myw3LjgyLTEwLjksNS40Mi01LjIyLDE2LjA3LTEzLjEzLDIyLjQ0LTE3LjM5LDMyLjA3LTIxLjQ1LDY5LjEzLTMxLjM4LDEwNy43NC0zMC43MS0uNTMtMS41NS01LjAxLTEuNzktNi41MS0xLjk4LTMuOTEtLjQ5LTEyLjY5LjQ4LTE0LjgyLjAxLS43My0uMTYtLjYtMS45Mi0xLjMzLTIuMDYtMi45OC0uNTMtMTAuNzgsMS43LTE0LjMzLDEuMDItLjI0LTEuMzcsMS43OC0xLjUxLDIuNzUtMS43Miw2LjU5LTEuNDQsMTMuOTgtMS4xLDIwLjcyLTIuMzEsMS43Ny0uMzIsMi45OSwxLjEsMi41Mi0xLjk1bC0zOC45OSwzLjk4LDE2Ljk5LTQtNC45OS0xLjk4YzUyLjEyLTcuOTIsMTA0LjI4LDcuNzMsMTQ1LjU5LDM5LjRaIi8+CiAgICAgICAgICA8cGF0aCBkPSJNODAuODksMzQ2LjAxYy00LjUyLjUxLTMuNDQtMi45NC00LjEtMy44Ni0uMTItLjE2LTEuNDMuNTMtMS45MS4yNC0zLjE0LTEuODktMy4yMi02LjEzLTMuMDEtOS4zN2wtMS45OCwxLjk5LTIuMDItMy41MWMxLjk1LS44LDIuMjktMS4yMSwyLjAxLTMuNDhsMTAuOTksMTcuOThaIi8+CiAgICAgICAgPC9nPgogICAgICA8L2c+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4=";
@@ -6028,11 +6225,11 @@ var resolveLogoNode = (logo, size, alt = SANQIAN_LOGO_ALT) => {
6028
6225
 
6029
6226
  // src/renderer/utils/useChatHeader.tsx
6030
6227
  var useChatHeader = (config) => {
6031
- const resolvedOnClose = (0, import_react13.useMemo)(() => resolveOnClose(config?.onClose), [config?.onClose]);
6032
- const resolvedOnPin = (0, import_react13.useMemo)(() => resolveOnPin(config?.onPin), [config?.onPin]);
6033
- const [isPinned, setIsPinned] = (0, import_react13.useState)(config?.alwaysOnTop ?? false);
6034
- const isFirstRender = (0, import_react13.useRef)(true);
6035
- (0, import_react13.useEffect)(() => {
6228
+ const resolvedOnClose = (0, import_react15.useMemo)(() => resolveOnClose(config?.onClose), [config?.onClose]);
6229
+ const resolvedOnPin = (0, import_react15.useMemo)(() => resolveOnPin(config?.onPin), [config?.onPin]);
6230
+ const [isPinned, setIsPinned] = (0, import_react15.useState)(config?.alwaysOnTop ?? false);
6231
+ const isFirstRender = (0, import_react15.useRef)(true);
6232
+ (0, import_react15.useEffect)(() => {
6036
6233
  if (isFirstRender.current) {
6037
6234
  isFirstRender.current = false;
6038
6235
  return;
@@ -6044,8 +6241,8 @@ var useChatHeader = (config) => {
6044
6241
  }, [config?.alwaysOnTop, resolvedOnPin]);
6045
6242
  const showPin = !!resolvedOnPin || typeof config?.alwaysOnTop === "boolean";
6046
6243
  const showClose = !!resolvedOnClose;
6047
- const logoNode = (0, import_react13.useMemo)(() => resolveLogoNode(config?.logo, "header"), [config?.logo]);
6048
- const togglePin = (0, import_react13.useCallback)(() => {
6244
+ const logoNode = (0, import_react15.useMemo)(() => resolveLogoNode(config?.logo, "header"), [config?.logo]);
6245
+ const togglePin = (0, import_react15.useCallback)(() => {
6049
6246
  setIsPinned((prev) => {
6050
6247
  const nextPinned = !prev;
6051
6248
  resolvedOnPin?.(nextPinned);
@@ -6063,27 +6260,27 @@ var useChatHeader = (config) => {
6063
6260
  };
6064
6261
 
6065
6262
  // src/renderer/components/SanqianMessageList.tsx
6066
- var import_react18 = require("react");
6263
+ var import_react20 = require("react");
6067
6264
  var import_react_virtuoso = require("react-virtuoso");
6068
6265
 
6069
6266
  // src/renderer/components/SanqianChatMessage.tsx
6070
- var import_react17 = require("react");
6267
+ var import_react19 = require("react");
6071
6268
 
6072
6269
  // src/renderer/renderers/MarkdownRenderer.tsx
6073
- var import_react14 = require("react");
6270
+ var import_react16 = require("react");
6074
6271
  var import_streamdown = require("streamdown");
6075
6272
  var import_rehype_harden = require("rehype-harden");
6076
6273
  var import_remark_gfm = __toESM(require("remark-gfm"));
6077
6274
  var import_jsx_runtime6 = require("react/jsx-runtime");
6078
6275
  var PROSE_CLASSES = "prose prose-chat max-w-none";
6079
- var MarkdownRenderer = (0, import_react14.memo)(function MarkdownRenderer2({
6276
+ var MarkdownRenderer = (0, import_react16.memo)(function MarkdownRenderer2({
6080
6277
  content,
6081
6278
  isStreaming = false,
6082
6279
  className = "",
6083
6280
  components,
6084
6281
  onLinkClick
6085
6282
  }) {
6086
- const rehypePlugins = (0, import_react14.useMemo)(() => {
6283
+ const rehypePlugins = (0, import_react16.useMemo)(() => {
6087
6284
  const origin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
6088
6285
  return [
6089
6286
  [import_rehype_harden.harden, {
@@ -6097,10 +6294,10 @@ var MarkdownRenderer = (0, import_react14.memo)(function MarkdownRenderer2({
6097
6294
  import_streamdown.defaultRehypePlugins.katex
6098
6295
  ];
6099
6296
  }, []);
6100
- const remarkPlugins = (0, import_react14.useMemo)(() => {
6297
+ const remarkPlugins = (0, import_react16.useMemo)(() => {
6101
6298
  return [import_remark_gfm.default];
6102
6299
  }, []);
6103
- const customComponents = (0, import_react14.useMemo)(() => {
6300
+ const customComponents = (0, import_react16.useMemo)(() => {
6104
6301
  const comps = {};
6105
6302
  comps.p = ({ children }) => {
6106
6303
  if (isStreaming && children && typeof children === "string" && children.endsWith("\u258C")) {
@@ -6157,10 +6354,10 @@ var MarkdownRenderer = (0, import_react14.memo)(function MarkdownRenderer2({
6157
6354
  });
6158
6355
 
6159
6356
  // src/renderer/components/IntermediateSteps.tsx
6160
- var import_react16 = require("react");
6357
+ var import_react18 = require("react");
6161
6358
 
6162
6359
  // src/renderer/renderers/ToolArgumentsDisplay.tsx
6163
- var import_react15 = require("react");
6360
+ var import_react17 = require("react");
6164
6361
  var import_jsx_runtime7 = require("react/jsx-runtime");
6165
6362
  function formatValue(value, indent = 0) {
6166
6363
  const indentStr = " ".repeat(indent);
@@ -6220,7 +6417,7 @@ function formatValue(value, indent = 0) {
6220
6417
  }
6221
6418
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-[var(--chat-text)]", children: String(value) });
6222
6419
  }
6223
- var ToolArgumentsDisplay = (0, import_react15.memo)(function ToolArgumentsDisplay2({
6420
+ var ToolArgumentsDisplay = (0, import_react17.memo)(function ToolArgumentsDisplay2({
6224
6421
  args,
6225
6422
  className = ""
6226
6423
  }) {
@@ -6286,7 +6483,7 @@ function ExpandableText({
6286
6483
  style,
6287
6484
  maxLines = 3
6288
6485
  }) {
6289
- const [isExpanded, setIsExpanded] = (0, import_react16.useState)(false);
6486
+ const [isExpanded, setIsExpanded] = (0, import_react18.useState)(false);
6290
6487
  const trimmed = content.trim();
6291
6488
  const lines = trimmed.split("\n");
6292
6489
  const needsExpand = lines.length > maxLines;
@@ -6307,7 +6504,7 @@ function ExpandableText({
6307
6504
  );
6308
6505
  }
6309
6506
  function ToolCallItem({ toolCall, toolResult }) {
6310
- const [expanded, setExpanded] = (0, import_react16.useState)(false);
6507
+ const [expanded, setExpanded] = (0, import_react18.useState)(false);
6311
6508
  const hasArgs = toolCall.toolArgs && Object.keys(toolCall.toolArgs).length > 0;
6312
6509
  const rawName = cleanToolName(toolCall.toolName);
6313
6510
  const displayName = rawName && !/^[{\[]/.test(rawName.trim()) ? rawName : toolCall.toolCallId || "tool";
@@ -6345,7 +6542,7 @@ function StreamingToolCallItem({
6345
6542
  isActive,
6346
6543
  strings
6347
6544
  }) {
6348
- const [expanded, setExpanded] = (0, import_react16.useState)(false);
6545
+ const [expanded, setExpanded] = (0, import_react18.useState)(false);
6349
6546
  const hasArgs = toolCall.toolArgs && Object.keys(toolCall.toolArgs).length > 0;
6350
6547
  const rawName = cleanToolName(toolCall.toolName);
6351
6548
  const displayName = rawName && !/^[{\[]/.test(rawName.trim()) ? rawName : toolCall.toolCallId || "tool";
@@ -6413,7 +6610,7 @@ function groupBlocksImpl(blocks) {
6413
6610
  }
6414
6611
  return rounds;
6415
6612
  }
6416
- var ThinkingSection = (0, import_react16.memo)(function ThinkingSection2({
6613
+ var ThinkingSection = (0, import_react18.memo)(function ThinkingSection2({
6417
6614
  thinking,
6418
6615
  currentThinking,
6419
6616
  isStreaming,
@@ -6422,16 +6619,16 @@ var ThinkingSection = (0, import_react16.memo)(function ThinkingSection2({
6422
6619
  className = "",
6423
6620
  strings = {}
6424
6621
  }) {
6425
- const contentRef = (0, import_react16.useRef)(null);
6426
- const isUserScrollingRef = (0, import_react16.useRef)(false);
6427
- const [loadingSymbolIndex, setLoadingSymbolIndex] = (0, import_react16.useState)(0);
6428
- const [manualExpanded, setManualExpanded] = (0, import_react16.useState)(false);
6622
+ const contentRef = (0, import_react18.useRef)(null);
6623
+ const isUserScrollingRef = (0, import_react18.useRef)(false);
6624
+ const [loadingSymbolIndex, setLoadingSymbolIndex] = (0, import_react18.useState)(0);
6625
+ const [manualExpanded, setManualExpanded] = (0, import_react18.useState)(false);
6429
6626
  const effectiveIsStreaming = isComplete ? false : isStreaming;
6430
6627
  const effectiveIsPaused = isComplete ? false : isPaused;
6431
6628
  const isExpanded = effectiveIsStreaming || effectiveIsPaused || manualExpanded;
6432
6629
  const displayContent = effectiveIsStreaming || effectiveIsPaused ? currentThinking || thinking : thinking;
6433
6630
  const hasContent = displayContent && displayContent.split("\n").filter((line) => line.trim() && !line.trim().match(/^─+$/)).length > 0;
6434
- (0, import_react16.useEffect)(() => {
6631
+ (0, import_react18.useEffect)(() => {
6435
6632
  if (effectiveIsStreaming) {
6436
6633
  const interval = setInterval(() => {
6437
6634
  setLoadingSymbolIndex((prev) => (prev + 1) % LOADING_SYMBOLS.length);
@@ -6439,13 +6636,13 @@ var ThinkingSection = (0, import_react16.memo)(function ThinkingSection2({
6439
6636
  return () => clearInterval(interval);
6440
6637
  }
6441
6638
  }, [effectiveIsStreaming]);
6442
- (0, import_react16.useEffect)(() => {
6639
+ (0, import_react18.useEffect)(() => {
6443
6640
  if (effectiveIsStreaming && isExpanded && contentRef.current && !isUserScrollingRef.current) {
6444
6641
  contentRef.current.scrollTop = contentRef.current.scrollHeight;
6445
6642
  }
6446
6643
  }, [displayContent, effectiveIsStreaming, isExpanded]);
6447
- const prevManualExpandedRef = (0, import_react16.useRef)(manualExpanded);
6448
- (0, import_react16.useEffect)(() => {
6644
+ const prevManualExpandedRef = (0, import_react18.useRef)(manualExpanded);
6645
+ (0, import_react18.useEffect)(() => {
6449
6646
  const wasCollapsed = !prevManualExpandedRef.current;
6450
6647
  const isNowExpanded = manualExpanded;
6451
6648
  if (wasCollapsed && isNowExpanded && !effectiveIsStreaming && contentRef.current) {
@@ -6453,13 +6650,13 @@ var ThinkingSection = (0, import_react16.memo)(function ThinkingSection2({
6453
6650
  }
6454
6651
  prevManualExpandedRef.current = manualExpanded;
6455
6652
  }, [manualExpanded, effectiveIsStreaming]);
6456
- const handleScroll = (0, import_react16.useCallback)(() => {
6653
+ const handleScroll = (0, import_react18.useCallback)(() => {
6457
6654
  if (!contentRef.current || !effectiveIsStreaming) return;
6458
6655
  const { scrollTop, scrollHeight, clientHeight } = contentRef.current;
6459
6656
  const isAtBottom = scrollHeight - scrollTop - clientHeight < 20;
6460
6657
  isUserScrollingRef.current = !isAtBottom;
6461
6658
  }, [effectiveIsStreaming]);
6462
- (0, import_react16.useEffect)(() => {
6659
+ (0, import_react18.useEffect)(() => {
6463
6660
  if (!effectiveIsStreaming) {
6464
6661
  isUserScrollingRef.current = false;
6465
6662
  }
@@ -6498,14 +6695,14 @@ var ThinkingSection = (0, import_react16.memo)(function ThinkingSection2({
6498
6695
  isExpanded && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { ref: contentRef, onScroll: handleScroll, className: "mt-1.5 ml-2 max-h-60 overflow-y-auto", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("pre", { className: "whitespace-pre-wrap m-0 font-sans italic", style: { color: "var(--chat-text)", opacity: 0.7, fontSize: "0.8125rem", lineHeight: "1.3" }, children: displayContent?.trim() }) })
6499
6696
  ] });
6500
6697
  });
6501
- var IntermediateSteps = (0, import_react16.memo)(function IntermediateSteps2({
6698
+ var IntermediateSteps = (0, import_react18.memo)(function IntermediateSteps2({
6502
6699
  blocks,
6503
6700
  className = "",
6504
6701
  defaultExpanded = false,
6505
6702
  strings = {}
6506
6703
  }) {
6507
- const [isExpanded, setIsExpanded] = (0, import_react16.useState)(defaultExpanded);
6508
- const rounds = (0, import_react16.useMemo)(() => groupBlocksIntoRounds(blocks), [blocks]);
6704
+ const [isExpanded, setIsExpanded] = (0, import_react18.useState)(defaultExpanded);
6705
+ const rounds = (0, import_react18.useMemo)(() => groupBlocksIntoRounds(blocks), [blocks]);
6509
6706
  if (rounds.length === 0) return null;
6510
6707
  const stepCount = rounds.filter((round) => round.toolCalls.length > 0).length;
6511
6708
  if (stepCount === 0) return null;
@@ -6587,7 +6784,7 @@ var IntermediateSteps = (0, import_react16.memo)(function IntermediateSteps2({
6587
6784
  }) })
6588
6785
  ] });
6589
6786
  });
6590
- var StreamingTimeline = (0, import_react16.memo)(function StreamingTimeline2({
6787
+ var StreamingTimeline = (0, import_react18.memo)(function StreamingTimeline2({
6591
6788
  blocks,
6592
6789
  currentThinking = "",
6593
6790
  isThinkingStreaming = false,
@@ -6596,14 +6793,14 @@ var StreamingTimeline = (0, import_react16.memo)(function StreamingTimeline2({
6596
6793
  className = "",
6597
6794
  strings = {}
6598
6795
  }) {
6599
- const [isExpanded, setIsExpanded] = (0, import_react16.useState)(true);
6600
- const isUserScrollingRef = (0, import_react16.useRef)(false);
6601
- const timelineRef = (0, import_react16.useRef)(null);
6796
+ const [isExpanded, setIsExpanded] = (0, import_react18.useState)(true);
6797
+ const isUserScrollingRef = (0, import_react18.useRef)(false);
6798
+ const timelineRef = (0, import_react18.useRef)(null);
6602
6799
  const isThinkingActive = isThinkingStreaming;
6603
6800
  const isToolsActive = isToolCallsStreaming;
6604
- const rounds = (0, import_react16.useMemo)(() => groupAllBlocksIntoRounds(blocks), [blocks]);
6801
+ const rounds = (0, import_react18.useMemo)(() => groupAllBlocksIntoRounds(blocks), [blocks]);
6605
6802
  const activeThinking = currentThinking;
6606
- const displayRounds = (0, import_react16.useMemo)(() => {
6803
+ const displayRounds = (0, import_react18.useMemo)(() => {
6607
6804
  const result = [];
6608
6805
  for (let roundIdx = 0; roundIdx < rounds.length; roundIdx++) {
6609
6806
  const round = rounds[roundIdx];
@@ -6665,18 +6862,18 @@ var StreamingTimeline = (0, import_react16.memo)(function StreamingTimeline2({
6665
6862
  }, [rounds, activeThinking, isThinkingActive, isToolsActive]);
6666
6863
  const stepCount = rounds.filter((round) => round.toolCalls.length > 0).length;
6667
6864
  const summary = `${stepCount} ${strings.steps || "\u6B65"}`;
6668
- const handleScroll = (0, import_react16.useCallback)(() => {
6865
+ const handleScroll = (0, import_react18.useCallback)(() => {
6669
6866
  if (!timelineRef.current) return;
6670
6867
  const { scrollTop, scrollHeight, clientHeight } = timelineRef.current;
6671
6868
  const isAtBottom = scrollHeight - scrollTop - clientHeight < 20;
6672
6869
  isUserScrollingRef.current = !isAtBottom;
6673
6870
  }, []);
6674
- (0, import_react16.useEffect)(() => {
6871
+ (0, import_react18.useEffect)(() => {
6675
6872
  if (isExpanded && timelineRef.current && !isUserScrollingRef.current) {
6676
6873
  timelineRef.current.scrollTop = timelineRef.current.scrollHeight;
6677
6874
  }
6678
6875
  }, [displayRounds, isExpanded]);
6679
- (0, import_react16.useEffect)(() => {
6876
+ (0, import_react18.useEffect)(() => {
6680
6877
  if (!isThinkingActive && !isToolsActive) {
6681
6878
  isUserScrollingRef.current = false;
6682
6879
  }
@@ -6764,7 +6961,7 @@ var StreamingTimeline = (0, import_react16.memo)(function StreamingTimeline2({
6764
6961
 
6765
6962
  // src/renderer/components/SanqianChatMessage.tsx
6766
6963
  var import_jsx_runtime9 = require("react/jsx-runtime");
6767
- var SanqianChatMessage = (0, import_react17.memo)(function SanqianChatMessage2({ message }) {
6964
+ var SanqianChatMessage = (0, import_react19.memo)(function SanqianChatMessage2({ message }) {
6768
6965
  if (message.role === "tool") return null;
6769
6966
  const isUser = message.role === "user";
6770
6967
  const hasToolCalls = (message.toolCalls?.length ?? 0) > 0;
@@ -6824,9 +7021,9 @@ var import_jsx_runtime10 = require("react/jsx-runtime");
6824
7021
  var AT_BOTTOM_THRESHOLD = 50;
6825
7022
  var INCREASE_VIEWPORT_BY = { top: 1500, bottom: 1500 };
6826
7023
  function ResizeAwareMessage({ message, onHeightChange }) {
6827
- const containerRef = (0, import_react18.useRef)(null);
6828
- const prevHeightRef = (0, import_react18.useRef)(0);
6829
- (0, import_react18.useEffect)(() => {
7024
+ const containerRef = (0, import_react20.useRef)(null);
7025
+ const prevHeightRef = (0, import_react20.useRef)(0);
7026
+ (0, import_react20.useEffect)(() => {
6830
7027
  const container = containerRef.current;
6831
7028
  if (!container || !onHeightChange) return;
6832
7029
  let rafId = null;
@@ -6848,16 +7045,16 @@ function ResizeAwareMessage({ message, onHeightChange }) {
6848
7045
  }, [onHeightChange]);
6849
7046
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: containerRef, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SanqianChatMessage, { message }) });
6850
7047
  }
6851
- var SanqianMessageList = (0, import_react18.forwardRef)(
7048
+ var SanqianMessageList = (0, import_react20.forwardRef)(
6852
7049
  function SanqianMessageList2({ messages, isLoading, className = "", emptyState, onClickEmpty, onAtBottomChange }, ref) {
6853
- const virtuosoRef = (0, import_react18.useRef)(null);
6854
- const [, setAtBottomState] = (0, import_react18.useState)(true);
6855
- const atBottomRef = (0, import_react18.useRef)(true);
6856
- const isManualScrollingRef = (0, import_react18.useRef)(false);
6857
- const manualScrollTimeoutRef = (0, import_react18.useRef)(null);
6858
- const isFollowOutputScrollingRef = (0, import_react18.useRef)(false);
6859
- const followOutputScrollTimeoutRef = (0, import_react18.useRef)(null);
6860
- const setAtBottom = (0, import_react18.useCallback)(
7050
+ const virtuosoRef = (0, import_react20.useRef)(null);
7051
+ const [, setAtBottomState] = (0, import_react20.useState)(true);
7052
+ const atBottomRef = (0, import_react20.useRef)(true);
7053
+ const isManualScrollingRef = (0, import_react20.useRef)(false);
7054
+ const manualScrollTimeoutRef = (0, import_react20.useRef)(null);
7055
+ const isFollowOutputScrollingRef = (0, import_react20.useRef)(false);
7056
+ const followOutputScrollTimeoutRef = (0, import_react20.useRef)(null);
7057
+ const setAtBottom = (0, import_react20.useCallback)(
6861
7058
  (value) => {
6862
7059
  if (isManualScrollingRef.current) return;
6863
7060
  if (isFollowOutputScrollingRef.current && !value) return;
@@ -6867,18 +7064,18 @@ var SanqianMessageList = (0, import_react18.forwardRef)(
6867
7064
  },
6868
7065
  [onAtBottomChange]
6869
7066
  );
6870
- const visibleMessages = (0, import_react18.useMemo)(
7067
+ const visibleMessages = (0, import_react20.useMemo)(
6871
7068
  () => messages.filter((message) => message.role !== "tool"),
6872
7069
  [messages]
6873
7070
  );
6874
7071
  const lastMessage = visibleMessages.length > 0 ? visibleMessages[visibleMessages.length - 1] : null;
6875
7072
  const hasStreamingActivity = isLoading || (lastMessage?.isStreaming ?? false);
6876
- const allItems = (0, import_react18.useMemo)(() => {
7073
+ const allItems = (0, import_react20.useMemo)(() => {
6877
7074
  const items = [...visibleMessages];
6878
7075
  items.push({ id: "footer-spacer", type: "footer" });
6879
7076
  return items;
6880
7077
  }, [visibleMessages]);
6881
- const scrollToBottom = (0, import_react18.useCallback)(
7078
+ const scrollToBottom = (0, import_react20.useCallback)(
6882
7079
  (behavior = "smooth", source) => {
6883
7080
  if (!virtuosoRef.current || allItems.length === 0) return;
6884
7081
  const isManualScroll = source === "scroll-button";
@@ -6904,14 +7101,14 @@ var SanqianMessageList = (0, import_react18.forwardRef)(
6904
7101
  },
6905
7102
  [allItems.length, onAtBottomChange]
6906
7103
  );
6907
- (0, import_react18.useImperativeHandle)(
7104
+ (0, import_react20.useImperativeHandle)(
6908
7105
  ref,
6909
7106
  () => ({
6910
7107
  scrollToBottom
6911
7108
  }),
6912
7109
  [scrollToBottom]
6913
7110
  );
6914
- (0, import_react18.useEffect)(() => {
7111
+ (0, import_react20.useEffect)(() => {
6915
7112
  return () => {
6916
7113
  if (manualScrollTimeoutRef.current) {
6917
7114
  clearTimeout(manualScrollTimeoutRef.current);
@@ -6921,13 +7118,13 @@ var SanqianMessageList = (0, import_react18.forwardRef)(
6921
7118
  }
6922
7119
  };
6923
7120
  }, []);
6924
- const handleMessageHeightChange = (0, import_react18.useCallback)(() => {
7121
+ const handleMessageHeightChange = (0, import_react20.useCallback)(() => {
6925
7122
  if (isManualScrollingRef.current) return;
6926
7123
  if (atBottomRef.current && hasStreamingActivity) {
6927
7124
  scrollToBottom("auto", "height-change");
6928
7125
  }
6929
7126
  }, [scrollToBottom, hasStreamingActivity]);
6930
- const handleClick = (0, import_react18.useCallback)(
7127
+ const handleClick = (0, import_react20.useCallback)(
6931
7128
  (e) => {
6932
7129
  const selection = window.getSelection();
6933
7130
  if (!selection || selection.isCollapsed) {
@@ -6938,7 +7135,7 @@ var SanqianMessageList = (0, import_react18.forwardRef)(
6938
7135
  },
6939
7136
  [onClickEmpty]
6940
7137
  );
6941
- const handleFollowOutput = (0, import_react18.useCallback)((isAtBottom) => {
7138
+ const handleFollowOutput = (0, import_react20.useCallback)((isAtBottom) => {
6942
7139
  if (isAtBottom) {
6943
7140
  if (followOutputScrollTimeoutRef.current) {
6944
7141
  clearTimeout(followOutputScrollTimeoutRef.current);
@@ -6952,7 +7149,7 @@ var SanqianMessageList = (0, import_react18.forwardRef)(
6952
7149
  }
6953
7150
  return false;
6954
7151
  }, []);
6955
- const itemContent = (0, import_react18.useCallback)(
7152
+ const itemContent = (0, import_react20.useCallback)(
6956
7153
  (_index, item) => {
6957
7154
  if ("type" in item && item.type === "footer") {
6958
7155
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-28" });
@@ -6986,10 +7183,10 @@ var SanqianMessageList = (0, import_react18.forwardRef)(
6986
7183
  );
6987
7184
 
6988
7185
  // src/renderer/components/ChatInput.tsx
6989
- var import_react19 = require("react");
7186
+ var import_react21 = require("react");
6990
7187
  var import_jsx_runtime11 = require("react/jsx-runtime");
6991
- var ChatInput = (0, import_react19.memo)(
6992
- (0, import_react19.forwardRef)(function ChatInput2({
7188
+ var ChatInput = (0, import_react21.memo)(
7189
+ (0, import_react21.forwardRef)(function ChatInput2({
6993
7190
  onSend,
6994
7191
  onStop,
6995
7192
  placeholder = "Type a message...",
@@ -7004,12 +7201,12 @@ var ChatInput = (0, import_react19.memo)(
7004
7201
  className = "",
7005
7202
  style
7006
7203
  }, ref) {
7007
- const [text, setText] = (0, import_react19.useState)("");
7008
- const textareaRef = (0, import_react19.useRef)(null);
7204
+ const [text, setText] = (0, import_react21.useState)("");
7205
+ const textareaRef = (0, import_react21.useRef)(null);
7009
7206
  const canSend = text.trim().length > 0 && !disabled && !isLoading;
7010
7207
  const showStopButton = isStreaming && !!onStop;
7011
7208
  const showSpinner = isLoading && !showStopButton;
7012
- (0, import_react19.useImperativeHandle)(
7209
+ (0, import_react21.useImperativeHandle)(
7013
7210
  ref,
7014
7211
  () => ({
7015
7212
  focus: () => textareaRef.current?.focus(),
@@ -7019,13 +7216,13 @@ var ChatInput = (0, import_react19.memo)(
7019
7216
  }),
7020
7217
  [text]
7021
7218
  );
7022
- (0, import_react19.useEffect)(() => {
7219
+ (0, import_react21.useEffect)(() => {
7023
7220
  if (autoFocus) {
7024
7221
  const timer = setTimeout(() => textareaRef.current?.focus(), 100);
7025
7222
  return () => clearTimeout(timer);
7026
7223
  }
7027
7224
  }, [autoFocus]);
7028
- const handleSubmit = (0, import_react19.useCallback)(
7225
+ const handleSubmit = (0, import_react21.useCallback)(
7029
7226
  (e) => {
7030
7227
  e?.preventDefault();
7031
7228
  if (!canSend) return;
@@ -7034,7 +7231,7 @@ var ChatInput = (0, import_react19.memo)(
7034
7231
  },
7035
7232
  [text, canSend, onSend]
7036
7233
  );
7037
- const handleKeyDown = (0, import_react19.useCallback)(
7234
+ const handleKeyDown = (0, import_react21.useCallback)(
7038
7235
  (e) => {
7039
7236
  if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
7040
7237
  e.preventDefault();
@@ -7102,7 +7299,7 @@ var ChatInput = (0, import_react19.memo)(
7102
7299
  );
7103
7300
 
7104
7301
  // src/renderer/components/HitlCard.tsx
7105
- var import_react20 = require("react");
7302
+ var import_react22 = require("react");
7106
7303
  var import_jsx_runtime12 = require("react/jsx-runtime");
7107
7304
  var defaultStrings = {
7108
7305
  approve: "Approve",
@@ -7141,7 +7338,7 @@ var riskColors = {
7141
7338
  icon: "!!"
7142
7339
  }
7143
7340
  };
7144
- var HitlCard = (0, import_react20.memo)(function HitlCard2({
7341
+ var HitlCard = (0, import_react22.memo)(function HitlCard2({
7145
7342
  interrupt,
7146
7343
  onApprove,
7147
7344
  onReject,
@@ -7153,16 +7350,16 @@ var HitlCard = (0, import_react20.memo)(function HitlCard2({
7153
7350
  const t = { ...defaultStrings, ...strings };
7154
7351
  const isApproval = interrupt.type === "approval_request";
7155
7352
  const isUserInput = interrupt.type === "user_input_request";
7156
- const [answer, setAnswer] = (0, import_react20.useState)(interrupt.default || "");
7157
- const [selectedIndices, setSelectedIndices] = (0, import_react20.useState)([]);
7158
- const [isComposing, setIsComposing] = (0, import_react20.useState)(false);
7159
- const [timeLeft, setTimeLeft] = (0, import_react20.useState)(interrupt.timeout ?? null);
7160
- const [rememberChoice, setRememberChoice] = (0, import_react20.useState)(false);
7161
- const inputRef = (0, import_react20.useRef)(null);
7162
- const textareaRef = (0, import_react20.useRef)(null);
7353
+ const [answer, setAnswer] = (0, import_react22.useState)(interrupt.default || "");
7354
+ const [selectedIndices, setSelectedIndices] = (0, import_react22.useState)([]);
7355
+ const [isComposing, setIsComposing] = (0, import_react22.useState)(false);
7356
+ const [timeLeft, setTimeLeft] = (0, import_react22.useState)(interrupt.timeout ?? null);
7357
+ const [rememberChoice, setRememberChoice] = (0, import_react22.useState)(false);
7358
+ const inputRef = (0, import_react22.useRef)(null);
7359
+ const textareaRef = (0, import_react22.useRef)(null);
7163
7360
  const riskLevel = interrupt.risk_level || "medium";
7164
7361
  const riskStyle = riskColors[riskLevel];
7165
- (0, import_react20.useEffect)(() => {
7362
+ (0, import_react22.useEffect)(() => {
7166
7363
  if (isUserInput) {
7167
7364
  if (!interrupt.options || interrupt.options.length === 0) {
7168
7365
  inputRef.current?.focus();
@@ -7170,7 +7367,7 @@ var HitlCard = (0, import_react20.memo)(function HitlCard2({
7170
7367
  }
7171
7368
  }
7172
7369
  }, [isUserInput, interrupt.options]);
7173
- (0, import_react20.useEffect)(() => {
7370
+ (0, import_react22.useEffect)(() => {
7174
7371
  if (timeLeft === null || timeLeft <= 0) return;
7175
7372
  const timer = setInterval(() => {
7176
7373
  setTimeLeft((prev) => {
@@ -7368,12 +7565,12 @@ var HitlCard = (0, import_react20.memo)(function HitlCard2({
7368
7565
  });
7369
7566
 
7370
7567
  // src/renderer/primitives/AlertBanner.tsx
7371
- var import_react21 = require("react");
7568
+ var import_react23 = require("react");
7372
7569
  var import_jsx_runtime13 = (
7373
7570
  // Error icon (circle with X)
7374
7571
  require("react/jsx-runtime")
7375
7572
  );
7376
- var AlertBanner = (0, import_react21.memo)(function AlertBanner2({
7573
+ var AlertBanner = (0, import_react23.memo)(function AlertBanner2({
7377
7574
  type,
7378
7575
  message,
7379
7576
  action,
@@ -7383,7 +7580,7 @@ var AlertBanner = (0, import_react21.memo)(function AlertBanner2({
7383
7580
  maxLines = 3,
7384
7581
  strings
7385
7582
  }) {
7386
- const [isExpanded, setIsExpanded] = (0, import_react21.useState)(false);
7583
+ const [isExpanded, setIsExpanded] = (0, import_react23.useState)(false);
7387
7584
  const defaultIcon = type === "error" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("svg", { className: "size-4 shrink-0", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
7388
7585
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
7389
7586
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M15 9l-6 6M9 9l6 6", strokeLinecap: "round" })
@@ -7446,7 +7643,7 @@ var AlertBanner = (0, import_react21.memo)(function AlertBanner2({
7446
7643
 
7447
7644
  // src/renderer/components/SanqianChat.tsx
7448
7645
  var import_jsx_runtime14 = require("react/jsx-runtime");
7449
- var SanqianChat = (0, import_react22.memo)(function SanqianChat2({
7646
+ var SanqianChat = (0, import_react24.memo)(function SanqianChat2({
7450
7647
  adapter,
7451
7648
  placeholder,
7452
7649
  autoConnect = true,
@@ -7458,20 +7655,20 @@ var SanqianChat = (0, import_react22.memo)(function SanqianChat2({
7458
7655
  config,
7459
7656
  logo
7460
7657
  }) {
7461
- const chatContainerRef = (0, import_react22.useRef)(null);
7462
- const chatInputRef = (0, import_react22.useRef)(null);
7463
- const messageListRef = (0, import_react22.useRef)(null);
7464
- const onStateChangeRef = (0, import_react22.useRef)(onStateChange);
7658
+ const chatContainerRef = (0, import_react24.useRef)(null);
7659
+ const chatInputRef = (0, import_react24.useRef)(null);
7660
+ const messageListRef = (0, import_react24.useRef)(null);
7661
+ const onStateChangeRef = (0, import_react24.useRef)(onStateChange);
7465
7662
  onStateChangeRef.current = onStateChange;
7466
7663
  const resolvedConfig = useResolvedUiConfig(config);
7467
7664
  const { themeClass, isDarkMode } = useResolvedTheme(resolvedConfig?.theme ?? "auto");
7468
7665
  const accentStyle = useAccentStyle(resolvedConfig?.accentColor);
7469
7666
  const resolvedLogo = logo ?? resolvedConfig?.logo;
7470
- const strings = (0, import_react22.useMemo)(
7667
+ const strings = (0, import_react24.useMemo)(
7471
7668
  () => resolveChatStrings(resolvedConfig?.locale, resolvedConfig?.strings),
7472
7669
  [resolvedConfig?.locale, resolvedConfig?.strings]
7473
7670
  );
7474
- const headerConfig = (0, import_react22.useMemo)(
7671
+ const headerConfig = (0, import_react24.useMemo)(
7475
7672
  () => {
7476
7673
  if (!resolvedConfig) {
7477
7674
  return resolvedLogo ? { logo: resolvedLogo } : void 0;
@@ -7484,7 +7681,7 @@ var SanqianChat = (0, import_react22.memo)(function SanqianChat2({
7484
7681
  [resolvedConfig, resolvedLogo]
7485
7682
  );
7486
7683
  const { logoNode, showPin, showClose, isPinned, togglePin, resolvedOnClose } = useChatHeader(headerConfig);
7487
- const emptyLogoNode = (0, import_react22.useMemo)(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
7684
+ const emptyLogoNode = (0, import_react24.useMemo)(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
7488
7685
  const showHeader = !!(logoNode || showClose || showPin);
7489
7686
  useChatStyles();
7490
7687
  useConnection({ adapter, autoConnect });
@@ -7505,7 +7702,7 @@ var SanqianChat = (0, import_react22.memo)(function SanqianChat2({
7505
7702
  chat.submitHitlInput({ cancelled: true });
7506
7703
  }
7507
7704
  };
7508
- (0, import_react22.useEffect)(() => {
7705
+ (0, import_react24.useEffect)(() => {
7509
7706
  onStateChangeRef.current?.({
7510
7707
  messages: chat.messages,
7511
7708
  conversationId: chat.conversationId
@@ -7624,10 +7821,187 @@ var SanqianChat = (0, import_react22.memo)(function SanqianChat2({
7624
7821
  });
7625
7822
 
7626
7823
  // src/renderer/components/FloatingChat.tsx
7627
- var import_react24 = require("react");
7824
+ var import_react29 = require("react");
7825
+
7826
+ // src/renderer/components/ModeToggleButton.tsx
7827
+ var import_react25 = require("react");
7828
+ var import_jsx_runtime15 = (
7829
+ // Float out icon - two overlapping panels (macOS style)
7830
+ require("react/jsx-runtime")
7831
+ );
7832
+ function ModeToggleButton({ className, locale = "en" }) {
7833
+ const { isEmbedded, toggleMode } = useChatPanel();
7834
+ const strings = (0, import_react25.useMemo)(() => resolveChatStrings(locale), [locale]);
7835
+ const handleClick = async () => {
7836
+ await toggleMode();
7837
+ };
7838
+ const tooltipText = isEmbedded ? strings.floatWindow : strings.embedWindow;
7839
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: `chat-tooltip-wrapper ${className || ""}`, children: [
7840
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7841
+ "button",
7842
+ {
7843
+ onClick: handleClick,
7844
+ className: headerIconButtonClass,
7845
+ "aria-label": tooltipText,
7846
+ children: isEmbedded ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
7847
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("rect", { x: "8", y: "3", width: "13", height: "13", rx: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
7848
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M5 8H4a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-1", strokeLinecap: "round", strokeLinejoin: "round" })
7849
+ ] }) : (
7850
+ // Embed icon - panel with sidebar (dock to sidebar)
7851
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
7852
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
7853
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M15 4v16", strokeLinecap: "round" })
7854
+ ] })
7855
+ )
7856
+ }
7857
+ ),
7858
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "chat-tooltip", children: tooltipText })
7859
+ ] });
7860
+ }
7861
+
7862
+ // src/renderer/components/AttachButton.tsx
7863
+ var import_react26 = require("react");
7864
+ var import_jsx_runtime16 = (
7865
+ // Attached state: filled icon
7866
+ require("react/jsx-runtime")
7867
+ );
7868
+ function AttachButton({ className, locale = "en" }) {
7869
+ const { isAttached, isAvailable, toggle } = useAttachState();
7870
+ const { isFloating } = useChatPanel();
7871
+ const strings = (0, import_react26.useMemo)(() => resolveChatStrings(locale), [locale]);
7872
+ if (!isFloating || !isAvailable) return null;
7873
+ const handleClick = async () => {
7874
+ await toggle();
7875
+ };
7876
+ const tooltipText = isAttached ? strings.detachWindow : strings.attachWindow;
7877
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: `chat-tooltip-wrapper ${className || ""}`, children: [
7878
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7879
+ "button",
7880
+ {
7881
+ onClick: handleClick,
7882
+ className: headerIconButtonClass,
7883
+ "aria-label": tooltipText,
7884
+ children: isAttached ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { className: headerIconClass, viewBox: "0 0 16 16", fill: "currentColor", children: [
7885
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M4.5 2A2.5 2.5 0 0 0 2 4.5v7A2.5 2.5 0 0 0 4.5 14h7a2.5 2.5 0 0 0 2.5-2.5v-7A2.5 2.5 0 0 0 11.5 2h-7z" }),
7886
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M9.5 6.5h3v1h-3v-1z", fill: "var(--bg-color, #fff)" })
7887
+ ] }) : (
7888
+ // Detached state: outline icon
7889
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { className: headerIconClass, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
7890
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { x: "2.5", y: "2.5", width: "11", height: "11", rx: "2" }),
7891
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M9.5 6.5h3", strokeLinecap: "round" })
7892
+ ] })
7893
+ )
7894
+ }
7895
+ ),
7896
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "chat-tooltip", children: tooltipText })
7897
+ ] });
7898
+ }
7899
+
7900
+ // src/renderer/components/Resizer.tsx
7901
+ var import_react27 = require("react");
7902
+ var import_jsx_runtime17 = require("react/jsx-runtime");
7903
+ var DEFAULT_WIDTH = 360;
7904
+ function Resizer({
7905
+ position = "left",
7906
+ minWidth = 240,
7907
+ maxWidth = 600,
7908
+ defaultWidth = DEFAULT_WIDTH,
7909
+ className = ""
7910
+ }) {
7911
+ const { isEmbedded, width, setWidth, onResizeEnd } = useChatPanel();
7912
+ const [isHovered, setIsHovered] = (0, import_react27.useState)(false);
7913
+ const [isDragging, setIsDragging] = (0, import_react27.useState)(false);
7914
+ const startX = (0, import_react27.useRef)(0);
7915
+ const startWidth = (0, import_react27.useRef)(0);
7916
+ const handleDoubleClick = (0, import_react27.useCallback)(() => {
7917
+ setWidth(defaultWidth, true);
7918
+ }, [defaultWidth, setWidth]);
7919
+ const handleMouseDown = (0, import_react27.useCallback)((e) => {
7920
+ e.preventDefault();
7921
+ setIsDragging(true);
7922
+ startX.current = e.clientX;
7923
+ startWidth.current = width;
7924
+ document.body.style.cursor = "col-resize";
7925
+ document.body.style.userSelect = "none";
7926
+ }, [width]);
7927
+ (0, import_react27.useEffect)(() => {
7928
+ if (!isDragging) return;
7929
+ const handleMouseMove = (e) => {
7930
+ const deltaX = e.clientX - startX.current;
7931
+ const newWidth = position === "left" ? startWidth.current - deltaX : startWidth.current + deltaX;
7932
+ const clampedWidth = Math.min(maxWidth, Math.max(minWidth, newWidth));
7933
+ setWidth(clampedWidth);
7934
+ };
7935
+ const handleMouseUp = () => {
7936
+ setIsDragging(false);
7937
+ document.body.style.cursor = "";
7938
+ document.body.style.userSelect = "";
7939
+ onResizeEnd();
7940
+ };
7941
+ document.addEventListener("mousemove", handleMouseMove);
7942
+ document.addEventListener("mouseup", handleMouseUp);
7943
+ return () => {
7944
+ document.removeEventListener("mousemove", handleMouseMove);
7945
+ document.removeEventListener("mouseup", handleMouseUp);
7946
+ };
7947
+ }, [isDragging, position, minWidth, maxWidth, setWidth, onResizeEnd]);
7948
+ if (!isEmbedded) return null;
7949
+ const isActive = isHovered || isDragging;
7950
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
7951
+ "div",
7952
+ {
7953
+ className: `chat-resizer ${className}`,
7954
+ onMouseDown: handleMouseDown,
7955
+ onDoubleClick: handleDoubleClick,
7956
+ onMouseEnter: () => setIsHovered(true),
7957
+ onMouseLeave: () => setIsHovered(false),
7958
+ style: {
7959
+ position: "absolute",
7960
+ top: 0,
7961
+ bottom: 0,
7962
+ [position]: 0,
7963
+ width: 6,
7964
+ cursor: "col-resize",
7965
+ zIndex: 100,
7966
+ // Ensure it's above other content and not affected by drag region
7967
+ WebkitAppRegion: "no-drag"
7968
+ },
7969
+ children: [
7970
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7971
+ "div",
7972
+ {
7973
+ style: {
7974
+ position: "absolute",
7975
+ top: 0,
7976
+ bottom: 0,
7977
+ left: position === "left" ? 0 : "auto",
7978
+ right: position === "right" ? 0 : "auto",
7979
+ width: 2,
7980
+ backgroundColor: isActive ? "var(--chat-accent, #2563EB)" : "transparent",
7981
+ transition: "background-color 0.15s ease-out, opacity 0.15s ease-out",
7982
+ opacity: isDragging ? 1 : isHovered ? 0.7 : 0
7983
+ }
7984
+ }
7985
+ ),
7986
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7987
+ "div",
7988
+ {
7989
+ style: {
7990
+ position: "absolute",
7991
+ top: 0,
7992
+ bottom: 0,
7993
+ left: -2,
7994
+ right: -2
7995
+ }
7996
+ }
7997
+ )
7998
+ ]
7999
+ }
8000
+ );
8001
+ }
7628
8002
 
7629
8003
  // src/renderer/hooks/useWindowBackgroundSync.ts
7630
- var import_react23 = require("react");
8004
+ var import_react28 = require("react");
7631
8005
  var cachedPlatform = null;
7632
8006
  var getPlatform = () => {
7633
8007
  if (cachedPlatform !== null) return cachedPlatform;
@@ -7645,7 +8019,7 @@ var setBackgroundColor = (color) => {
7645
8019
  }
7646
8020
  };
7647
8021
  function useWindowBackgroundSync(isDarkMode) {
7648
- (0, import_react23.useEffect)(() => {
8022
+ (0, import_react28.useEffect)(() => {
7649
8023
  if (getPlatform() !== "win32") return;
7650
8024
  const colors = getBaseColors(isDarkMode);
7651
8025
  setBackgroundColor(colors.bg);
@@ -7653,8 +8027,8 @@ function useWindowBackgroundSync(isDarkMode) {
7653
8027
  }
7654
8028
 
7655
8029
  // src/renderer/components/FloatingChat.tsx
7656
- var import_jsx_runtime15 = require("react/jsx-runtime");
7657
- var FloatingChat = (0, import_react24.memo)(function FloatingChat2({
8030
+ var import_jsx_runtime18 = require("react/jsx-runtime");
8031
+ var FloatingChat = (0, import_react29.memo)(function FloatingChat2({
7658
8032
  messages,
7659
8033
  isLoading,
7660
8034
  isStreaming,
@@ -7675,8 +8049,8 @@ var FloatingChat = (0, import_react24.memo)(function FloatingChat2({
7675
8049
  header,
7676
8050
  footer
7677
8051
  }) {
7678
- const chatContainerRef = (0, import_react24.useRef)(null);
7679
- const chatInputRef = (0, import_react24.useRef)(null);
8052
+ const chatContainerRef = (0, import_react29.useRef)(null);
8053
+ const chatInputRef = (0, import_react29.useRef)(null);
7680
8054
  useChatStyles();
7681
8055
  useFocusPersistence({
7682
8056
  containerRef: chatContainerRef,
@@ -7688,18 +8062,18 @@ var FloatingChat = (0, import_react24.memo)(function FloatingChat2({
7688
8062
  const { themeClass, isDarkMode } = useResolvedTheme(themeMode);
7689
8063
  const accentStyle = useAccentStyle(resolvedConfig?.accentColor);
7690
8064
  useWindowBackgroundSync(isDarkMode);
7691
- const rootStyle = (0, import_react24.useMemo)(() => ({
8065
+ const rootStyle = (0, import_react29.useMemo)(() => ({
7692
8066
  ...accentStyle || {},
7693
8067
  minHeight: "100vh",
7694
8068
  minWidth: "100vw"
7695
8069
  }), [accentStyle]);
7696
8070
  const resolvedLogo = logo ?? resolvedConfig?.logo;
7697
8071
  const resolvedLocale = resolvedConfig?.locale ?? locale;
7698
- const resolvedStrings = (0, import_react24.useMemo)(
8072
+ const resolvedStrings = (0, import_react29.useMemo)(
7699
8073
  () => resolveChatStrings(resolvedLocale, resolvedConfig?.strings),
7700
8074
  [resolvedLocale, resolvedConfig?.strings]
7701
8075
  );
7702
- const headerConfig = (0, import_react24.useMemo)(
8076
+ const headerConfig = (0, import_react29.useMemo)(
7703
8077
  () => {
7704
8078
  if (!resolvedConfig) {
7705
8079
  return resolvedLogo ? { logo: resolvedLogo } : void 0;
@@ -7712,71 +8086,77 @@ var FloatingChat = (0, import_react24.memo)(function FloatingChat2({
7712
8086
  [resolvedConfig, resolvedLogo]
7713
8087
  );
7714
8088
  const { logoNode, showPin, showClose, isPinned, togglePin, resolvedOnClose } = useChatHeader(headerConfig);
7715
- const emptyLogoNode = (0, import_react24.useMemo)(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
8089
+ const emptyLogoNode = (0, import_react29.useMemo)(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
7716
8090
  const inputPlaceholder = placeholder ?? resolvedStrings.inputPlaceholder;
7717
8091
  const showHeader = !!(header || logoNode || showPin || showClose);
7718
- const defaultHeader = /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("header", { className: "flex h-9 flex-shrink-0 items-center px-2 border-b chat-divider-border", children: [
7719
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-2", children: [
8092
+ const defaultHeader = /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("header", { className: "flex h-9 flex-shrink-0 items-center px-2 border-b chat-divider-border", children: [
8093
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2", children: [
7720
8094
  logoNode,
7721
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-sm font-medium text-[var(--chat-text)]", children: resolvedStrings.chat })
8095
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-sm font-medium text-[var(--chat-text)]", children: resolvedStrings.chat })
7722
8096
  ] }),
7723
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex-1" }),
7724
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-1", children: [
7725
- showPin && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7726
- "button",
7727
- {
7728
- onClick: togglePin,
7729
- className: headerIconButtonClass,
7730
- title: isPinned ? resolvedStrings.unpin : resolvedStrings.pin,
7731
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: isPinned ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
7732
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M12 17v5" }),
7733
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z" })
7734
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
7735
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M12 17v5" }),
7736
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M15 9.34V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H7.89" }),
7737
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "m2 2 20 20" }),
7738
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M9 9v1.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h11" })
7739
- ] }) })
7740
- }
7741
- ),
7742
- showClose && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7743
- "button",
7744
- {
7745
- onClick: resolvedOnClose,
7746
- className: headerIconButtonClass,
7747
- title: resolvedStrings.close,
7748
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M6 6l12 12M18 6l-12 12", strokeLinecap: "round", strokeLinejoin: "round" }) })
7749
- }
7750
- )
8097
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex-1" }),
8098
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-1", children: [
8099
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ModeToggleButton, { locale: resolvedLocale }),
8100
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AttachButton, { locale: resolvedLocale }),
8101
+ showPin && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "chat-tooltip-wrapper", children: [
8102
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
8103
+ "button",
8104
+ {
8105
+ onClick: togglePin,
8106
+ className: headerIconButtonClass,
8107
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: isPinned ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
8108
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M12 17v5" }),
8109
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z" })
8110
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
8111
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M12 17v5" }),
8112
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M15 9.34V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H7.89" }),
8113
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "m2 2 20 20" }),
8114
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M9 9v1.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h11" })
8115
+ ] }) })
8116
+ }
8117
+ ),
8118
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "chat-tooltip", children: isPinned ? resolvedStrings.unpin : resolvedStrings.pin })
8119
+ ] }),
8120
+ showClose && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "chat-tooltip-wrapper", children: [
8121
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
8122
+ "button",
8123
+ {
8124
+ onClick: resolvedOnClose,
8125
+ className: headerIconButtonClass,
8126
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M6 6l12 12M18 6l-12 12", strokeLinecap: "round", strokeLinejoin: "round" }) })
8127
+ }
8128
+ ),
8129
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "chat-tooltip", children: resolvedStrings.close })
8130
+ ] })
7751
8131
  ] })
7752
8132
  ] });
7753
8133
  const resolvedHeader = header ?? (showHeader ? defaultHeader : null);
7754
- const defaultRenderMessage = (0, import_react24.useCallback)(
8134
+ const defaultRenderMessage = (0, import_react29.useCallback)(
7755
8135
  (message) => {
7756
8136
  if (message.role === "tool") return null;
7757
8137
  const isUser = message.role === "user";
7758
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: `flex ${isUser ? "justify-end" : "justify-start"} mb-4`, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: `text-left ${isUser ? "max-w-[80%]" : "w-full"}`, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: `relative group ${isUser ? "inline-block max-w-full" : "block w-full"}`, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8138
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: `flex ${isUser ? "justify-end" : "justify-start"} mb-4`, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: `text-left ${isUser ? "max-w-[80%]" : "w-full"}`, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: `relative group ${isUser ? "inline-block max-w-full" : "block w-full"}`, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7759
8139
  "div",
7760
8140
  {
7761
8141
  className: `message-bubble-wrapper ${isUser ? "rounded-2xl shadow-sm bg-[var(--chat-accent)] text-white px-4 py-3 whitespace-pre-wrap break-words" : "text-[var(--chat-text)] break-words"}`,
7762
- children: isUser ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "whitespace-pre-wrap", children: message.content }) : message.content && (renderContent ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "prose prose-chat dark:prose-invert max-w-none px-3", children: renderContent(message.content, message.isStreaming ?? false) }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MarkdownRenderer, { content: message.content, isStreaming: message.isStreaming, className: "px-3" }))
8142
+ children: isUser ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "whitespace-pre-wrap", children: message.content }) : message.content && (renderContent ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "prose prose-chat dark:prose-invert max-w-none px-3", children: renderContent(message.content, message.isStreaming ?? false) }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MarkdownRenderer, { content: message.content, isStreaming: message.isStreaming, className: "px-3" }))
7763
8143
  }
7764
8144
  ) }) }) });
7765
8145
  },
7766
8146
  [renderContent]
7767
8147
  );
7768
- const defaultRenderHitl = (0, import_react24.useCallback)(
7769
- (interrupt, onApprove, onReject) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "p-4 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg m-2", children: [
7770
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "font-medium mb-2", children: interrupt.type === "approval_request" ? resolvedStrings.hitlApprovalRequired : resolvedStrings.hitlInputRequired }),
7771
- interrupt.tool && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("p", { className: "text-sm mb-2", children: [
8148
+ const defaultRenderHitl = (0, import_react29.useCallback)(
8149
+ (interrupt, onApprove, onReject) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "p-4 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg m-2", children: [
8150
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "font-medium mb-2", children: interrupt.type === "approval_request" ? resolvedStrings.hitlApprovalRequired : resolvedStrings.hitlInputRequired }),
8151
+ interrupt.tool && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "text-sm mb-2", children: [
7772
8152
  resolvedStrings.hitlToolLabel,
7773
8153
  ": ",
7774
8154
  interrupt.tool
7775
8155
  ] }),
7776
- interrupt.reason && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm mb-2", children: interrupt.reason }),
7777
- interrupt.question && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm mb-2", children: interrupt.question }),
7778
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex gap-2 mt-3", children: [
7779
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8156
+ interrupt.reason && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm mb-2", children: interrupt.reason }),
8157
+ interrupt.question && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm mb-2", children: interrupt.question }),
8158
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex gap-2 mt-3", children: [
8159
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7780
8160
  "button",
7781
8161
  {
7782
8162
  onClick: onApprove,
@@ -7784,7 +8164,7 @@ var FloatingChat = (0, import_react24.memo)(function FloatingChat2({
7784
8164
  children: resolvedStrings.hitlApprove
7785
8165
  }
7786
8166
  ),
7787
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8167
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7788
8168
  "button",
7789
8169
  {
7790
8170
  onClick: onReject,
@@ -7796,9 +8176,10 @@ var FloatingChat = (0, import_react24.memo)(function FloatingChat2({
7796
8176
  ] }),
7797
8177
  [resolvedStrings]
7798
8178
  );
7799
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { ref: chatContainerRef, className: `flex flex-col h-full bg-[var(--chat-bg)] text-[var(--chat-text)] ${themeClass} ${className}`, style: rootStyle, "data-chat-font-size": resolvedConfig?.fontSize || "normal", children: [
7800
- resolvedHeader && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex-shrink-0", children: resolvedHeader }),
7801
- messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex flex-1 items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex items-center justify-center", children: emptyLogoNode }) }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8179
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { ref: chatContainerRef, className: `relative flex flex-col h-full bg-[var(--chat-bg)] text-[var(--chat-text)] ${themeClass} ${className}`, style: rootStyle, "data-chat-font-size": resolvedConfig?.fontSize || "normal", children: [
8180
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Resizer, { position: "left", minWidth: 240, maxWidth: 600 }),
8181
+ resolvedHeader && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex-shrink-0", children: resolvedHeader }),
8182
+ messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex flex-1 items-center justify-center p-4", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex items-center justify-center", children: emptyLogoNode }) }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7802
8183
  MessageList,
7803
8184
  {
7804
8185
  messages,
@@ -7806,12 +8187,12 @@ var FloatingChat = (0, import_react24.memo)(function FloatingChat2({
7806
8187
  renderMessage: renderMessage || defaultRenderMessage
7807
8188
  }
7808
8189
  ),
7809
- pendingInterrupt && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex-shrink-0", children: (renderHitl || defaultRenderHitl)(
8190
+ pendingInterrupt && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex-shrink-0", children: (renderHitl || defaultRenderHitl)(
7810
8191
  pendingInterrupt,
7811
8192
  () => onApproveHitl?.(),
7812
8193
  () => onRejectHitl?.()
7813
8194
  ) }),
7814
- error && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex-shrink-0 px-3 pt-2", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8195
+ error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex-shrink-0 px-3 pt-2", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7815
8196
  AlertBanner,
7816
8197
  {
7817
8198
  type: "error",
@@ -7819,7 +8200,7 @@ var FloatingChat = (0, import_react24.memo)(function FloatingChat2({
7819
8200
  className: `flex items-center gap-2 rounded-xl px-3 py-2 text-sm ${isDarkMode ? "bg-red-900/60 text-red-200" : "bg-red-100 text-red-800"}`
7820
8201
  }
7821
8202
  ) }),
7822
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex-shrink-0 px-3 pb-3 pt-1 border-t chat-divider-border", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
8203
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex-shrink-0 px-3 pb-3 pt-1 border-t chat-divider-border", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7823
8204
  ChatInput,
7824
8205
  {
7825
8206
  ref: chatInputRef,
@@ -7834,16 +8215,16 @@ var FloatingChat = (0, import_react24.memo)(function FloatingChat2({
7834
8215
  autoFocus: true
7835
8216
  }
7836
8217
  ) }),
7837
- footer && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex-shrink-0", children: footer })
8218
+ footer && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex-shrink-0", children: footer })
7838
8219
  ] });
7839
8220
  });
7840
8221
 
7841
8222
  // src/renderer/components/HistoryList.tsx
7842
- var import_react25 = require("react");
7843
- var import_jsx_runtime16 = require("react/jsx-runtime");
8223
+ var import_react30 = require("react");
8224
+ var import_jsx_runtime19 = require("react/jsx-runtime");
7844
8225
  function DeleteButton({ onClick, title, colors }) {
7845
- const [isHovered, setIsHovered] = (0, import_react25.useState)(false);
7846
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8226
+ const [isHovered, setIsHovered] = (0, import_react30.useState)(false);
8227
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
7847
8228
  "button",
7848
8229
  {
7849
8230
  onClick,
@@ -7864,7 +8245,7 @@ function DeleteButton({ onClick, title, colors }) {
7864
8245
  alignItems: "center",
7865
8246
  justifyContent: "center"
7866
8247
  },
7867
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8248
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
7868
8249
  "svg",
7869
8250
  {
7870
8251
  style: { width: "0.875rem", height: "0.875rem" },
@@ -7872,7 +8253,7 @@ function DeleteButton({ onClick, title, colors }) {
7872
8253
  fill: "none",
7873
8254
  stroke: "currentColor",
7874
8255
  strokeWidth: "1.5",
7875
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8256
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
7876
8257
  "path",
7877
8258
  {
7878
8259
  d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16",
@@ -7886,8 +8267,8 @@ function DeleteButton({ onClick, title, colors }) {
7886
8267
  );
7887
8268
  }
7888
8269
  function LoadMoreButton({ onClick, colors, children }) {
7889
- const [isHovered, setIsHovered] = (0, import_react25.useState)(false);
7890
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8270
+ const [isHovered, setIsHovered] = (0, import_react30.useState)(false);
8271
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
7891
8272
  "button",
7892
8273
  {
7893
8274
  onClick,
@@ -7936,7 +8317,7 @@ function formatRelativeTime(dateStr, strings) {
7936
8317
  return date.toLocaleDateString(void 0, { month: "short", day: "numeric" });
7937
8318
  }
7938
8319
  }
7939
- var HistoryList = (0, import_react25.memo)(function HistoryList2({
8320
+ var HistoryList = (0, import_react30.memo)(function HistoryList2({
7940
8321
  conversations,
7941
8322
  selectedId,
7942
8323
  isLoading,
@@ -7948,11 +8329,11 @@ var HistoryList = (0, import_react25.memo)(function HistoryList2({
7948
8329
  isDarkMode = false,
7949
8330
  strings = {}
7950
8331
  }) {
7951
- const [hoveredId, setHoveredId] = (0, import_react25.useState)(null);
7952
- const loadMoreRef = (0, import_react25.useRef)(null);
7953
- const isLoadingRef = (0, import_react25.useRef)(isLoading);
8332
+ const [hoveredId, setHoveredId] = (0, import_react30.useState)(null);
8333
+ const loadMoreRef = (0, import_react30.useRef)(null);
8334
+ const isLoadingRef = (0, import_react30.useRef)(isLoading);
7954
8335
  isLoadingRef.current = isLoading;
7955
- (0, import_react25.useEffect)(() => {
8336
+ (0, import_react30.useEffect)(() => {
7956
8337
  if (!hasMore || loadError || !onLoadMore) return;
7957
8338
  const sentinel = loadMoreRef.current;
7958
8339
  if (!sentinel) return;
@@ -7976,7 +8357,7 @@ var HistoryList = (0, import_react25.memo)(function HistoryList2({
7976
8357
  deleteText: "#ef4444",
7977
8358
  loadingDot: isDarkMode ? "rgba(255, 255, 255, 0.3)" : "rgba(0, 0, 0, 0.2)"
7978
8359
  };
7979
- const loadingDots = /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { display: "flex", justifyContent: "center", padding: "1.5rem 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { display: "flex", gap: "0.25rem" }, children: [0, 150, 300].map((delay) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8360
+ const loadingDots = /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { display: "flex", justifyContent: "center", padding: "1.5rem 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { display: "flex", gap: "0.25rem" }, children: [0, 150, 300].map((delay) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
7980
8361
  "span",
7981
8362
  {
7982
8363
  style: {
@@ -7994,13 +8375,13 @@ var HistoryList = (0, import_react25.memo)(function HistoryList2({
7994
8375
  return loadingDots;
7995
8376
  }
7996
8377
  if (conversations.length === 0) {
7997
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { textAlign: "center", color: colors.muted, padding: "1.5rem 0", fontSize: "0.875rem" }, children: strings.noHistory || "No conversations yet" });
8378
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { textAlign: "center", color: colors.muted, padding: "1.5rem 0", fontSize: "0.875rem" }, children: strings.noHistory || "No conversations yet" });
7998
8379
  }
7999
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { padding: "0.25rem 0.75rem 0" }, children: [
8380
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { padding: "0.25rem 0.75rem 0" }, children: [
8000
8381
  conversations.map((conv) => {
8001
8382
  const isSelected = conv.id === selectedId;
8002
8383
  const isHovered = conv.id === hoveredId;
8003
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
8384
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
8004
8385
  "div",
8005
8386
  {
8006
8387
  style: {
@@ -8018,17 +8399,17 @@ var HistoryList = (0, import_react25.memo)(function HistoryList2({
8018
8399
  onMouseEnter: () => setHoveredId(conv.id),
8019
8400
  onMouseLeave: () => setHoveredId(null),
8020
8401
  children: [
8021
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { minWidth: 0, flex: 1 }, children: [
8022
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: {
8402
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { minWidth: 0, flex: 1 }, children: [
8403
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: {
8023
8404
  fontSize: "0.875rem",
8024
8405
  color: colors.text,
8025
8406
  overflow: "hidden",
8026
8407
  textOverflow: "ellipsis",
8027
8408
  whiteSpace: "nowrap"
8028
8409
  }, children: conv.title || "Untitled" }),
8029
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { fontSize: "0.75rem", color: colors.muted }, children: formatRelativeTime(conv.updatedAt, strings) })
8410
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { fontSize: "0.75rem", color: colors.muted }, children: formatRelativeTime(conv.updatedAt, strings) })
8030
8411
  ] }),
8031
- isHovered && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8412
+ isHovered && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
8032
8413
  DeleteButton,
8033
8414
  {
8034
8415
  onClick: (e) => {
@@ -8044,15 +8425,234 @@ var HistoryList = (0, import_react25.memo)(function HistoryList2({
8044
8425
  conv.id
8045
8426
  );
8046
8427
  }),
8047
- hasMore && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref: loadMoreRef, style: { paddingTop: "0.5rem", textAlign: "center", minHeight: "2rem" }, children: isLoading ? loadingDots : loadError ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LoadMoreButton, { onClick: onLoadMore, colors, children: strings.loadMore || "Load more" }) : null })
8428
+ hasMore && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { ref: loadMoreRef, style: { paddingTop: "0.5rem", textAlign: "center", minHeight: "2rem" }, children: isLoading ? loadingDots : loadError ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(LoadMoreButton, { onClick: onLoadMore, colors, children: strings.loadMore || "Load more" }) : null })
8048
8429
  ] });
8049
8430
  });
8050
8431
 
8432
+ // src/renderer/components/HistoryModal.tsx
8433
+ var import_react31 = require("react");
8434
+ var import_jsx_runtime20 = require("react/jsx-runtime");
8435
+ var ANIMATION_DURATION = 120;
8436
+ var HistoryModal = (0, import_react31.memo)(function HistoryModal2({
8437
+ isOpen,
8438
+ onClose,
8439
+ title,
8440
+ closeLabel = "Close",
8441
+ children,
8442
+ isDarkMode = false
8443
+ }) {
8444
+ const modalRef = (0, import_react31.useRef)(null);
8445
+ const [isClosing, setIsClosing] = (0, import_react31.useState)(false);
8446
+ const [shouldRender, setShouldRender] = (0, import_react31.useState)(isOpen);
8447
+ (0, import_react31.useEffect)(() => {
8448
+ if (isOpen) {
8449
+ setShouldRender(true);
8450
+ setIsClosing(false);
8451
+ }
8452
+ }, [isOpen]);
8453
+ const handleClose = (0, import_react31.useCallback)(() => {
8454
+ setIsClosing(true);
8455
+ setTimeout(() => {
8456
+ setShouldRender(false);
8457
+ setIsClosing(false);
8458
+ onClose();
8459
+ }, ANIMATION_DURATION);
8460
+ }, [onClose]);
8461
+ (0, import_react31.useEffect)(() => {
8462
+ if (!shouldRender || isClosing) return;
8463
+ const handleKeyDown = (e) => {
8464
+ if (e.key === "Escape") {
8465
+ e.preventDefault();
8466
+ handleClose();
8467
+ }
8468
+ };
8469
+ document.addEventListener("keydown", handleKeyDown);
8470
+ return () => document.removeEventListener("keydown", handleKeyDown);
8471
+ }, [shouldRender, isClosing, handleClose]);
8472
+ (0, import_react31.useEffect)(() => {
8473
+ if (!isOpen || !modalRef.current) return;
8474
+ modalRef.current.focus();
8475
+ }, [isOpen]);
8476
+ const handleBackdropClick = (0, import_react31.useCallback)(
8477
+ (e) => {
8478
+ if (e.target === e.currentTarget && !isClosing) {
8479
+ handleClose();
8480
+ }
8481
+ },
8482
+ [handleClose, isClosing]
8483
+ );
8484
+ if (!shouldRender) return null;
8485
+ const closingClass = isClosing ? " chat-modal-closing" : "";
8486
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
8487
+ "div",
8488
+ {
8489
+ className: `chat-modal-backdrop${closingClass}`,
8490
+ style: {
8491
+ position: "absolute",
8492
+ inset: 0,
8493
+ zIndex: 50,
8494
+ display: "flex",
8495
+ alignItems: "center",
8496
+ justifyContent: "center",
8497
+ background: "rgba(0, 0, 0, 0.5)"
8498
+ },
8499
+ onClick: handleBackdropClick,
8500
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
8501
+ "div",
8502
+ {
8503
+ ref: modalRef,
8504
+ role: "dialog",
8505
+ "aria-modal": "true",
8506
+ "aria-labelledby": "history-modal-title",
8507
+ tabIndex: -1,
8508
+ className: `chat-modal-content${closingClass}`,
8509
+ style: {
8510
+ width: "80%",
8511
+ height: "70%",
8512
+ maxWidth: "600px",
8513
+ minHeight: "300px",
8514
+ background: "var(--chat-bg)",
8515
+ borderRadius: "12px",
8516
+ border: "1px solid var(--chat-border)",
8517
+ boxShadow: isDarkMode ? "0 25px 50px -12px rgba(0, 0, 0, 0.5)" : "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
8518
+ display: "flex",
8519
+ flexDirection: "column",
8520
+ overflow: "hidden",
8521
+ outline: "none"
8522
+ },
8523
+ onClick: (e) => e.stopPropagation(),
8524
+ children: [
8525
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
8526
+ "div",
8527
+ {
8528
+ style: {
8529
+ display: "flex",
8530
+ alignItems: "center",
8531
+ justifyContent: "space-between",
8532
+ padding: "8px 12px",
8533
+ borderBottom: "1px solid var(--chat-border)",
8534
+ flexShrink: 0
8535
+ },
8536
+ children: [
8537
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
8538
+ "span",
8539
+ {
8540
+ id: "history-modal-title",
8541
+ style: {
8542
+ fontSize: "0.8125rem",
8543
+ fontWeight: 500,
8544
+ color: "var(--chat-text)"
8545
+ },
8546
+ children: title
8547
+ }
8548
+ ),
8549
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
8550
+ "button",
8551
+ {
8552
+ onClick: handleClose,
8553
+ "aria-label": closeLabel,
8554
+ style: {
8555
+ display: "flex",
8556
+ alignItems: "center",
8557
+ justifyContent: "center",
8558
+ width: "22px",
8559
+ height: "22px",
8560
+ borderRadius: "4px",
8561
+ border: "none",
8562
+ background: "transparent",
8563
+ color: "var(--chat-muted)",
8564
+ cursor: "pointer",
8565
+ transition: "background 0.15s, color 0.15s"
8566
+ },
8567
+ onMouseEnter: (e) => {
8568
+ e.currentTarget.style.background = "var(--chat-hover)";
8569
+ e.currentTarget.style.color = "var(--chat-text)";
8570
+ },
8571
+ onMouseLeave: (e) => {
8572
+ e.currentTarget.style.background = "transparent";
8573
+ e.currentTarget.style.color = "var(--chat-muted)";
8574
+ },
8575
+ title: closeLabel,
8576
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
8577
+ "svg",
8578
+ {
8579
+ width: "14",
8580
+ height: "14",
8581
+ viewBox: "0 0 24 24",
8582
+ fill: "none",
8583
+ stroke: "currentColor",
8584
+ strokeWidth: "2",
8585
+ strokeLinecap: "round",
8586
+ strokeLinejoin: "round",
8587
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("path", { d: "M18 6L6 18M6 6l12 12" })
8588
+ }
8589
+ )
8590
+ }
8591
+ )
8592
+ ]
8593
+ }
8594
+ ),
8595
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
8596
+ "div",
8597
+ {
8598
+ style: {
8599
+ flex: 1,
8600
+ overflow: "auto",
8601
+ minHeight: 0
8602
+ },
8603
+ className: "chat-scrollbar",
8604
+ children
8605
+ }
8606
+ )
8607
+ ]
8608
+ }
8609
+ )
8610
+ }
8611
+ );
8612
+ });
8613
+
8051
8614
  // src/renderer/components/CompactChat.tsx
8052
- var import_react26 = require("react");
8615
+ var import_react32 = require("react");
8053
8616
  var import_react_dom = require("react-dom");
8054
- var import_jsx_runtime17 = require("react/jsx-runtime");
8055
- var CompactChat = (0, import_react26.memo)(function CompactChat2({
8617
+
8618
+ // src/renderer/components/PanelControls.tsx
8619
+ var import_jsx_runtime21 = require("react/jsx-runtime");
8620
+ function PanelHeaderButtons({
8621
+ showModeToggle = true,
8622
+ showAttachToggle = true,
8623
+ locale = "en"
8624
+ }) {
8625
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
8626
+ showModeToggle && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ModeToggleButton, { locale }),
8627
+ showAttachToggle && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(AttachButton, { locale })
8628
+ ] });
8629
+ }
8630
+ function PanelResizer({
8631
+ showResizer = true,
8632
+ resizerPosition = "left",
8633
+ resizerMinWidth = 280,
8634
+ resizerMaxWidth = 600
8635
+ }) {
8636
+ if (!showResizer) return null;
8637
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8638
+ Resizer,
8639
+ {
8640
+ position: resizerPosition,
8641
+ minWidth: resizerMinWidth,
8642
+ maxWidth: resizerMaxWidth
8643
+ }
8644
+ );
8645
+ }
8646
+ var PanelControls = {
8647
+ HeaderButtons: PanelHeaderButtons,
8648
+ Resizer: PanelResizer,
8649
+ ModeToggleButton,
8650
+ AttachButton
8651
+ };
8652
+
8653
+ // src/renderer/components/CompactChat.tsx
8654
+ var import_jsx_runtime22 = require("react/jsx-runtime");
8655
+ var CompactChat = (0, import_react32.memo)(function CompactChat2({
8056
8656
  adapter,
8057
8657
  config,
8058
8658
  logo,
@@ -8087,12 +8687,12 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8087
8687
  const { themeClass, isDarkMode: resolvedIsDarkMode } = useResolvedTheme(themeMode);
8088
8688
  const accentStyle = useAccentStyle(resolvedConfig?.accentColor);
8089
8689
  const resolvedLogo = logo ?? resolvedConfig?.logo;
8090
- const baseStrings = (0, import_react26.useMemo)(
8690
+ const baseStrings = (0, import_react32.useMemo)(
8091
8691
  () => resolveChatStrings(resolvedConfig?.locale, resolvedConfig?.strings),
8092
8692
  [resolvedConfig?.locale, resolvedConfig?.strings]
8093
8693
  );
8094
- const mergedStrings = (0, import_react26.useMemo)(() => ({ ...baseStrings, ...strings }), [baseStrings, strings]);
8095
- const headerConfig = (0, import_react26.useMemo)(
8694
+ const mergedStrings = (0, import_react32.useMemo)(() => ({ ...baseStrings, ...strings }), [baseStrings, strings]);
8695
+ const headerConfig = (0, import_react32.useMemo)(
8096
8696
  () => {
8097
8697
  if (!resolvedConfig) {
8098
8698
  return resolvedLogo ? { logo: resolvedLogo } : void 0;
@@ -8105,16 +8705,17 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8105
8705
  [resolvedConfig, resolvedLogo]
8106
8706
  );
8107
8707
  const { logoNode, showPin, showClose, isPinned, togglePin, resolvedOnClose } = useChatHeader(headerConfig);
8108
- const emptyLogoNode = (0, import_react26.useMemo)(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
8109
- const chatContainerRef = (0, import_react26.useRef)(null);
8110
- const chatInputRef = (0, import_react26.useRef)(null);
8111
- const [showHistory, setShowHistory] = (0, import_react26.useState)(false);
8112
- const [connectionAlert, setConnectionAlert] = (0, import_react26.useState)(null);
8113
- const portalContainerRef = (0, import_react26.useRef)(inputPortalContainer ?? null);
8708
+ const emptyLogoNode = (0, import_react32.useMemo)(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
8709
+ const { isEmbedded, toggleMode, hide: hidePanel } = useChatPanel();
8710
+ const chatContainerRef = (0, import_react32.useRef)(null);
8711
+ const chatInputRef = (0, import_react32.useRef)(null);
8712
+ const [showHistory, setShowHistory] = (0, import_react32.useState)(false);
8713
+ const [connectionAlert, setConnectionAlert] = (0, import_react32.useState)(null);
8714
+ const portalContainerRef = (0, import_react32.useRef)(inputPortalContainer ?? null);
8114
8715
  portalContainerRef.current = inputPortalContainer ?? null;
8115
8716
  const shouldRenderInputExternally = !!inputPortalContainer;
8116
8717
  const inputPlaceholder = placeholder ?? mergedStrings.inputPlaceholder;
8117
- const headerTitle = showHistory ? mergedStrings.recentChats || "Recent Chats" : mergedStrings.chat || "Chat";
8718
+ const headerTitle = mergedStrings.chat || "Chat";
8118
8719
  const connection = useConnection({
8119
8720
  adapter,
8120
8721
  autoConnect,
@@ -8148,27 +8749,27 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8148
8749
  adapter,
8149
8750
  onError
8150
8751
  });
8151
- (0, import_react26.useEffect)(() => {
8752
+ (0, import_react32.useEffect)(() => {
8152
8753
  if (sendMessageRef) {
8153
8754
  sendMessageRef.current = chat.sendMessage;
8154
8755
  }
8155
8756
  }, [sendMessageRef, chat.sendMessage]);
8156
- (0, import_react26.useEffect)(() => {
8757
+ (0, import_react32.useEffect)(() => {
8157
8758
  if (newConversationRef) {
8158
8759
  newConversationRef.current = chat.newConversation;
8159
8760
  }
8160
8761
  }, [newConversationRef, chat.newConversation]);
8161
- (0, import_react26.useEffect)(() => {
8762
+ (0, import_react32.useEffect)(() => {
8162
8763
  if (parentFocusInputRef) {
8163
8764
  parentFocusInputRef.current = () => chatInputRef.current?.focus();
8164
8765
  }
8165
8766
  }, [parentFocusInputRef]);
8166
- (0, import_react26.useEffect)(() => {
8767
+ (0, import_react32.useEffect)(() => {
8167
8768
  if (parentSetTextRef) {
8168
8769
  parentSetTextRef.current = (text) => chatInputRef.current?.setValue(text);
8169
8770
  }
8170
8771
  }, [parentSetTextRef]);
8171
- (0, import_react26.useEffect)(() => {
8772
+ (0, import_react32.useEffect)(() => {
8172
8773
  if (onMessageReceived && chat.messages.length > 0) {
8173
8774
  const lastMessage = chat.messages[chat.messages.length - 1];
8174
8775
  if (lastMessage.role === "assistant" && !lastMessage.isStreaming) {
@@ -8176,12 +8777,12 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8176
8777
  }
8177
8778
  }
8178
8779
  }, [chat.messages, onMessageReceived]);
8179
- (0, import_react26.useEffect)(() => {
8780
+ (0, import_react32.useEffect)(() => {
8180
8781
  if (onLoadingChange) {
8181
8782
  onLoadingChange(chat.isLoading);
8182
8783
  }
8183
8784
  }, [chat.isLoading, onLoadingChange]);
8184
- (0, import_react26.useEffect)(() => {
8785
+ (0, import_react32.useEffect)(() => {
8185
8786
  if (onStateChange) {
8186
8787
  onStateChange({
8187
8788
  messages: chat.messages,
@@ -8189,19 +8790,19 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8189
8790
  });
8190
8791
  }
8191
8792
  }, [chat.messages, chat.conversationId, onStateChange]);
8192
- (0, import_react26.useEffect)(() => {
8793
+ (0, import_react32.useEffect)(() => {
8193
8794
  if (showHistory && connection.isConnected) {
8194
8795
  conversations.loadConversations();
8195
8796
  }
8196
8797
  }, [showHistory, connection.isConnected]);
8197
- const handleSelectConversation = (0, import_react26.useCallback)(
8798
+ const handleSelectConversation = (0, import_react32.useCallback)(
8198
8799
  async (id) => {
8199
8800
  await chat.loadConversation(id);
8200
8801
  setShowHistory(false);
8201
8802
  },
8202
8803
  [chat]
8203
8804
  );
8204
- const handleDeleteConversation = (0, import_react26.useCallback)(
8805
+ const handleDeleteConversation = (0, import_react32.useCallback)(
8205
8806
  async (id) => {
8206
8807
  await conversations.deleteConversation(id);
8207
8808
  if (id === chat.conversationId) {
@@ -8210,14 +8811,14 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8210
8811
  },
8211
8812
  [conversations, chat]
8212
8813
  );
8213
- const handleNewChat = (0, import_react26.useCallback)(() => {
8814
+ const handleNewChat = (0, import_react32.useCallback)(() => {
8214
8815
  chat.newConversation();
8215
8816
  setShowHistory(false);
8216
8817
  setTimeout(() => {
8217
8818
  chatInputRef.current?.focus();
8218
8819
  }, 0);
8219
8820
  }, [chat]);
8220
- (0, import_react26.useEffect)(() => {
8821
+ (0, import_react32.useEffect)(() => {
8221
8822
  const handleKeyDown = (e) => {
8222
8823
  const isMac2 = navigator.platform.includes("Mac");
8223
8824
  const modifierKey = isMac2 ? e.metaKey : e.ctrlKey;
@@ -8231,7 +8832,7 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8231
8832
  }, [handleNewChat]);
8232
8833
  const isMac = typeof navigator !== "undefined" && navigator.platform.includes("Mac");
8233
8834
  const shortcutKey = isMac ? "\u2318N" : "Ctrl+N";
8234
- const defaultRenderMessage = (0, import_react26.useCallback)((message) => {
8835
+ const defaultRenderMessage = (0, import_react32.useCallback)((message) => {
8235
8836
  if (message.role === "tool") return null;
8236
8837
  const isUser = message.role === "user";
8237
8838
  const hasToolCalls = message.toolCalls && message.toolCalls.length > 0;
@@ -8243,9 +8844,9 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8243
8844
  const hasThinking = message.thinking || message.isThinkingStreaming || message.currentThinking;
8244
8845
  const showThinkingSection = !isUser && !hasToolActivity && !showIntermediateSteps && hasThinking;
8245
8846
  const isToolCallsStreaming = message.isToolCallsStreaming ?? ((message.toolCalls?.some((tc) => tc.status === "running") ?? false) || (message.blocks?.some((b) => b.type === "tool_call" && b.toolStatus === "running") ?? false));
8246
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: `flex ${isUser ? "justify-end" : "justify-start"} mb-4`, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: `text-left ${isUser ? "max-w-[80%]" : "w-full"}`, children: [
8247
- !isUser && showIntermediateSteps && message.blocks && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IntermediateSteps, { blocks: message.blocks, strings: mergedStrings }),
8248
- showThinkingSection && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8847
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: `flex ${isUser ? "justify-end" : "justify-start"} mb-4`, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: `text-left ${isUser ? "max-w-[80%]" : "w-full"}`, children: [
8848
+ !isUser && showIntermediateSteps && message.blocks && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(IntermediateSteps, { blocks: message.blocks, strings: mergedStrings }),
8849
+ showThinkingSection && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8249
8850
  ThinkingSection,
8250
8851
  {
8251
8852
  thinking: message.thinking || "",
@@ -8256,7 +8857,7 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8256
8857
  strings: mergedStrings
8257
8858
  }
8258
8859
  ),
8259
- showStreamingTimeline && message.blocks && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8860
+ showStreamingTimeline && message.blocks && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8260
8861
  StreamingTimeline,
8261
8862
  {
8262
8863
  blocks: message.blocks,
@@ -8267,23 +8868,22 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8267
8868
  strings: mergedStrings
8268
8869
  }
8269
8870
  ),
8270
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: `relative group ${isUser ? "inline-block max-w-full" : "block w-full"}`, style: { fontSize: "0.875rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8871
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: `relative group ${isUser ? "inline-block max-w-full" : "block w-full"}`, style: { fontSize: "0.875rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8271
8872
  "div",
8272
8873
  {
8273
8874
  className: `message-bubble-wrapper ${isUser ? "rounded-2xl shadow-sm bg-[var(--chat-accent)] text-white px-4 py-3 whitespace-pre-wrap break-words" : "text-[var(--chat-text)] break-words"}`,
8274
- children: isUser ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "whitespace-pre-wrap", children: message.content }) : message.content && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MarkdownRenderer, { content: message.content, isStreaming: message.isStreaming, className: "px-3" })
8875
+ children: isUser ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "whitespace-pre-wrap", children: message.content }) : message.content && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(MarkdownRenderer, { content: message.content, isStreaming: message.isStreaming, className: "px-3" })
8275
8876
  }
8276
8877
  ) })
8277
8878
  ] }) });
8278
8879
  }, [mergedStrings]);
8279
- const containerClass = floating ? `chat-window-container ${themeClass} ${className}` : `flex h-full flex-col bg-[var(--chat-bg)] text-[var(--chat-text)] ${themeClass} ${className}`;
8280
- const baseColors = (0, import_react26.useMemo)(() => {
8880
+ const containerClass = floating ? `relative chat-window-container ${themeClass} ${className}` : `relative flex h-full flex-col bg-[var(--chat-bg)] text-[var(--chat-text)] ${themeClass} ${className}`;
8881
+ const baseColors = (0, import_react32.useMemo)(() => {
8281
8882
  if (!floating) return null;
8282
8883
  return getBaseColors(resolvedIsDarkMode);
8283
8884
  }, [floating, resolvedIsDarkMode]);
8284
- const containerStyle = (0, import_react26.useMemo)(() => {
8285
- if (!floating || !baseColors) return accentStyle;
8286
- return {
8885
+ const containerStyle = (0, import_react32.useMemo)(() => {
8886
+ const baseStyle = floating && baseColors ? {
8287
8887
  ...accentStyle,
8288
8888
  // Override CSS variables with tinted colors for consistency with app
8289
8889
  "--chat-bg": baseColors.bg,
@@ -8291,9 +8891,17 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8291
8891
  "--chat-card": baseColors.card,
8292
8892
  "--chat-window-bg": baseColors.bg,
8293
8893
  "--chat-window-border": resolvedIsDarkMode ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.1)"
8294
- };
8295
- }, [floating, baseColors, accentStyle, resolvedIsDarkMode]);
8296
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8894
+ } : accentStyle;
8895
+ if (isEmbedded) {
8896
+ return {
8897
+ ...baseStyle,
8898
+ borderRadius: 0,
8899
+ boxShadow: "none"
8900
+ };
8901
+ }
8902
+ return baseStyle;
8903
+ }, [floating, baseColors, accentStyle, resolvedIsDarkMode, isEmbedded]);
8904
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
8297
8905
  "div",
8298
8906
  {
8299
8907
  ref: chatContainerRef,
@@ -8301,103 +8909,172 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8301
8909
  style: containerStyle,
8302
8910
  "data-chat-font-size": resolvedConfig?.fontSize || "normal",
8303
8911
  children: [
8304
- !hideHeader && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("header", { className: "flex h-9 flex-shrink-0 items-center px-2 border-b chat-divider-border", style: { WebkitAppRegion: "drag" }, children: [
8305
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-1", style: { WebkitAppRegion: "no-drag" }, children: [
8306
- showHistory && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8307
- "button",
8308
- {
8309
- onClick: () => setShowHistory(false),
8310
- className: headerIconButtonClass,
8311
- title: "Back",
8312
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M15 19l-7-7 7-7", strokeLinecap: "round", strokeLinejoin: "round" }) })
8313
- }
8314
- ),
8315
- headerLeft || /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2", children: [
8316
- logoNode,
8317
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-sm font-medium text-[var(--chat-text)]", children: headerTitle })
8318
- ] })
8319
- ] }),
8320
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex-1" }),
8321
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-0.5", style: { WebkitAppRegion: "no-drag" }, children: [
8322
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "chat-tooltip-wrapper", children: [
8323
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8912
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PanelResizer, {}),
8913
+ !hideHeader && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("header", { className: "flex h-9 flex-shrink-0 items-center px-2 border-b chat-divider-border", style: { WebkitAppRegion: "drag" }, children: isEmbedded ? (
8914
+ // Embedded mode: left-aligned buttons (collapse, float, history, new chat)
8915
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-0.5", style: { WebkitAppRegion: "no-drag" }, children: [
8916
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "chat-tooltip-wrapper", children: [
8917
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8918
+ "button",
8919
+ {
8920
+ onClick: hidePanel,
8921
+ className: headerIconButtonClass,
8922
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
8923
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
8924
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M15 4v16", strokeLinecap: "round" })
8925
+ ] })
8926
+ }
8927
+ ),
8928
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "chat-tooltip", children: mergedStrings.collapseSidebar })
8929
+ ] }),
8930
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "chat-tooltip-wrapper", children: [
8931
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8932
+ "button",
8933
+ {
8934
+ onClick: toggleMode,
8935
+ className: headerIconButtonClass,
8936
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
8937
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("rect", { x: "8", y: "3", width: "13", height: "13", rx: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
8938
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M5 8H4a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-1", strokeLinecap: "round", strokeLinejoin: "round" })
8939
+ ] })
8940
+ }
8941
+ ),
8942
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "chat-tooltip", children: mergedStrings.floatWindow })
8943
+ ] }),
8944
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "chat-tooltip-wrapper", children: [
8945
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8946
+ "button",
8947
+ {
8948
+ onClick: () => setShowHistory(true),
8949
+ className: headerIconButtonClass,
8950
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z", strokeLinecap: "round", strokeLinejoin: "round" }) })
8951
+ }
8952
+ ),
8953
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "chat-tooltip", children: mergedStrings.history || mergedStrings.recentChats })
8954
+ ] }),
8955
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "chat-tooltip-wrapper", children: [
8956
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8324
8957
  "button",
8325
8958
  {
8326
8959
  onClick: handleNewChat,
8327
8960
  className: headerIconButtonClass,
8328
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M12 5v14m-7-7h14", strokeLinecap: "round", strokeLinejoin: "round" }) })
8961
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M12 5v14m-7-7h14", strokeLinecap: "round", strokeLinejoin: "round" }) })
8329
8962
  }
8330
8963
  ),
8331
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "chat-tooltip", children: [
8332
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { children: mergedStrings.newChat || "New Chat" }),
8333
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "chat-tooltip-shortcut", children: shortcutKey })
8964
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "chat-tooltip", children: [
8965
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { children: mergedStrings.newChat || "New Chat" }),
8966
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "chat-tooltip-shortcut", children: shortcutKey })
8334
8967
  ] })
8335
8968
  ] }),
8336
- !showHistory && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8337
- "button",
8338
- {
8339
- onClick: () => setShowHistory(true),
8340
- className: headerIconButtonClass,
8341
- title: mergedStrings.recentChats || "Recent Chats",
8342
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z", strokeLinecap: "round", strokeLinejoin: "round" }) })
8343
- }
8344
- ),
8345
- showPin && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8346
- "button",
8347
- {
8348
- onClick: togglePin,
8349
- className: headerIconButtonClass,
8350
- title: isPinned ? mergedStrings.unpin : mergedStrings.pin,
8351
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: isPinned ? (
8352
- // Pin (active state) - lucide pin
8353
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
8354
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M12 17v5" }),
8355
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z" })
8356
- ] })
8357
- ) : (
8358
- // PinOff (inactive state) - lucide pin-off
8359
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
8360
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M12 17v5" }),
8361
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M15 9.34V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H7.89" }),
8362
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "m2 2 20 20" }),
8363
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M9 9v1.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h11" })
8364
- ] })
8365
- ) })
8366
- }
8367
- ),
8368
- showClose && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8369
- "button",
8370
- {
8371
- onClick: resolvedOnClose,
8372
- className: headerIconButtonClass,
8373
- title: mergedStrings.close,
8374
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M6 6l12 12M18 6l-12 12", strokeLinecap: "round", strokeLinejoin: "round" }) })
8375
- }
8376
- ),
8377
8969
  headerRight
8378
8970
  ] })
8379
- ] }),
8380
- showHistory ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex-1 overflow-y-auto chat-scrollbar pt-2", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8381
- HistoryList,
8971
+ ) : (
8972
+ // Floating mode: original layout with logo, title, and right-aligned buttons
8973
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
8974
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex items-center gap-1", style: { WebkitAppRegion: "no-drag" }, children: headerLeft || /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-2", children: [
8975
+ logoNode,
8976
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-sm font-medium text-[var(--chat-text)]", children: headerTitle })
8977
+ ] }) }),
8978
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex-1" }),
8979
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-0.5", style: { WebkitAppRegion: "no-drag" }, children: [
8980
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PanelHeaderButtons, { locale: resolvedConfig?.locale }),
8981
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "chat-tooltip-wrapper", children: [
8982
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8983
+ "button",
8984
+ {
8985
+ onClick: handleNewChat,
8986
+ className: headerIconButtonClass,
8987
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M12 5v14m-7-7h14", strokeLinecap: "round", strokeLinejoin: "round" }) })
8988
+ }
8989
+ ),
8990
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "chat-tooltip", children: [
8991
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { children: mergedStrings.newChat || "New Chat" }),
8992
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "chat-tooltip-shortcut", children: shortcutKey })
8993
+ ] })
8994
+ ] }),
8995
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "chat-tooltip-wrapper", children: [
8996
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8997
+ "button",
8998
+ {
8999
+ onClick: () => setShowHistory(true),
9000
+ className: headerIconButtonClass,
9001
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z", strokeLinecap: "round", strokeLinejoin: "round" }) })
9002
+ }
9003
+ ),
9004
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "chat-tooltip", children: mergedStrings.recentChats || "Recent Chats" })
9005
+ ] }),
9006
+ showPin && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "chat-tooltip-wrapper", children: [
9007
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
9008
+ "button",
9009
+ {
9010
+ onClick: togglePin,
9011
+ className: headerIconButtonClass,
9012
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: isPinned ? (
9013
+ // Pin (active state) - lucide pin
9014
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
9015
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M12 17v5" }),
9016
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z" })
9017
+ ] })
9018
+ ) : (
9019
+ // PinOff (inactive state) - lucide pin-off
9020
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
9021
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M12 17v5" }),
9022
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M15 9.34V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H7.89" }),
9023
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "m2 2 20 20" }),
9024
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M9 9v1.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h11" })
9025
+ ] })
9026
+ ) })
9027
+ }
9028
+ ),
9029
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "chat-tooltip", children: isPinned ? mergedStrings.unpin : mergedStrings.pin })
9030
+ ] }),
9031
+ showClose && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "chat-tooltip-wrapper", children: [
9032
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
9033
+ "button",
9034
+ {
9035
+ onClick: resolvedOnClose,
9036
+ className: headerIconButtonClass,
9037
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M6 6l12 12M18 6l-12 12", strokeLinecap: "round", strokeLinejoin: "round" }) })
9038
+ }
9039
+ ),
9040
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "chat-tooltip", children: mergedStrings.close })
9041
+ ] }),
9042
+ headerRight
9043
+ ] })
9044
+ ] })
9045
+ ) }),
9046
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
9047
+ HistoryModal,
8382
9048
  {
8383
- conversations: conversations.conversations,
8384
- selectedId: chat.conversationId,
8385
- isLoading: conversations.isLoading,
8386
- hasMore: conversations.hasMore,
8387
- loadError: conversations.loadError,
8388
- onSelect: handleSelectConversation,
8389
- onDelete: handleDeleteConversation,
8390
- onLoadMore: conversations.loadMore,
9049
+ isOpen: showHistory,
9050
+ onClose: () => setShowHistory(false),
9051
+ title: mergedStrings.recentChats || "Recent Chats",
9052
+ closeLabel: mergedStrings.close || "Close",
8391
9053
  isDarkMode: resolvedIsDarkMode,
8392
- strings: {
8393
- noHistory: mergedStrings.noHistory,
8394
- loadMore: mergedStrings.loadMore,
8395
- today: mergedStrings.today,
8396
- yesterday: mergedStrings.yesterday,
8397
- delete: mergedStrings.delete
8398
- }
9054
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
9055
+ HistoryList,
9056
+ {
9057
+ conversations: conversations.conversations,
9058
+ selectedId: chat.conversationId,
9059
+ isLoading: conversations.isLoading,
9060
+ hasMore: conversations.hasMore,
9061
+ loadError: conversations.loadError,
9062
+ onSelect: handleSelectConversation,
9063
+ onDelete: handleDeleteConversation,
9064
+ onLoadMore: conversations.loadMore,
9065
+ isDarkMode: resolvedIsDarkMode,
9066
+ strings: {
9067
+ noHistory: mergedStrings.noHistory,
9068
+ loadMore: mergedStrings.loadMore,
9069
+ today: mergedStrings.today,
9070
+ yesterday: mergedStrings.yesterday,
9071
+ delete: mergedStrings.delete
9072
+ }
9073
+ }
9074
+ )
8399
9075
  }
8400
- ) }) : chat.messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex flex-1 items-center justify-center p-4", children: emptyState ?? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex items-center justify-center", children: emptyLogoNode }) }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
9076
+ ),
9077
+ chat.messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex flex-1 items-center justify-center p-4", children: emptyState ?? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex items-center justify-center", children: emptyLogoNode }) }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8401
9078
  MessageList,
8402
9079
  {
8403
9080
  messages: chat.messages,
@@ -8407,83 +9084,80 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8407
9084
  ),
8408
9085
  (() => {
8409
9086
  if (hideInput && !shouldRenderInputExternally) return null;
8410
- const disableInput = showHistory || !!chat.pendingInterrupt || chat.isLoading && !chat.isStreaming;
8411
- const inputElement = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
9087
+ const disableInput = !!chat.pendingInterrupt || chat.isLoading && !chat.isStreaming;
9088
+ const inputElement = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8412
9089
  ChatInput,
8413
9090
  {
8414
9091
  ref: chatInputRef,
8415
9092
  onSend: chat.sendMessage,
8416
9093
  onStop: chat.stopStreaming,
8417
- placeholder: showHistory ? mergedStrings.selectConversation : inputPlaceholder,
9094
+ placeholder: inputPlaceholder,
8418
9095
  sendLabel: mergedStrings.inputSend,
8419
9096
  stopLabel: mergedStrings.inputStop,
8420
9097
  disabled: disableInput,
8421
9098
  isStreaming: chat.isStreaming,
8422
9099
  isLoading: chat.isLoading,
8423
- autoFocus: !showHistory,
8424
- className: showHistory ? "opacity-50" : ""
9100
+ autoFocus: true
8425
9101
  }
8426
9102
  );
8427
9103
  if (shouldRenderInputExternally && portalContainerRef.current) {
8428
9104
  return (0, import_react_dom.createPortal)(inputElement, portalContainerRef.current);
8429
9105
  }
8430
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col gap-2 px-3 pb-3 pt-1", children: [
8431
- !showHistory && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
8432
- alert ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8433
- AlertBanner,
8434
- {
8435
- type: alert.type,
8436
- message: alert.message,
8437
- action: alert.action,
8438
- onDismiss: alert.dismissible ? onAlertDismiss : void 0,
8439
- className: `flex items-center gap-2 rounded-xl px-3 py-2 text-sm ${alert.type === "error" ? resolvedIsDarkMode ? "bg-red-900/60 text-red-200" : "bg-red-100 text-red-800" : resolvedIsDarkMode ? "bg-amber-900/60 text-amber-200" : "bg-amber-100 text-amber-800"}`
8440
- }
8441
- ) : connectionAlert ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8442
- AlertBanner,
8443
- {
8444
- type: connectionAlert.type,
8445
- message: connectionAlert.message,
8446
- action: connectionAlert.action,
8447
- onDismiss: connectionAlert.dismissible ? () => setConnectionAlert(null) : void 0,
8448
- className: `flex items-center gap-2 rounded-xl px-3 py-2 text-sm ${connectionAlert.type === "error" ? resolvedIsDarkMode ? "bg-red-900/60 text-red-200" : "bg-red-100 text-red-800" : resolvedIsDarkMode ? "bg-amber-900/60 text-amber-200" : "bg-amber-100 text-amber-800"}`
8449
- }
8450
- ) : chat.error && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8451
- AlertBanner,
8452
- {
8453
- type: "error",
8454
- message: chat.error,
8455
- onDismiss: () => chat.setError(null),
8456
- className: `flex items-center gap-2 rounded-xl px-3 py-2 text-sm ${resolvedIsDarkMode ? "bg-red-900/60 text-red-200" : "bg-red-100 text-red-800"}`
8457
- }
8458
- ),
8459
- chat.pendingInterrupt && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8460
- HitlCard,
8461
- {
8462
- interrupt: chat.pendingInterrupt,
8463
- onApprove: chat.approveHitl,
8464
- onReject: chat.rejectHitl,
8465
- onSubmit: chat.submitHitlInput,
8466
- isDarkMode: resolvedIsDarkMode,
8467
- strings: {
8468
- approve: mergedStrings.hitlApprove,
8469
- reject: mergedStrings.hitlReject,
8470
- submit: mergedStrings.hitlSubmit,
8471
- cancel: mergedStrings.hitlCancel,
8472
- rememberChoice: mergedStrings.hitlRememberChoice,
8473
- requiredField: mergedStrings.hitlRequiredField,
8474
- timeoutIn: mergedStrings.hitlTimeoutIn,
8475
- seconds: mergedStrings.hitlSeconds,
8476
- executeTool: mergedStrings.hitlExecuteTool,
8477
- toolLabel: mergedStrings.hitlToolLabel,
8478
- argsLabel: mergedStrings.hitlArgsLabel,
8479
- defaultPrefix: mergedStrings.hitlDefaultPrefix,
8480
- enterResponse: mergedStrings.hitlEnterResponse,
8481
- approvalRequest: mergedStrings.hitlApprovalRequest,
8482
- inputRequest: mergedStrings.hitlInputRequest
8483
- }
9106
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex flex-col gap-2 px-3 pb-3 pt-1", children: [
9107
+ alert ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
9108
+ AlertBanner,
9109
+ {
9110
+ type: alert.type,
9111
+ message: alert.message,
9112
+ action: alert.action,
9113
+ onDismiss: alert.dismissible ? onAlertDismiss : void 0,
9114
+ className: `flex items-center gap-2 rounded-xl px-3 py-2 text-sm ${alert.type === "error" ? resolvedIsDarkMode ? "bg-red-900/60 text-red-200" : "bg-red-100 text-red-800" : resolvedIsDarkMode ? "bg-amber-900/60 text-amber-200" : "bg-amber-100 text-amber-800"}`
9115
+ }
9116
+ ) : connectionAlert ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
9117
+ AlertBanner,
9118
+ {
9119
+ type: connectionAlert.type,
9120
+ message: connectionAlert.message,
9121
+ action: connectionAlert.action,
9122
+ onDismiss: connectionAlert.dismissible ? () => setConnectionAlert(null) : void 0,
9123
+ className: `flex items-center gap-2 rounded-xl px-3 py-2 text-sm ${connectionAlert.type === "error" ? resolvedIsDarkMode ? "bg-red-900/60 text-red-200" : "bg-red-100 text-red-800" : resolvedIsDarkMode ? "bg-amber-900/60 text-amber-200" : "bg-amber-100 text-amber-800"}`
9124
+ }
9125
+ ) : chat.error ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
9126
+ AlertBanner,
9127
+ {
9128
+ type: "error",
9129
+ message: chat.error,
9130
+ onDismiss: () => chat.setError(null),
9131
+ className: `flex items-center gap-2 rounded-xl px-3 py-2 text-sm ${resolvedIsDarkMode ? "bg-red-900/60 text-red-200" : "bg-red-100 text-red-800"}`
9132
+ }
9133
+ ) : null,
9134
+ chat.pendingInterrupt && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
9135
+ HitlCard,
9136
+ {
9137
+ interrupt: chat.pendingInterrupt,
9138
+ onApprove: chat.approveHitl,
9139
+ onReject: chat.rejectHitl,
9140
+ onSubmit: chat.submitHitlInput,
9141
+ isDarkMode: resolvedIsDarkMode,
9142
+ strings: {
9143
+ approve: mergedStrings.hitlApprove,
9144
+ reject: mergedStrings.hitlReject,
9145
+ submit: mergedStrings.hitlSubmit,
9146
+ cancel: mergedStrings.hitlCancel,
9147
+ rememberChoice: mergedStrings.hitlRememberChoice,
9148
+ requiredField: mergedStrings.hitlRequiredField,
9149
+ timeoutIn: mergedStrings.hitlTimeoutIn,
9150
+ seconds: mergedStrings.hitlSeconds,
9151
+ executeTool: mergedStrings.hitlExecuteTool,
9152
+ toolLabel: mergedStrings.hitlToolLabel,
9153
+ argsLabel: mergedStrings.hitlArgsLabel,
9154
+ defaultPrefix: mergedStrings.hitlDefaultPrefix,
9155
+ enterResponse: mergedStrings.hitlEnterResponse,
9156
+ approvalRequest: mergedStrings.hitlApprovalRequest,
9157
+ inputRequest: mergedStrings.hitlInputRequest
8484
9158
  }
8485
- )
8486
- ] }),
9159
+ }
9160
+ ),
8487
9161
  inputElement
8488
9162
  ] });
8489
9163
  })()
@@ -8494,16 +9168,23 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8494
9168
  // Annotate the CommonJS export names for ESM import in node:
8495
9169
  0 && (module.exports = {
8496
9170
  AlertBanner,
9171
+ AttachButton,
8497
9172
  ChatInput,
8498
9173
  CompactChat,
8499
9174
  FloatingChat,
8500
9175
  HistoryList,
9176
+ HistoryModal,
8501
9177
  HitlCard,
8502
9178
  I18nProvider,
8503
9179
  IntermediateSteps,
8504
9180
  MarkdownRenderer,
8505
9181
  MessageBubble,
8506
9182
  MessageList,
9183
+ ModeToggleButton,
9184
+ PanelControls,
9185
+ PanelHeaderButtons,
9186
+ PanelResizer,
9187
+ Resizer,
8507
9188
  SanqianChat,
8508
9189
  SanqianChatMessage,
8509
9190
  SanqianMessageList,
@@ -8519,7 +9200,9 @@ var CompactChat = (0, import_react26.memo)(function CompactChat2({
8519
9200
  ensureFullChatStyles,
8520
9201
  getTranslations,
8521
9202
  resolveChatStrings,
9203
+ useAttachState,
8522
9204
  useChat,
9205
+ useChatPanel,
8523
9206
  useChatStyles,
8524
9207
  useConnection,
8525
9208
  useConversations,