@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.
@@ -861,7 +861,14 @@ var CHAT_UI_STRINGS = {
861
861
  hitlApprovalRequest: "Approval Request",
862
862
  hitlInputRequest: "Input Request",
863
863
  hitlApprovalRequired: "Approval Required",
864
- hitlInputRequired: "Input Required"
864
+ hitlInputRequired: "Input Required",
865
+ // ChatPanel strings
866
+ attachWindow: "Dock",
867
+ detachWindow: "Undock",
868
+ floatWindow: "Float",
869
+ embedWindow: "Embed",
870
+ collapseSidebar: "Collapse",
871
+ history: "History"
865
872
  },
866
873
  zh: {
867
874
  inputPlaceholder: "\u8F93\u5165\u6D88\u606F...",
@@ -911,7 +918,14 @@ var CHAT_UI_STRINGS = {
911
918
  hitlApprovalRequest: "\u9700\u8981\u5BA1\u6279",
912
919
  hitlInputRequest: "\u9700\u8981\u8F93\u5165",
913
920
  hitlApprovalRequired: "\u9700\u8981\u5BA1\u6279",
914
- hitlInputRequired: "\u9700\u8981\u8F93\u5165"
921
+ hitlInputRequired: "\u9700\u8981\u8F93\u5165",
922
+ // ChatPanel strings
923
+ attachWindow: "\u5438\u9644",
924
+ detachWindow: "\u5206\u79BB",
925
+ floatWindow: "\u6D6E\u52A8",
926
+ embedWindow: "\u5D4C\u5165",
927
+ collapseSidebar: "\u6536\u8D77",
928
+ history: "\u5386\u53F2"
915
929
  }
916
930
  };
917
931
  function resolveChatStrings(locale = "en", overrides) {
@@ -955,6 +969,12 @@ var toTranslations = (flat) => ({
955
969
  untitled: flat.conversationUntitled,
956
970
  delete: flat.delete,
957
971
  deleteConfirm: flat.conversationDeleteConfirm
972
+ },
973
+ panel: {
974
+ attachWindow: flat.attachWindow,
975
+ detachWindow: flat.detachWindow,
976
+ floatWindow: flat.floatWindow,
977
+ embedWindow: flat.embedWindow
958
978
  }
959
979
  });
960
980
  var I18nContext = createContext2(null);
@@ -992,7 +1012,8 @@ function I18nProvider({
992
1012
  input: { ...base.input, ...custom.input },
993
1013
  message: { ...base.message, ...custom.message },
994
1014
  connection: { ...base.connection, ...custom.connection },
995
- conversation: { ...base.conversation, ...custom.conversation }
1015
+ conversation: { ...base.conversation, ...custom.conversation },
1016
+ panel: { ...base.panel, ...custom.panel }
996
1017
  };
997
1018
  }, [locale, customTranslations]);
998
1019
  return /* @__PURE__ */ jsx2(I18nContext.Provider, { value: { locale, setLocale, t }, children });
@@ -1428,6 +1449,43 @@ code {
1428
1449
  animation: chat-fade-in 0.2s ease-out;
1429
1450
  }
1430
1451
 
1452
+ /* Modal animations */
1453
+ @keyframes chat-modal-fade-in {
1454
+ from { opacity: 0; }
1455
+ to { opacity: 1; }
1456
+ }
1457
+
1458
+ @keyframes chat-modal-fade-out {
1459
+ from { opacity: 1; }
1460
+ to { opacity: 0; }
1461
+ }
1462
+
1463
+ @keyframes chat-modal-slide-in {
1464
+ from { opacity: 0; transform: scale(0.95); }
1465
+ to { opacity: 1; transform: scale(1); }
1466
+ }
1467
+
1468
+ @keyframes chat-modal-slide-out {
1469
+ from { opacity: 1; transform: scale(1); }
1470
+ to { opacity: 0; transform: scale(0.95); }
1471
+ }
1472
+
1473
+ .chat-modal-backdrop {
1474
+ animation: chat-modal-fade-in 0.15s ease-out forwards;
1475
+ }
1476
+
1477
+ .chat-modal-backdrop.chat-modal-closing {
1478
+ animation: chat-modal-fade-out 0.12s ease-in forwards;
1479
+ }
1480
+
1481
+ .chat-modal-content {
1482
+ animation: chat-modal-slide-in 0.15s ease-out forwards;
1483
+ }
1484
+
1485
+ .chat-modal-content.chat-modal-closing {
1486
+ animation: chat-modal-slide-out 0.12s ease-in forwards;
1487
+ }
1488
+
1431
1489
  /* ========================================
1432
1490
  Prose Overrides
1433
1491
  ======================================== */
@@ -4969,6 +5027,136 @@ function useResolvedUiConfig(config) {
4969
5027
  }, [ipcConfig, config]);
4970
5028
  }
4971
5029
 
5030
+ // src/renderer/hooks/useChatPanel.ts
5031
+ import { useState as useState7, useEffect as useEffect8, useCallback as useCallback6 } from "react";
5032
+ var getChatPanelApi = () => {
5033
+ return window.chatPanel;
5034
+ };
5035
+ function useChatPanel() {
5036
+ const [mode, setModeState] = useState7("embedded");
5037
+ const [visible, setVisible] = useState7(false);
5038
+ const [width, setWidthState] = useState7(360);
5039
+ useEffect8(() => {
5040
+ const api = getChatPanelApi();
5041
+ if (!api) {
5042
+ console.warn("[useChatPanel] chatPanel API not available");
5043
+ return;
5044
+ }
5045
+ api.getMode?.().then(setModeState).catch(() => {
5046
+ });
5047
+ api.isVisible?.().then(setVisible).catch(() => {
5048
+ });
5049
+ api.getWidth?.().then(setWidthState).catch(() => {
5050
+ });
5051
+ const unsubMode = api.onModeChanged?.(setModeState);
5052
+ const unsubVisible = api.onVisibilityChanged?.(setVisible);
5053
+ return () => {
5054
+ unsubMode?.();
5055
+ unsubVisible?.();
5056
+ };
5057
+ }, []);
5058
+ const setMode = useCallback6(async (newMode) => {
5059
+ const api = getChatPanelApi();
5060
+ if (!api?.setMode) return;
5061
+ await api.setMode(newMode);
5062
+ setModeState(newMode);
5063
+ }, []);
5064
+ const toggleMode = useCallback6(async () => {
5065
+ const api = getChatPanelApi();
5066
+ if (!api?.toggleMode) return mode;
5067
+ const newMode = await api.toggleMode();
5068
+ setModeState(newMode);
5069
+ return newMode;
5070
+ }, [mode]);
5071
+ const show = useCallback6(async () => {
5072
+ const api = getChatPanelApi();
5073
+ if (!api?.show) return;
5074
+ await api.show();
5075
+ setVisible(true);
5076
+ }, []);
5077
+ const hide = useCallback6(async () => {
5078
+ const api = getChatPanelApi();
5079
+ if (!api?.hide) return;
5080
+ await api.hide();
5081
+ setVisible(false);
5082
+ }, []);
5083
+ const toggle = useCallback6(async () => {
5084
+ const api = getChatPanelApi();
5085
+ if (!api?.toggle) return;
5086
+ await api.toggle();
5087
+ setVisible((v) => !v);
5088
+ }, []);
5089
+ const setWidth = useCallback6(async (newWidth, animate) => {
5090
+ const api = getChatPanelApi();
5091
+ if (!api?.setWidth) return;
5092
+ await api.setWidth(newWidth, animate);
5093
+ setWidthState(newWidth);
5094
+ }, []);
5095
+ const onResizeEnd = useCallback6(async () => {
5096
+ const api = getChatPanelApi();
5097
+ if (!api?.onResizeEnd) return;
5098
+ await api.onResizeEnd();
5099
+ }, []);
5100
+ return {
5101
+ mode,
5102
+ visible,
5103
+ width,
5104
+ isEmbedded: mode === "embedded",
5105
+ isFloating: mode === "floating",
5106
+ setMode,
5107
+ toggleMode,
5108
+ show,
5109
+ hide,
5110
+ toggle,
5111
+ setWidth,
5112
+ onResizeEnd
5113
+ };
5114
+ }
5115
+
5116
+ // src/renderer/hooks/useAttachState.ts
5117
+ import { useState as useState8, useEffect as useEffect9, useCallback as useCallback7 } from "react";
5118
+ var getChatPanelApi2 = () => {
5119
+ return window.chatPanel;
5120
+ };
5121
+ function useAttachState() {
5122
+ const [state, setState] = useState8("unavailable");
5123
+ const [isLoading, setIsLoading] = useState8(true);
5124
+ useEffect9(() => {
5125
+ const api = getChatPanelApi2();
5126
+ if (!api) {
5127
+ setIsLoading(false);
5128
+ return;
5129
+ }
5130
+ api.getAttachState?.().then((result) => {
5131
+ if (result.success) {
5132
+ setState(result.data);
5133
+ }
5134
+ }).catch(() => {
5135
+ }).finally(() => setIsLoading(false));
5136
+ const unsubscribe = api.onAttachStateChanged?.(setState);
5137
+ return () => {
5138
+ unsubscribe?.();
5139
+ };
5140
+ }, []);
5141
+ const toggle = useCallback7(async () => {
5142
+ const api = getChatPanelApi2();
5143
+ if (!api?.toggleAttach) return state;
5144
+ const result = await api.toggleAttach();
5145
+ if (result.success) {
5146
+ setState(result.data);
5147
+ return result.data;
5148
+ }
5149
+ return state;
5150
+ }, [state]);
5151
+ return {
5152
+ state,
5153
+ isAttached: state === "attached",
5154
+ isAvailable: state !== "unavailable",
5155
+ isLoading,
5156
+ toggle
5157
+ };
5158
+ }
5159
+
4972
5160
  // src/core/history.ts
4973
5161
  function safeParseArgs(value) {
4974
5162
  if (!value) return void 0;
@@ -5728,7 +5916,7 @@ function createSdkAdapter(config) {
5728
5916
  import { SanqianSDK } from "@yushaw/sanqian-sdk/browser";
5729
5917
 
5730
5918
  // src/renderer/components/MessageList.tsx
5731
- import { memo, useRef as useRef4, useEffect as useEffect8, useCallback as useCallback6 } from "react";
5919
+ import { memo, useRef as useRef4, useEffect as useEffect10, useCallback as useCallback8 } from "react";
5732
5920
  import { jsx as jsx3 } from "react/jsx-runtime";
5733
5921
  var SCROLL_THRESHOLD = 100;
5734
5922
  var MessageList = memo(function MessageList2({
@@ -5740,26 +5928,26 @@ var MessageList = memo(function MessageList2({
5740
5928
  }) {
5741
5929
  const containerRef = useRef4(null);
5742
5930
  const isNearBottomRef = useRef4(true);
5743
- const checkIfNearBottom = useCallback6(() => {
5931
+ const checkIfNearBottom = useCallback8(() => {
5744
5932
  const container = containerRef.current;
5745
5933
  if (!container) return true;
5746
5934
  return container.scrollTop <= SCROLL_THRESHOLD;
5747
5935
  }, []);
5748
- const handleScroll = useCallback6(() => {
5936
+ const handleScroll = useCallback8(() => {
5749
5937
  isNearBottomRef.current = checkIfNearBottom();
5750
5938
  }, [checkIfNearBottom]);
5751
- const scrollToBottom = useCallback6(
5939
+ const scrollToBottom = useCallback8(
5752
5940
  (behavior = scrollBehavior) => {
5753
5941
  containerRef.current?.scrollTo({ top: 0, behavior });
5754
5942
  },
5755
5943
  [scrollBehavior]
5756
5944
  );
5757
- useEffect8(() => {
5945
+ useEffect10(() => {
5758
5946
  if (autoScroll && isNearBottomRef.current) {
5759
5947
  scrollToBottom();
5760
5948
  }
5761
5949
  }, [messages, autoScroll, scrollToBottom]);
5762
- useEffect8(() => {
5950
+ useEffect10(() => {
5763
5951
  scrollToBottom("instant");
5764
5952
  isNearBottomRef.current = true;
5765
5953
  }, [scrollToBottom]);
@@ -5796,20 +5984,20 @@ var MessageBubble = memo2(function MessageBubble2({
5796
5984
  });
5797
5985
 
5798
5986
  // src/renderer/components/SanqianChat.tsx
5799
- import { memo as memo10, useEffect as useEffect15, useMemo as useMemo8, useRef as useRef10 } from "react";
5987
+ import { memo as memo10, useEffect as useEffect17, useMemo as useMemo8, useRef as useRef10 } from "react";
5800
5988
 
5801
5989
  // src/renderer/utils/chatConfig.ts
5802
- import { useEffect as useEffect9, useMemo as useMemo3, useState as useState7 } from "react";
5990
+ import { useEffect as useEffect11, useMemo as useMemo3, useState as useState9 } from "react";
5803
5991
  var getSystemTheme = () => {
5804
5992
  if (typeof window === "undefined") return "light";
5805
5993
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
5806
5994
  };
5807
5995
  function useResolvedTheme(mode = "auto") {
5808
- const [resolvedTheme, setResolvedTheme] = useState7(() => {
5996
+ const [resolvedTheme, setResolvedTheme] = useState9(() => {
5809
5997
  if (mode === "auto") return getSystemTheme();
5810
5998
  return mode === "dark" ? "dark" : "light";
5811
5999
  });
5812
- useEffect9(() => {
6000
+ useEffect11(() => {
5813
6001
  if (mode !== "auto") {
5814
6002
  setResolvedTheme(mode === "dark" ? "dark" : "light");
5815
6003
  return;
@@ -5913,7 +6101,7 @@ function resolveOnPin(onPin) {
5913
6101
  }
5914
6102
 
5915
6103
  // src/renderer/utils/useChatHeader.tsx
5916
- import { useCallback as useCallback7, useEffect as useEffect10, useMemo as useMemo4, useRef as useRef5, useState as useState8 } from "react";
6104
+ import { useCallback as useCallback9, useEffect as useEffect12, useMemo as useMemo4, useRef as useRef5, useState as useState10 } from "react";
5917
6105
 
5918
6106
  // src/renderer/assets/sanqianLogo.ts
5919
6107
  var SANQIAN_LOGO_DATA_URI = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iTGF5ZXJfMiIgZGF0YS1uYW1lPSJMYXllciAyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MTUuODcgNDI4LjIiPgogIDxnIGlkPSJMYXllcl8xLTIiIGRhdGEtbmFtZT0iTGF5ZXIgMSI+CiAgICA8ZyBpZD0iQzhvaUxXIj4KICAgICAgPGc+CiAgICAgICAgPHBhdGggZD0iTTQwNC45LDE1OC4wM2wxLjk4LTEuMDFjLS4zMSw2LjM1LDEuMDQsMTIuNTYsMS43NCwxOC44Mi41Myw0LjcyLDEuNjIsOC41NywxLjI2LDE0LjY4LTEuMDcsMTguNDEtNy4wOCwzNS45Ni0xMS45OCw1My41bDcuOTUtMTYuNTRjMy43MS0xMi4wOCw2Ljc4LTI0LjI0LDguMDUtMzYuODdsMS45Ny0uMWMtMS43MSw0LjkxLTEuNDQsMTAuNjYtMi4yNiwxNS43NC00LjY3LDI5LjA1LTE3LjgzLDU4LjI3LTM1LjMxLDgxLjY5LTguNzYsMTEuNzMtMTkuNzgsMjEuMzUtMjguNDQsMzIuNTYtMi45OSwzLjg4LTEyLjM4LDcuOTktMTYuMjMsMTAuNTUtMi4wOCwxLjM4LTQuOTQsNS44Ny02LjQ4LDcuMDEtNiw0LjQ1LTE3LjE5LDUuNDMtMjIuMjYsMTEuNDcsMS4xLDEuMTksMy42OS0uNTQsNC45NS0xLjA1LDE1LjQ0LTYuMiwyOC45NC0xMy45Niw0Mi42MS0yMy40LDQuNjMsMS4wNi0uODQsMi4zMS0xLjg5LDMuMDgtNDEuOTYsMzAuNTUtOTAuNDYsNDYuMy0xNDEuOTQsMjcuNjQtMTkuMzEtNy0yNi4yMS0xOC45Ny00MC41NS0yNi40NS0xMy4xLTYuODMtMTUuOTktMTEuNTctMjUuMTgtMjIuNTQtMi45My0zLjUtMTAuNzEtMTEuNDctMTIuNDItMTQuODYtLjU2LTEuMTEtNi4yLTIwLjQ4LTYuMjEtMjEuNi0uMDQtNC4zNSwzLjE0LTkuOTcsMy42My0xNC44NC44LTcuOTMtMi45Ny0xOC45MSwzLTI0LjQ5LjY3LDMuMTQuNzgsNi41NSwxLjkxLDkuNjEuNTEsMS4zNy0uMzYsMS43LDIuMDksMS40LDEuOTQtNC4yNi0uMzYtOS45OS4xNy0xMy4yNSwxLjIxLTcuNDcsOC4zLTIxLjg0LDEzLjMzLTI3Ljc2LDUuMzUtNi4yOSwxNC4xMy0xNC4wOSwyMi41MS0xNC40OWwtMTAsOS40OSw2Ljk5LTEuNWMtMy4wNCw0LjgxLTcuNDUsOC43My0xMC40MSwxMy41OS01LjA2LDguMjktNS44NiwxNy44MS02LjU5LDI3LjQzbDQuMDIsMTkuNDljMi4wOC0uOTQuNTUtNS4wNSwxLjItNy4yOS4yNC0uODMsMi4yNi0zLjA5LDIuNzgtMi43LDMuMiwxNC4wNiwxMC40NSwyNC41NSwyMC40MiwzNC42MSwyNS4xLDI1LjM1LDY0LjA0LDMyLjc4LDk3LjI3LDE5LjU2LDguMDMtMy4xOSwxNS43LTguOTYsMjMuMzItMTIuMTdsLTIsMi45OGgxLjQ5YzE3LjE1LTEyLjY2LDMzLjYzLTI3LjExLDQyLjUzLTQ2Ljk5bDIsLjUxLS4wMyw1LjQ4LDguMy0xNi4yLDkuNy0yNy43OWMuNDUsNy41OS0yLjYxLDE0LjY3LTQuNDQsMjEuODYtLjkyLDMuNjItLjQ1LDUuNzgtMi4zOSwxMC44LTYuNTksMTcuMDgtMTkuMTgsMzMuMzEtMzIuMTYsNDUuODVsMy45OC0uNTFjLS4wMy40Ny4xNywxLjA1LDAsMS40OS0xLjg3LDQuNzItMjQuMzMsMjAuMTQtMjkuNzEsMjMuMy0xMC4zMSw2LjA1LTIxLjY3LDExLjEtMzMuMjcsMTQuMjMtLjE2LDEuODUsMy4yNi45OCw0LjM3Ljg2LDM2LjgtNC4wMiw3NS4yOC0yOS43NCw5NS40NS02MC41NSwxMS40MS0xNy40MywxNi42Ni0zMy4yNCwyMS44Ny01My4xMy44OC0zLjM2LDMuMzUtNi4wOSwyLjMyLTEwLjE5LDEuNjctLjI2LDEuMDcsMi40MSwxLjA0LDMuNTMtLjA5LDIuODUtLjkyLDUuMjMtMS4wOSw3LjkzLS4wNywxLjA4LS42NCwzLjc5LDEuMDMsMy41Mmw0Ljk2LTE5LjU0YzEuNTYtMTcuMzEsMy41NC0zMi4yOS43NS00OS42Ni0xLjAxLTYuMy00LjA2LTEzLjMyLTQuNzItMTkuMy0uMjQtMi4xNy40LTIuNjQsMS4yNS0uMjQuNzcsMi4xNywxLjE5LDQuNTIsMS43Nyw2Ljc1LDEuNzEuMjcsMS4wNy0yLjQuOTEtMy40LS42LTMuNTctMy4xLTEwLjk4LTQuNDQtMTQuNTctMy43OS0xMC4yMS0xMC4zMS0xOS42My0xMy40Ny0zMC4wMSwxLjU0Ljk1LDMuMTksMy43MSw0LjE5LDUuMywxMy4xMywyMC45OCwyMC42OSw0NC4zMiwyNC44Miw2OC43WiIvPgogICAgICAgIDxnPgogICAgICAgICAgPHBhdGggZD0iTTIyMC44OSw0MDYuMDJjLS4yNiwxLjMzLDEuODMsMS42LDIuNzQsMS43NSwzMi4xLDUuMjksNTguMjgsMS41MSw4OC4yNC0xMS4yNmwyOS4wMS0xNS40OGMtNC43Nyw1LjEyLTEyLjEyLDkuNjQtMTguMzMsMTMuMTYtNy4wNCwzLjk5LTE5LjI3LDcuNzItMjQuNjgsMTEuMzItLjQxLjI3LTEuMzIsMS4yNC0uOTksMS41aDUuOTljLTYuNjcsMS40Ny0xMy40OCw0LjgzLTE5Ljk3LDYuNTQtNS4xMywxLjM1LTE3LjY2LDIuMzctMjEuMDQsMy45Ni0uNDYuMjEtMS4yNiwxLjMtLjk4LDEuNTFsNC45OSwxYy0yOC4zLDUuNTktNTcuMTQtLjQ4LTg0LjQ4LTguMDEtMS42LDEuMDUuNzUsMS4xOCwxLjQ1LDEuNTMsMTMuMzMsNi42OSwyOS4yMiwxMC4wNyw0NC4wNCwxMS40OWwtMS4wMSwxLjk4LDUsLjAyYy4yNSwxLjcyLTIuMzcsMS4wNi0zLjQ4Ljk4LTMxLjc4LTIuNDEtNjcuMzktMTYuNTMtOTMuNDMtMzQuNTgtMTcuNDYtMTIuMS0zMS4xNS0yNy4wMy00NS41NC00MS40NWwtMjAuNTMtMzEuOTYtMSwzLjk5Yy0uMTItLjcxLTEuOTktOS4yNC00LjAxLTYuOTguNjksMi43NSwyLjYzLDUuNDQsMy41NCw3Ljk1LjM0Ljk0LDEuMzIsMy4yNS0uNTMsMy4wMy0xMC42OC0yMS44NS0xNy44My00NS45NS0xOS4wNS03MC40NS0uNDItOC40OSwzLjMtNDEuNCw4LjE2LTQ3LjQyLjE3LS4yMSwzLjA2LDEuMTgsMy44Ny0yLjY1bC0xLjk4LS40N2MtLjg1LTUuMDQsMy42NC02LjUyLDUuNjYtOS44MnM5LjM3LTE2LjcsMTAuMzEtMTkuNzFjLjE2LS41MS4yNy0xLjYzLS40OC0xLjQ4LTIuNzUsMi4xOC0zLjgzLDUuNTktNS42Niw4LjM0LS42OCwxLjAyLTIuMDIsMy4xMi0xLjgzLjE4LDExLjc1LTI0LjQ3LDI4LjEzLTQyLjQxLDUwLjY1LTU3LjM1LDUuOTYtMy45NSwxMi44Mi02LjUsMTguMzMtMTEuMTYtOS43My41LTIyLjE4LDQuMzItMzAuOTksOC41LTMuMywxLjU3LTguNTIsNi4wOC0xMS4wNyw2Ljk2LTEuNjQuNTctMy4wOC0uNi01LjIxLjUtMS44LjkzLTEwLjY0LDguNi0xMi43NCwxMC41MS0yNC43OSwyMi41Ni00MS4yNiw1Ny41MS00Niw5MC41MS0xLjYxLjA1LTIuMDUtMy41My0yLjA0LTQuNTMuMDUtNC4wOSwxLjMtMTAuMjksMi4wNS0xNC40NmwtMy44OS4xYy0yLjIsMTEuOTYtNS43OSwyMy41OC01LjEyLDM1Ljg4bC0yLTYuOTljLTEuNDctLjA5LTEuNzYsMy41OS0xLjg3LDQuNjEtMi40NywyMy44NSw2LjI4LDU4LjIxLDE1LjQsODAuMzYsMS4wMiwyLjQ5LDkuMTQsMTcuMjEsOC40OCwxOC4wMS0xLjU5LDEuOTItMi4xNC0xLjQ5LTIuNDctMS45OS0xMy4zNC0yMC4yMi0yMS42Mi00My4xLTI1LjU0LTY3LjAxbC0xLjk4LDEuMDFjLTIuMzYtMTUuMTEtNC45NS0yOS4wNy00LjA1LTQ0LjU0LjMyLTUuNDQsMi42Mi0xMC44NywyLjAzLTE2LjQ2bC0zLjk4LDE2LjUxYy0uOTUsMTAuMzEtLjU5LDIwLjY4LTEuMDEsMzEtLjA1LDEuMjEuNzYsMy43Mi0uOTksMy40OC0yLjAxLTE4LjI0LS41NC0zNi4zMSwzLjI4LTU0LjIsNS42OS0yNi42LDE4LjI4LTU0LjI3LDM2LjE5LTc0LjgxLDEyLjUzLTE0LjM3LDI4LjEyLTI3Ljk5LDQyLjg4LTM4LjY4LDIuMDktMS41MSw1LjA0LTMuOCw3LjMxLTUuMTMsOC4xLTQuNzIsMTcuODQtNS45OSwyNS4zMS0xMS42OC0uNTgtMS4xMS0zLjA2LS4zNi00LjA2LS4wNi00LjkzLDEuNDUtMTIuMTUsNC4wNy0xNi45Miw2LjA4LTUuOTIsMi41LTExLjU0LDUuNzEtMTcsOS4wNmwtMy4wMS0xLjU2YzcuMzEtMy4yNywxMy41My03LjI4LDIxLjAzLTEwLjQ4LDQxLjYzLTE3LjcyLDEwNS4zMi0yMCwxMzcuMzYsMTYuNTMsNy40NSw4LjQ5LDE5LjI1LDIyLjU4LDI1LjA1LDMwLjk5LDEuODgsMi43MiwyLjc5LDUuNzQsMS41NSw4Ljk0aDMuMDJjLS41OC45NC0uOTksNi41Ni0uOCw2Ljg0LjQ0LjY1LDIuOTcuNjQsMy4zOCwyLjY0LjI5LDEuNDMsMS40OSwxNC43LDEuNDMsMTUuOTUtLjAzLjYtMS44MS40Ny0yLjAxLDEuMjUtLjg0LDMuMjcuNDcsMTIuNTEtLjA3LDE2LjY4LS45NSw3LjM0LTYuMTksMTAuMTItOS44MywxNS4yNy0xLjI4LDEuODEtMS45OCw2LjU3LTQuMTUsNy44NC0xLjc3LDEuMDQtNC45NS42NC03LjE4LDEuNjEtMi4zNCwxLjAyLTMuNTEsNi42Ni03Ljc4LDQuOTNsMi45OS0xMWMtMy4zOSw0LjA2LTEzLjU2LDEwLjAzLTEwLjIxLjI4LDEuMzEtMy44MS44NC0zLjI4LDEuNTEtNi41NC44MS0zLjkyLDMuNzktMTIuOTIsMy43MS0xNi4xNi0uMDEtLjQyLTEuOTktLjk4LTIuNy0yLjM2LTQuMDItNy44Mi02LjM1LTE1LjE3LTEyLjY2LTIxLjg3LTExLjMtMTItNDIuMzMtMTguMi01Ny44OS0xNC4xLTE2Ljg4LDQuNDUtNDQuNjUsMjYuNDQtNTEuMyw0Mi43LTgsMTkuNTgtMTUuMTcsMzkuNjctMTIuMyw2MS4zOCw0LjA5LDMwLjg2LDE2LjE2LDUzLjYsMzMuNCw3OC42LDEuNTMsMi4yMiw0LjIxLDMuNTksNS40NCw2LjA1LTMuNzktMS4zNy03Ljc1LTUuOTQtMTAuNTEtOC45OC0xMC45My0xMS45OS0xOS44OS0yNi4yNS0yNi41LTQxLjAxLTMuMDMsMS40LDMuMjksNi43Mi0uOTcsNy45OWwtNy4wMy0xNy45OS0xLjk4LDEuOTljLS40Mi0yLjYtMS4wOC04LjIzLTQuMDItOC40OCw0LjMsMjguMjgsMTIuOTgsNTIuNjYsMzEuMDQsNzQuOTYsMjcuNDgsMzMuOTQsNzIuOTMsNjEuMzIsMTE3LjM1LDYyLjY1bDguNjIsMS44OGgtMjFaIi8+CiAgICAgICAgICA8cGF0aCBkPSJNMjg4LjQ4LDQxLjQzYzE3LDEzLjA0LDI2LjQ2LDI0LjkxLDM2LjU4LDQzLjkyLDE1Ljc5LDI5LjY4LDIyLjc5LDYyLjM3LDE1LjgyLDk1LjY3LTEuNjcuMjYtMS4wOS0yLjQzLTEuMDMtMy41My4yLTMuNDksMS42NC02Ljg3LDEuMDMtMTAuNDdsLTEuNTEuOThjLTIuOCwyMS43Mi0xMC41OSw0NS44NC0yMy4wNSw2My45NS01LjY4LDguMjYtOS44NSwxMC41NS0xNi45NSwxNi4wNS0yLjk1LDIuMjktNi4xOSw4LjE3LTkuNDgsNy41MiwxLjA3LTEuODMsNS44NS0zLjk1LDQuNDktNi41MWwtMTAuNDksNyw4Ljk5LTguNS0xLjQ4LS40OWMtMTguNjIsMTcuMTktNDguNjUsMjkuNDYtNzMuNTEsMTkuNDQtMS42LS42NS0yLjQ1LjEtMS45OS0yLjQ1LDEzLjc2LDYuMTcsMjcuODEsMi4wMyw0MC45Ny0zLjUyLDM2LjAyLTE1LjE5LDU3LjE2LTUzLjQ4LDU2LjkyLTkyLjA5LS4wMi0zLjE5LS41Mi0xMS43LTIuODktMTMuMzksMS44OSwxMC0uMywyMi40Ny0zLjMxLDMyLjIxLS4zMiwxLjA1LS4yNiwzLjAzLTEuNjksMi43OSw5Ljc1LTUxLjA4LTIwLjUyLTEwMC41NC02My43MS0xMjUuOC02LjQ1LTMuNzctMTQuMzUtNS42Ni0xOS41Ni0xMC40OWwtMTguNzQtNi43YzIuMDktLjA3LDQuMTgtLjE0LDYuMjYuMjMsMjAuOTcsMy43NywzOS44NCwxNC4zNiw1OC40NCwyMy41NSwxLjczLjg1LDMuNDUsMS44Myw1LjA0LDIuOSwyLjgyLDEuODgsOC42OSw5LjgxLDkuNzcsMTAuMy40My4yLDEuNjQuMjUsMS40OC0uNDktMzEuNzMtMzkuNzgtODMuNTMtNTguNjMtMTMzLjk5LTUzLjUybDcuOTktMi45OGMtMTguMjUuMjEtMzcuNDcsNC40MS01NC41MiwxMC45Ny0yLjg2LjI4LS44Ny0xLjI5LjE2LTEuODUsMS4yMS0uNjUsMTQuNzItNS4xMiwxMy4zNy02LjEyLTE2LjY3LDMuNjUtMzMuMTIsMTEuNy00Ny41MiwyMC45Ny05LjE1LDUuODktMTUuODIsMTIuMTMtMjMuOTcsMTkuMDItMS4xMi45NS0xLjYzLDIuNDItMy41LDEuOTksMy42My0zLjQyLDQuMzEtNy41Myw3LjgyLTEwLjksNS40Mi01LjIyLDE2LjA3LTEzLjEzLDIyLjQ0LTE3LjM5LDMyLjA3LTIxLjQ1LDY5LjEzLTMxLjM4LDEwNy43NC0zMC43MS0uNTMtMS41NS01LjAxLTEuNzktNi41MS0xLjk4LTMuOTEtLjQ5LTEyLjY5LjQ4LTE0LjgyLjAxLS43My0uMTYtLjYtMS45Mi0xLjMzLTIuMDYtMi45OC0uNTMtMTAuNzgsMS43LTE0LjMzLDEuMDItLjI0LTEuMzcsMS43OC0xLjUxLDIuNzUtMS43Miw2LjU5LTEuNDQsMTMuOTgtMS4xLDIwLjcyLTIuMzEsMS43Ny0uMzIsMi45OSwxLjEsMi41Mi0xLjk1bC0zOC45OSwzLjk4LDE2Ljk5LTQtNC45OS0xLjk4YzUyLjEyLTcuOTIsMTA0LjI4LDcuNzMsMTQ1LjU5LDM5LjRaIi8+CiAgICAgICAgICA8cGF0aCBkPSJNODAuODksMzQ2LjAxYy00LjUyLjUxLTMuNDQtMi45NC00LjEtMy44Ni0uMTItLjE2LTEuNDMuNTMtMS45MS4yNC0zLjE0LTEuODktMy4yMi02LjEzLTMuMDEtOS4zN2wtMS45OCwxLjk5LTIuMDItMy41MWMxLjk1LS44LDIuMjktMS4yMSwyLjAxLTMuNDhsMTAuOTksMTcuOThaIi8+CiAgICAgICAgPC9nPgogICAgICA8L2c+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4=";
@@ -5958,9 +6146,9 @@ var resolveLogoNode = (logo, size, alt = SANQIAN_LOGO_ALT) => {
5958
6146
  var useChatHeader = (config) => {
5959
6147
  const resolvedOnClose = useMemo4(() => resolveOnClose(config?.onClose), [config?.onClose]);
5960
6148
  const resolvedOnPin = useMemo4(() => resolveOnPin(config?.onPin), [config?.onPin]);
5961
- const [isPinned, setIsPinned] = useState8(config?.alwaysOnTop ?? false);
6149
+ const [isPinned, setIsPinned] = useState10(config?.alwaysOnTop ?? false);
5962
6150
  const isFirstRender = useRef5(true);
5963
- useEffect10(() => {
6151
+ useEffect12(() => {
5964
6152
  if (isFirstRender.current) {
5965
6153
  isFirstRender.current = false;
5966
6154
  return;
@@ -5973,7 +6161,7 @@ var useChatHeader = (config) => {
5973
6161
  const showPin = !!resolvedOnPin || typeof config?.alwaysOnTop === "boolean";
5974
6162
  const showClose = !!resolvedOnClose;
5975
6163
  const logoNode = useMemo4(() => resolveLogoNode(config?.logo, "header"), [config?.logo]);
5976
- const togglePin = useCallback7(() => {
6164
+ const togglePin = useCallback9(() => {
5977
6165
  setIsPinned((prev) => {
5978
6166
  const nextPinned = !prev;
5979
6167
  resolvedOnPin?.(nextPinned);
@@ -5993,9 +6181,9 @@ var useChatHeader = (config) => {
5993
6181
  // src/renderer/components/SanqianMessageList.tsx
5994
6182
  import {
5995
6183
  useRef as useRef7,
5996
- useEffect as useEffect12,
5997
- useCallback as useCallback9,
5998
- useState as useState10,
6184
+ useEffect as useEffect14,
6185
+ useCallback as useCallback11,
6186
+ useState as useState12,
5999
6187
  useMemo as useMemo7,
6000
6188
  useImperativeHandle,
6001
6189
  forwardRef
@@ -6093,7 +6281,7 @@ var MarkdownRenderer = memo3(function MarkdownRenderer2({
6093
6281
  });
6094
6282
 
6095
6283
  // src/renderer/components/IntermediateSteps.tsx
6096
- import { memo as memo5, useState as useState9, useRef as useRef6, useEffect as useEffect11, useCallback as useCallback8, useMemo as useMemo6 } from "react";
6284
+ import { memo as memo5, useState as useState11, useRef as useRef6, useEffect as useEffect13, useCallback as useCallback10, useMemo as useMemo6 } from "react";
6097
6285
 
6098
6286
  // src/renderer/renderers/ToolArgumentsDisplay.tsx
6099
6287
  import { memo as memo4 } from "react";
@@ -6222,7 +6410,7 @@ function ExpandableText({
6222
6410
  style,
6223
6411
  maxLines = 3
6224
6412
  }) {
6225
- const [isExpanded, setIsExpanded] = useState9(false);
6413
+ const [isExpanded, setIsExpanded] = useState11(false);
6226
6414
  const trimmed = content.trim();
6227
6415
  const lines = trimmed.split("\n");
6228
6416
  const needsExpand = lines.length > maxLines;
@@ -6243,7 +6431,7 @@ function ExpandableText({
6243
6431
  );
6244
6432
  }
6245
6433
  function ToolCallItem({ toolCall, toolResult }) {
6246
- const [expanded, setExpanded] = useState9(false);
6434
+ const [expanded, setExpanded] = useState11(false);
6247
6435
  const hasArgs = toolCall.toolArgs && Object.keys(toolCall.toolArgs).length > 0;
6248
6436
  const rawName = cleanToolName(toolCall.toolName);
6249
6437
  const displayName = rawName && !/^[{\[]/.test(rawName.trim()) ? rawName : toolCall.toolCallId || "tool";
@@ -6281,7 +6469,7 @@ function StreamingToolCallItem({
6281
6469
  isActive,
6282
6470
  strings
6283
6471
  }) {
6284
- const [expanded, setExpanded] = useState9(false);
6472
+ const [expanded, setExpanded] = useState11(false);
6285
6473
  const hasArgs = toolCall.toolArgs && Object.keys(toolCall.toolArgs).length > 0;
6286
6474
  const rawName = cleanToolName(toolCall.toolName);
6287
6475
  const displayName = rawName && !/^[{\[]/.test(rawName.trim()) ? rawName : toolCall.toolCallId || "tool";
@@ -6360,14 +6548,14 @@ var ThinkingSection = memo5(function ThinkingSection2({
6360
6548
  }) {
6361
6549
  const contentRef = useRef6(null);
6362
6550
  const isUserScrollingRef = useRef6(false);
6363
- const [loadingSymbolIndex, setLoadingSymbolIndex] = useState9(0);
6364
- const [manualExpanded, setManualExpanded] = useState9(false);
6551
+ const [loadingSymbolIndex, setLoadingSymbolIndex] = useState11(0);
6552
+ const [manualExpanded, setManualExpanded] = useState11(false);
6365
6553
  const effectiveIsStreaming = isComplete ? false : isStreaming;
6366
6554
  const effectiveIsPaused = isComplete ? false : isPaused;
6367
6555
  const isExpanded = effectiveIsStreaming || effectiveIsPaused || manualExpanded;
6368
6556
  const displayContent = effectiveIsStreaming || effectiveIsPaused ? currentThinking || thinking : thinking;
6369
6557
  const hasContent = displayContent && displayContent.split("\n").filter((line) => line.trim() && !line.trim().match(/^─+$/)).length > 0;
6370
- useEffect11(() => {
6558
+ useEffect13(() => {
6371
6559
  if (effectiveIsStreaming) {
6372
6560
  const interval = setInterval(() => {
6373
6561
  setLoadingSymbolIndex((prev) => (prev + 1) % LOADING_SYMBOLS.length);
@@ -6375,13 +6563,13 @@ var ThinkingSection = memo5(function ThinkingSection2({
6375
6563
  return () => clearInterval(interval);
6376
6564
  }
6377
6565
  }, [effectiveIsStreaming]);
6378
- useEffect11(() => {
6566
+ useEffect13(() => {
6379
6567
  if (effectiveIsStreaming && isExpanded && contentRef.current && !isUserScrollingRef.current) {
6380
6568
  contentRef.current.scrollTop = contentRef.current.scrollHeight;
6381
6569
  }
6382
6570
  }, [displayContent, effectiveIsStreaming, isExpanded]);
6383
6571
  const prevManualExpandedRef = useRef6(manualExpanded);
6384
- useEffect11(() => {
6572
+ useEffect13(() => {
6385
6573
  const wasCollapsed = !prevManualExpandedRef.current;
6386
6574
  const isNowExpanded = manualExpanded;
6387
6575
  if (wasCollapsed && isNowExpanded && !effectiveIsStreaming && contentRef.current) {
@@ -6389,13 +6577,13 @@ var ThinkingSection = memo5(function ThinkingSection2({
6389
6577
  }
6390
6578
  prevManualExpandedRef.current = manualExpanded;
6391
6579
  }, [manualExpanded, effectiveIsStreaming]);
6392
- const handleScroll = useCallback8(() => {
6580
+ const handleScroll = useCallback10(() => {
6393
6581
  if (!contentRef.current || !effectiveIsStreaming) return;
6394
6582
  const { scrollTop, scrollHeight, clientHeight } = contentRef.current;
6395
6583
  const isAtBottom = scrollHeight - scrollTop - clientHeight < 20;
6396
6584
  isUserScrollingRef.current = !isAtBottom;
6397
6585
  }, [effectiveIsStreaming]);
6398
- useEffect11(() => {
6586
+ useEffect13(() => {
6399
6587
  if (!effectiveIsStreaming) {
6400
6588
  isUserScrollingRef.current = false;
6401
6589
  }
@@ -6440,7 +6628,7 @@ var IntermediateSteps = memo5(function IntermediateSteps2({
6440
6628
  defaultExpanded = false,
6441
6629
  strings = {}
6442
6630
  }) {
6443
- const [isExpanded, setIsExpanded] = useState9(defaultExpanded);
6631
+ const [isExpanded, setIsExpanded] = useState11(defaultExpanded);
6444
6632
  const rounds = useMemo6(() => groupBlocksIntoRounds(blocks), [blocks]);
6445
6633
  if (rounds.length === 0) return null;
6446
6634
  const stepCount = rounds.filter((round) => round.toolCalls.length > 0).length;
@@ -6532,7 +6720,7 @@ var StreamingTimeline = memo5(function StreamingTimeline2({
6532
6720
  className = "",
6533
6721
  strings = {}
6534
6722
  }) {
6535
- const [isExpanded, setIsExpanded] = useState9(true);
6723
+ const [isExpanded, setIsExpanded] = useState11(true);
6536
6724
  const isUserScrollingRef = useRef6(false);
6537
6725
  const timelineRef = useRef6(null);
6538
6726
  const isThinkingActive = isThinkingStreaming;
@@ -6601,18 +6789,18 @@ var StreamingTimeline = memo5(function StreamingTimeline2({
6601
6789
  }, [rounds, activeThinking, isThinkingActive, isToolsActive]);
6602
6790
  const stepCount = rounds.filter((round) => round.toolCalls.length > 0).length;
6603
6791
  const summary = `${stepCount} ${strings.steps || "\u6B65"}`;
6604
- const handleScroll = useCallback8(() => {
6792
+ const handleScroll = useCallback10(() => {
6605
6793
  if (!timelineRef.current) return;
6606
6794
  const { scrollTop, scrollHeight, clientHeight } = timelineRef.current;
6607
6795
  const isAtBottom = scrollHeight - scrollTop - clientHeight < 20;
6608
6796
  isUserScrollingRef.current = !isAtBottom;
6609
6797
  }, []);
6610
- useEffect11(() => {
6798
+ useEffect13(() => {
6611
6799
  if (isExpanded && timelineRef.current && !isUserScrollingRef.current) {
6612
6800
  timelineRef.current.scrollTop = timelineRef.current.scrollHeight;
6613
6801
  }
6614
6802
  }, [displayRounds, isExpanded]);
6615
- useEffect11(() => {
6803
+ useEffect13(() => {
6616
6804
  if (!isThinkingActive && !isToolsActive) {
6617
6805
  isUserScrollingRef.current = false;
6618
6806
  }
@@ -6762,7 +6950,7 @@ var INCREASE_VIEWPORT_BY = { top: 1500, bottom: 1500 };
6762
6950
  function ResizeAwareMessage({ message, onHeightChange }) {
6763
6951
  const containerRef = useRef7(null);
6764
6952
  const prevHeightRef = useRef7(0);
6765
- useEffect12(() => {
6953
+ useEffect14(() => {
6766
6954
  const container = containerRef.current;
6767
6955
  if (!container || !onHeightChange) return;
6768
6956
  let rafId = null;
@@ -6787,13 +6975,13 @@ function ResizeAwareMessage({ message, onHeightChange }) {
6787
6975
  var SanqianMessageList = forwardRef(
6788
6976
  function SanqianMessageList2({ messages, isLoading, className = "", emptyState, onClickEmpty, onAtBottomChange }, ref) {
6789
6977
  const virtuosoRef = useRef7(null);
6790
- const [, setAtBottomState] = useState10(true);
6978
+ const [, setAtBottomState] = useState12(true);
6791
6979
  const atBottomRef = useRef7(true);
6792
6980
  const isManualScrollingRef = useRef7(false);
6793
6981
  const manualScrollTimeoutRef = useRef7(null);
6794
6982
  const isFollowOutputScrollingRef = useRef7(false);
6795
6983
  const followOutputScrollTimeoutRef = useRef7(null);
6796
- const setAtBottom = useCallback9(
6984
+ const setAtBottom = useCallback11(
6797
6985
  (value) => {
6798
6986
  if (isManualScrollingRef.current) return;
6799
6987
  if (isFollowOutputScrollingRef.current && !value) return;
@@ -6814,7 +7002,7 @@ var SanqianMessageList = forwardRef(
6814
7002
  items.push({ id: "footer-spacer", type: "footer" });
6815
7003
  return items;
6816
7004
  }, [visibleMessages]);
6817
- const scrollToBottom = useCallback9(
7005
+ const scrollToBottom = useCallback11(
6818
7006
  (behavior = "smooth", source) => {
6819
7007
  if (!virtuosoRef.current || allItems.length === 0) return;
6820
7008
  const isManualScroll = source === "scroll-button";
@@ -6847,7 +7035,7 @@ var SanqianMessageList = forwardRef(
6847
7035
  }),
6848
7036
  [scrollToBottom]
6849
7037
  );
6850
- useEffect12(() => {
7038
+ useEffect14(() => {
6851
7039
  return () => {
6852
7040
  if (manualScrollTimeoutRef.current) {
6853
7041
  clearTimeout(manualScrollTimeoutRef.current);
@@ -6857,13 +7045,13 @@ var SanqianMessageList = forwardRef(
6857
7045
  }
6858
7046
  };
6859
7047
  }, []);
6860
- const handleMessageHeightChange = useCallback9(() => {
7048
+ const handleMessageHeightChange = useCallback11(() => {
6861
7049
  if (isManualScrollingRef.current) return;
6862
7050
  if (atBottomRef.current && hasStreamingActivity) {
6863
7051
  scrollToBottom("auto", "height-change");
6864
7052
  }
6865
7053
  }, [scrollToBottom, hasStreamingActivity]);
6866
- const handleClick = useCallback9(
7054
+ const handleClick = useCallback11(
6867
7055
  (e) => {
6868
7056
  const selection = window.getSelection();
6869
7057
  if (!selection || selection.isCollapsed) {
@@ -6874,7 +7062,7 @@ var SanqianMessageList = forwardRef(
6874
7062
  },
6875
7063
  [onClickEmpty]
6876
7064
  );
6877
- const handleFollowOutput = useCallback9((isAtBottom) => {
7065
+ const handleFollowOutput = useCallback11((isAtBottom) => {
6878
7066
  if (isAtBottom) {
6879
7067
  if (followOutputScrollTimeoutRef.current) {
6880
7068
  clearTimeout(followOutputScrollTimeoutRef.current);
@@ -6888,7 +7076,7 @@ var SanqianMessageList = forwardRef(
6888
7076
  }
6889
7077
  return false;
6890
7078
  }, []);
6891
- const itemContent = useCallback9(
7079
+ const itemContent = useCallback11(
6892
7080
  (_index, item) => {
6893
7081
  if ("type" in item && item.type === "footer") {
6894
7082
  return /* @__PURE__ */ jsx10("div", { className: "h-28" });
@@ -6924,10 +7112,10 @@ var SanqianMessageList = forwardRef(
6924
7112
  // src/renderer/components/ChatInput.tsx
6925
7113
  import {
6926
7114
  memo as memo7,
6927
- useState as useState11,
7115
+ useState as useState13,
6928
7116
  useRef as useRef8,
6929
- useCallback as useCallback10,
6930
- useEffect as useEffect13,
7117
+ useCallback as useCallback12,
7118
+ useEffect as useEffect15,
6931
7119
  forwardRef as forwardRef2,
6932
7120
  useImperativeHandle as useImperativeHandle2
6933
7121
  } from "react";
@@ -6948,7 +7136,7 @@ var ChatInput = memo7(
6948
7136
  className = "",
6949
7137
  style
6950
7138
  }, ref) {
6951
- const [text, setText] = useState11("");
7139
+ const [text, setText] = useState13("");
6952
7140
  const textareaRef = useRef8(null);
6953
7141
  const canSend = text.trim().length > 0 && !disabled && !isLoading;
6954
7142
  const showStopButton = isStreaming && !!onStop;
@@ -6963,13 +7151,13 @@ var ChatInput = memo7(
6963
7151
  }),
6964
7152
  [text]
6965
7153
  );
6966
- useEffect13(() => {
7154
+ useEffect15(() => {
6967
7155
  if (autoFocus) {
6968
7156
  const timer = setTimeout(() => textareaRef.current?.focus(), 100);
6969
7157
  return () => clearTimeout(timer);
6970
7158
  }
6971
7159
  }, [autoFocus]);
6972
- const handleSubmit = useCallback10(
7160
+ const handleSubmit = useCallback12(
6973
7161
  (e) => {
6974
7162
  e?.preventDefault();
6975
7163
  if (!canSend) return;
@@ -6978,7 +7166,7 @@ var ChatInput = memo7(
6978
7166
  },
6979
7167
  [text, canSend, onSend]
6980
7168
  );
6981
- const handleKeyDown = useCallback10(
7169
+ const handleKeyDown = useCallback12(
6982
7170
  (e) => {
6983
7171
  if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
6984
7172
  e.preventDefault();
@@ -7046,7 +7234,7 @@ var ChatInput = memo7(
7046
7234
  );
7047
7235
 
7048
7236
  // src/renderer/components/HitlCard.tsx
7049
- import { memo as memo8, useState as useState12, useEffect as useEffect14, useRef as useRef9 } from "react";
7237
+ import { memo as memo8, useState as useState14, useEffect as useEffect16, useRef as useRef9 } from "react";
7050
7238
  import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
7051
7239
  var defaultStrings = {
7052
7240
  approve: "Approve",
@@ -7097,16 +7285,16 @@ var HitlCard = memo8(function HitlCard2({
7097
7285
  const t = { ...defaultStrings, ...strings };
7098
7286
  const isApproval = interrupt.type === "approval_request";
7099
7287
  const isUserInput = interrupt.type === "user_input_request";
7100
- const [answer, setAnswer] = useState12(interrupt.default || "");
7101
- const [selectedIndices, setSelectedIndices] = useState12([]);
7102
- const [isComposing, setIsComposing] = useState12(false);
7103
- const [timeLeft, setTimeLeft] = useState12(interrupt.timeout ?? null);
7104
- const [rememberChoice, setRememberChoice] = useState12(false);
7288
+ const [answer, setAnswer] = useState14(interrupt.default || "");
7289
+ const [selectedIndices, setSelectedIndices] = useState14([]);
7290
+ const [isComposing, setIsComposing] = useState14(false);
7291
+ const [timeLeft, setTimeLeft] = useState14(interrupt.timeout ?? null);
7292
+ const [rememberChoice, setRememberChoice] = useState14(false);
7105
7293
  const inputRef = useRef9(null);
7106
7294
  const textareaRef = useRef9(null);
7107
7295
  const riskLevel = interrupt.risk_level || "medium";
7108
7296
  const riskStyle = riskColors[riskLevel];
7109
- useEffect14(() => {
7297
+ useEffect16(() => {
7110
7298
  if (isUserInput) {
7111
7299
  if (!interrupt.options || interrupt.options.length === 0) {
7112
7300
  inputRef.current?.focus();
@@ -7114,7 +7302,7 @@ var HitlCard = memo8(function HitlCard2({
7114
7302
  }
7115
7303
  }
7116
7304
  }, [isUserInput, interrupt.options]);
7117
- useEffect14(() => {
7305
+ useEffect16(() => {
7118
7306
  if (timeLeft === null || timeLeft <= 0) return;
7119
7307
  const timer = setInterval(() => {
7120
7308
  setTimeLeft((prev) => {
@@ -7312,7 +7500,7 @@ var HitlCard = memo8(function HitlCard2({
7312
7500
  });
7313
7501
 
7314
7502
  // src/renderer/primitives/AlertBanner.tsx
7315
- import { memo as memo9, useState as useState13 } from "react";
7503
+ import { memo as memo9, useState as useState15 } from "react";
7316
7504
  import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
7317
7505
  var AlertBanner = memo9(function AlertBanner2({
7318
7506
  type,
@@ -7324,7 +7512,7 @@ var AlertBanner = memo9(function AlertBanner2({
7324
7512
  maxLines = 3,
7325
7513
  strings
7326
7514
  }) {
7327
- const [isExpanded, setIsExpanded] = useState13(false);
7515
+ const [isExpanded, setIsExpanded] = useState15(false);
7328
7516
  const defaultIcon = type === "error" ? (
7329
7517
  // Error icon (circle with X)
7330
7518
  /* @__PURE__ */ jsxs8("svg", { className: "size-4 shrink-0", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
@@ -7449,7 +7637,7 @@ var SanqianChat = memo10(function SanqianChat2({
7449
7637
  chat.submitHitlInput({ cancelled: true });
7450
7638
  }
7451
7639
  };
7452
- useEffect15(() => {
7640
+ useEffect17(() => {
7453
7641
  onStateChangeRef.current?.({
7454
7642
  messages: chat.messages,
7455
7643
  conversationId: chat.conversationId
@@ -7568,10 +7756,187 @@ var SanqianChat = memo10(function SanqianChat2({
7568
7756
  });
7569
7757
 
7570
7758
  // src/renderer/components/FloatingChat.tsx
7571
- import { memo as memo11, useCallback as useCallback12, useMemo as useMemo9, useRef as useRef11 } from "react";
7759
+ import { memo as memo11, useCallback as useCallback15, useMemo as useMemo11, useRef as useRef12 } from "react";
7760
+
7761
+ // src/renderer/components/ModeToggleButton.tsx
7762
+ import { useMemo as useMemo9 } from "react";
7763
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
7764
+ function ModeToggleButton({ className, locale = "en" }) {
7765
+ const { isEmbedded, toggleMode } = useChatPanel();
7766
+ const strings = useMemo9(() => resolveChatStrings(locale), [locale]);
7767
+ const handleClick = async () => {
7768
+ await toggleMode();
7769
+ };
7770
+ const tooltipText = isEmbedded ? strings.floatWindow : strings.embedWindow;
7771
+ return /* @__PURE__ */ jsxs10("div", { className: `chat-tooltip-wrapper ${className || ""}`, children: [
7772
+ /* @__PURE__ */ jsx15(
7773
+ "button",
7774
+ {
7775
+ onClick: handleClick,
7776
+ className: headerIconButtonClass,
7777
+ "aria-label": tooltipText,
7778
+ children: isEmbedded ? (
7779
+ // Float out icon - two overlapping panels (macOS style)
7780
+ /* @__PURE__ */ jsxs10("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
7781
+ /* @__PURE__ */ jsx15("rect", { x: "8", y: "3", width: "13", height: "13", rx: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
7782
+ /* @__PURE__ */ jsx15("path", { d: "M5 8H4a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-1", strokeLinecap: "round", strokeLinejoin: "round" })
7783
+ ] })
7784
+ ) : (
7785
+ // Embed icon - panel with sidebar (dock to sidebar)
7786
+ /* @__PURE__ */ jsxs10("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
7787
+ /* @__PURE__ */ jsx15("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
7788
+ /* @__PURE__ */ jsx15("path", { d: "M15 4v16", strokeLinecap: "round" })
7789
+ ] })
7790
+ )
7791
+ }
7792
+ ),
7793
+ /* @__PURE__ */ jsx15("div", { className: "chat-tooltip", children: tooltipText })
7794
+ ] });
7795
+ }
7796
+
7797
+ // src/renderer/components/AttachButton.tsx
7798
+ import { useMemo as useMemo10 } from "react";
7799
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
7800
+ function AttachButton({ className, locale = "en" }) {
7801
+ const { isAttached, isAvailable, toggle } = useAttachState();
7802
+ const { isFloating } = useChatPanel();
7803
+ const strings = useMemo10(() => resolveChatStrings(locale), [locale]);
7804
+ if (!isFloating || !isAvailable) return null;
7805
+ const handleClick = async () => {
7806
+ await toggle();
7807
+ };
7808
+ const tooltipText = isAttached ? strings.detachWindow : strings.attachWindow;
7809
+ return /* @__PURE__ */ jsxs11("div", { className: `chat-tooltip-wrapper ${className || ""}`, children: [
7810
+ /* @__PURE__ */ jsx16(
7811
+ "button",
7812
+ {
7813
+ onClick: handleClick,
7814
+ className: headerIconButtonClass,
7815
+ "aria-label": tooltipText,
7816
+ children: isAttached ? (
7817
+ // Attached state: filled icon
7818
+ /* @__PURE__ */ jsxs11("svg", { className: headerIconClass, viewBox: "0 0 16 16", fill: "currentColor", children: [
7819
+ /* @__PURE__ */ jsx16("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" }),
7820
+ /* @__PURE__ */ jsx16("path", { d: "M9.5 6.5h3v1h-3v-1z", fill: "var(--bg-color, #fff)" })
7821
+ ] })
7822
+ ) : (
7823
+ // Detached state: outline icon
7824
+ /* @__PURE__ */ jsxs11("svg", { className: headerIconClass, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
7825
+ /* @__PURE__ */ jsx16("rect", { x: "2.5", y: "2.5", width: "11", height: "11", rx: "2" }),
7826
+ /* @__PURE__ */ jsx16("path", { d: "M9.5 6.5h3", strokeLinecap: "round" })
7827
+ ] })
7828
+ )
7829
+ }
7830
+ ),
7831
+ /* @__PURE__ */ jsx16("div", { className: "chat-tooltip", children: tooltipText })
7832
+ ] });
7833
+ }
7834
+
7835
+ // src/renderer/components/Resizer.tsx
7836
+ import { useCallback as useCallback14, useRef as useRef11, useEffect as useEffect18, useState as useState16 } from "react";
7837
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
7838
+ var DEFAULT_WIDTH = 360;
7839
+ function Resizer({
7840
+ position = "left",
7841
+ minWidth = 240,
7842
+ maxWidth = 600,
7843
+ defaultWidth = DEFAULT_WIDTH,
7844
+ className = ""
7845
+ }) {
7846
+ const { isEmbedded, width, setWidth, onResizeEnd } = useChatPanel();
7847
+ const [isHovered, setIsHovered] = useState16(false);
7848
+ const [isDragging, setIsDragging] = useState16(false);
7849
+ const startX = useRef11(0);
7850
+ const startWidth = useRef11(0);
7851
+ const handleDoubleClick = useCallback14(() => {
7852
+ setWidth(defaultWidth, true);
7853
+ }, [defaultWidth, setWidth]);
7854
+ const handleMouseDown = useCallback14((e) => {
7855
+ e.preventDefault();
7856
+ setIsDragging(true);
7857
+ startX.current = e.clientX;
7858
+ startWidth.current = width;
7859
+ document.body.style.cursor = "col-resize";
7860
+ document.body.style.userSelect = "none";
7861
+ }, [width]);
7862
+ useEffect18(() => {
7863
+ if (!isDragging) return;
7864
+ const handleMouseMove = (e) => {
7865
+ const deltaX = e.clientX - startX.current;
7866
+ const newWidth = position === "left" ? startWidth.current - deltaX : startWidth.current + deltaX;
7867
+ const clampedWidth = Math.min(maxWidth, Math.max(minWidth, newWidth));
7868
+ setWidth(clampedWidth);
7869
+ };
7870
+ const handleMouseUp = () => {
7871
+ setIsDragging(false);
7872
+ document.body.style.cursor = "";
7873
+ document.body.style.userSelect = "";
7874
+ onResizeEnd();
7875
+ };
7876
+ document.addEventListener("mousemove", handleMouseMove);
7877
+ document.addEventListener("mouseup", handleMouseUp);
7878
+ return () => {
7879
+ document.removeEventListener("mousemove", handleMouseMove);
7880
+ document.removeEventListener("mouseup", handleMouseUp);
7881
+ };
7882
+ }, [isDragging, position, minWidth, maxWidth, setWidth, onResizeEnd]);
7883
+ if (!isEmbedded) return null;
7884
+ const isActive = isHovered || isDragging;
7885
+ return /* @__PURE__ */ jsxs12(
7886
+ "div",
7887
+ {
7888
+ className: `chat-resizer ${className}`,
7889
+ onMouseDown: handleMouseDown,
7890
+ onDoubleClick: handleDoubleClick,
7891
+ onMouseEnter: () => setIsHovered(true),
7892
+ onMouseLeave: () => setIsHovered(false),
7893
+ style: {
7894
+ position: "absolute",
7895
+ top: 0,
7896
+ bottom: 0,
7897
+ [position]: 0,
7898
+ width: 6,
7899
+ cursor: "col-resize",
7900
+ zIndex: 100,
7901
+ // Ensure it's above other content and not affected by drag region
7902
+ WebkitAppRegion: "no-drag"
7903
+ },
7904
+ children: [
7905
+ /* @__PURE__ */ jsx17(
7906
+ "div",
7907
+ {
7908
+ style: {
7909
+ position: "absolute",
7910
+ top: 0,
7911
+ bottom: 0,
7912
+ left: position === "left" ? 0 : "auto",
7913
+ right: position === "right" ? 0 : "auto",
7914
+ width: 2,
7915
+ backgroundColor: isActive ? "var(--chat-accent, #2563EB)" : "transparent",
7916
+ transition: "background-color 0.15s ease-out, opacity 0.15s ease-out",
7917
+ opacity: isDragging ? 1 : isHovered ? 0.7 : 0
7918
+ }
7919
+ }
7920
+ ),
7921
+ /* @__PURE__ */ jsx17(
7922
+ "div",
7923
+ {
7924
+ style: {
7925
+ position: "absolute",
7926
+ top: 0,
7927
+ bottom: 0,
7928
+ left: -2,
7929
+ right: -2
7930
+ }
7931
+ }
7932
+ )
7933
+ ]
7934
+ }
7935
+ );
7936
+ }
7572
7937
 
7573
7938
  // src/renderer/hooks/useWindowBackgroundSync.ts
7574
- import { useEffect as useEffect16 } from "react";
7939
+ import { useEffect as useEffect19 } from "react";
7575
7940
  var cachedPlatform = null;
7576
7941
  var getPlatform = () => {
7577
7942
  if (cachedPlatform !== null) return cachedPlatform;
@@ -7589,7 +7954,7 @@ var setBackgroundColor = (color) => {
7589
7954
  }
7590
7955
  };
7591
7956
  function useWindowBackgroundSync(isDarkMode) {
7592
- useEffect16(() => {
7957
+ useEffect19(() => {
7593
7958
  if (getPlatform() !== "win32") return;
7594
7959
  const colors = getBaseColors(isDarkMode);
7595
7960
  setBackgroundColor(colors.bg);
@@ -7597,7 +7962,7 @@ function useWindowBackgroundSync(isDarkMode) {
7597
7962
  }
7598
7963
 
7599
7964
  // src/renderer/components/FloatingChat.tsx
7600
- import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
7965
+ import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
7601
7966
  var FloatingChat = memo11(function FloatingChat2({
7602
7967
  messages,
7603
7968
  isLoading,
@@ -7619,8 +7984,8 @@ var FloatingChat = memo11(function FloatingChat2({
7619
7984
  header,
7620
7985
  footer
7621
7986
  }) {
7622
- const chatContainerRef = useRef11(null);
7623
- const chatInputRef = useRef11(null);
7987
+ const chatContainerRef = useRef12(null);
7988
+ const chatInputRef = useRef12(null);
7624
7989
  useChatStyles();
7625
7990
  useFocusPersistence({
7626
7991
  containerRef: chatContainerRef,
@@ -7632,18 +7997,18 @@ var FloatingChat = memo11(function FloatingChat2({
7632
7997
  const { themeClass, isDarkMode } = useResolvedTheme(themeMode);
7633
7998
  const accentStyle = useAccentStyle(resolvedConfig?.accentColor);
7634
7999
  useWindowBackgroundSync(isDarkMode);
7635
- const rootStyle = useMemo9(() => ({
8000
+ const rootStyle = useMemo11(() => ({
7636
8001
  ...accentStyle || {},
7637
8002
  minHeight: "100vh",
7638
8003
  minWidth: "100vw"
7639
8004
  }), [accentStyle]);
7640
8005
  const resolvedLogo = logo ?? resolvedConfig?.logo;
7641
8006
  const resolvedLocale = resolvedConfig?.locale ?? locale;
7642
- const resolvedStrings = useMemo9(
8007
+ const resolvedStrings = useMemo11(
7643
8008
  () => resolveChatStrings(resolvedLocale, resolvedConfig?.strings),
7644
8009
  [resolvedLocale, resolvedConfig?.strings]
7645
8010
  );
7646
- const headerConfig = useMemo9(
8011
+ const headerConfig = useMemo11(
7647
8012
  () => {
7648
8013
  if (!resolvedConfig) {
7649
8014
  return resolvedLogo ? { logo: resolvedLogo } : void 0;
@@ -7656,71 +8021,77 @@ var FloatingChat = memo11(function FloatingChat2({
7656
8021
  [resolvedConfig, resolvedLogo]
7657
8022
  );
7658
8023
  const { logoNode, showPin, showClose, isPinned, togglePin, resolvedOnClose } = useChatHeader(headerConfig);
7659
- const emptyLogoNode = useMemo9(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
8024
+ const emptyLogoNode = useMemo11(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
7660
8025
  const inputPlaceholder = placeholder ?? resolvedStrings.inputPlaceholder;
7661
8026
  const showHeader = !!(header || logoNode || showPin || showClose);
7662
- const defaultHeader = /* @__PURE__ */ jsxs10("header", { className: "flex h-9 flex-shrink-0 items-center px-2 border-b chat-divider-border", children: [
7663
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
8027
+ const defaultHeader = /* @__PURE__ */ jsxs13("header", { className: "flex h-9 flex-shrink-0 items-center px-2 border-b chat-divider-border", children: [
8028
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2", children: [
7664
8029
  logoNode,
7665
- /* @__PURE__ */ jsx15("span", { className: "text-sm font-medium text-[var(--chat-text)]", children: resolvedStrings.chat })
8030
+ /* @__PURE__ */ jsx18("span", { className: "text-sm font-medium text-[var(--chat-text)]", children: resolvedStrings.chat })
7666
8031
  ] }),
7667
- /* @__PURE__ */ jsx15("div", { className: "flex-1" }),
7668
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1", children: [
7669
- showPin && /* @__PURE__ */ jsx15(
7670
- "button",
7671
- {
7672
- onClick: togglePin,
7673
- className: headerIconButtonClass,
7674
- title: isPinned ? resolvedStrings.unpin : resolvedStrings.pin,
7675
- children: /* @__PURE__ */ jsx15("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: isPinned ? /* @__PURE__ */ jsxs10(Fragment3, { children: [
7676
- /* @__PURE__ */ jsx15("path", { d: "M12 17v5" }),
7677
- /* @__PURE__ */ jsx15("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" })
7678
- ] }) : /* @__PURE__ */ jsxs10(Fragment3, { children: [
7679
- /* @__PURE__ */ jsx15("path", { d: "M12 17v5" }),
7680
- /* @__PURE__ */ jsx15("path", { d: "M15 9.34V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H7.89" }),
7681
- /* @__PURE__ */ jsx15("path", { d: "m2 2 20 20" }),
7682
- /* @__PURE__ */ jsx15("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" })
7683
- ] }) })
7684
- }
7685
- ),
7686
- showClose && /* @__PURE__ */ jsx15(
7687
- "button",
7688
- {
7689
- onClick: resolvedOnClose,
7690
- className: headerIconButtonClass,
7691
- title: resolvedStrings.close,
7692
- children: /* @__PURE__ */ jsx15("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ jsx15("path", { d: "M6 6l12 12M18 6l-12 12", strokeLinecap: "round", strokeLinejoin: "round" }) })
7693
- }
7694
- )
8032
+ /* @__PURE__ */ jsx18("div", { className: "flex-1" }),
8033
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1", children: [
8034
+ /* @__PURE__ */ jsx18(ModeToggleButton, { locale: resolvedLocale }),
8035
+ /* @__PURE__ */ jsx18(AttachButton, { locale: resolvedLocale }),
8036
+ showPin && /* @__PURE__ */ jsxs13("div", { className: "chat-tooltip-wrapper", children: [
8037
+ /* @__PURE__ */ jsx18(
8038
+ "button",
8039
+ {
8040
+ onClick: togglePin,
8041
+ className: headerIconButtonClass,
8042
+ children: /* @__PURE__ */ jsx18("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: isPinned ? /* @__PURE__ */ jsxs13(Fragment3, { children: [
8043
+ /* @__PURE__ */ jsx18("path", { d: "M12 17v5" }),
8044
+ /* @__PURE__ */ jsx18("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" })
8045
+ ] }) : /* @__PURE__ */ jsxs13(Fragment3, { children: [
8046
+ /* @__PURE__ */ jsx18("path", { d: "M12 17v5" }),
8047
+ /* @__PURE__ */ jsx18("path", { d: "M15 9.34V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H7.89" }),
8048
+ /* @__PURE__ */ jsx18("path", { d: "m2 2 20 20" }),
8049
+ /* @__PURE__ */ jsx18("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" })
8050
+ ] }) })
8051
+ }
8052
+ ),
8053
+ /* @__PURE__ */ jsx18("div", { className: "chat-tooltip", children: isPinned ? resolvedStrings.unpin : resolvedStrings.pin })
8054
+ ] }),
8055
+ showClose && /* @__PURE__ */ jsxs13("div", { className: "chat-tooltip-wrapper", children: [
8056
+ /* @__PURE__ */ jsx18(
8057
+ "button",
8058
+ {
8059
+ onClick: resolvedOnClose,
8060
+ className: headerIconButtonClass,
8061
+ children: /* @__PURE__ */ jsx18("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ jsx18("path", { d: "M6 6l12 12M18 6l-12 12", strokeLinecap: "round", strokeLinejoin: "round" }) })
8062
+ }
8063
+ ),
8064
+ /* @__PURE__ */ jsx18("div", { className: "chat-tooltip", children: resolvedStrings.close })
8065
+ ] })
7695
8066
  ] })
7696
8067
  ] });
7697
8068
  const resolvedHeader = header ?? (showHeader ? defaultHeader : null);
7698
- const defaultRenderMessage = useCallback12(
8069
+ const defaultRenderMessage = useCallback15(
7699
8070
  (message) => {
7700
8071
  if (message.role === "tool") return null;
7701
8072
  const isUser = message.role === "user";
7702
- return /* @__PURE__ */ jsx15("div", { className: `flex ${isUser ? "justify-end" : "justify-start"} mb-4`, children: /* @__PURE__ */ jsx15("div", { className: `text-left ${isUser ? "max-w-[80%]" : "w-full"}`, children: /* @__PURE__ */ jsx15("div", { className: `relative group ${isUser ? "inline-block max-w-full" : "block w-full"}`, children: /* @__PURE__ */ jsx15(
8073
+ return /* @__PURE__ */ jsx18("div", { className: `flex ${isUser ? "justify-end" : "justify-start"} mb-4`, children: /* @__PURE__ */ jsx18("div", { className: `text-left ${isUser ? "max-w-[80%]" : "w-full"}`, children: /* @__PURE__ */ jsx18("div", { className: `relative group ${isUser ? "inline-block max-w-full" : "block w-full"}`, children: /* @__PURE__ */ jsx18(
7703
8074
  "div",
7704
8075
  {
7705
8076
  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"}`,
7706
- children: isUser ? /* @__PURE__ */ jsx15("span", { className: "whitespace-pre-wrap", children: message.content }) : message.content && (renderContent ? /* @__PURE__ */ jsx15("div", { className: "prose prose-chat dark:prose-invert max-w-none px-3", children: renderContent(message.content, message.isStreaming ?? false) }) : /* @__PURE__ */ jsx15(MarkdownRenderer, { content: message.content, isStreaming: message.isStreaming, className: "px-3" }))
8077
+ children: isUser ? /* @__PURE__ */ jsx18("span", { className: "whitespace-pre-wrap", children: message.content }) : message.content && (renderContent ? /* @__PURE__ */ jsx18("div", { className: "prose prose-chat dark:prose-invert max-w-none px-3", children: renderContent(message.content, message.isStreaming ?? false) }) : /* @__PURE__ */ jsx18(MarkdownRenderer, { content: message.content, isStreaming: message.isStreaming, className: "px-3" }))
7707
8078
  }
7708
8079
  ) }) }) });
7709
8080
  },
7710
8081
  [renderContent]
7711
8082
  );
7712
- const defaultRenderHitl = useCallback12(
7713
- (interrupt, onApprove, onReject) => /* @__PURE__ */ jsxs10("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: [
7714
- /* @__PURE__ */ jsx15("p", { className: "font-medium mb-2", children: interrupt.type === "approval_request" ? resolvedStrings.hitlApprovalRequired : resolvedStrings.hitlInputRequired }),
7715
- interrupt.tool && /* @__PURE__ */ jsxs10("p", { className: "text-sm mb-2", children: [
8083
+ const defaultRenderHitl = useCallback15(
8084
+ (interrupt, onApprove, onReject) => /* @__PURE__ */ jsxs13("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: [
8085
+ /* @__PURE__ */ jsx18("p", { className: "font-medium mb-2", children: interrupt.type === "approval_request" ? resolvedStrings.hitlApprovalRequired : resolvedStrings.hitlInputRequired }),
8086
+ interrupt.tool && /* @__PURE__ */ jsxs13("p", { className: "text-sm mb-2", children: [
7716
8087
  resolvedStrings.hitlToolLabel,
7717
8088
  ": ",
7718
8089
  interrupt.tool
7719
8090
  ] }),
7720
- interrupt.reason && /* @__PURE__ */ jsx15("p", { className: "text-sm mb-2", children: interrupt.reason }),
7721
- interrupt.question && /* @__PURE__ */ jsx15("p", { className: "text-sm mb-2", children: interrupt.question }),
7722
- /* @__PURE__ */ jsxs10("div", { className: "flex gap-2 mt-3", children: [
7723
- /* @__PURE__ */ jsx15(
8091
+ interrupt.reason && /* @__PURE__ */ jsx18("p", { className: "text-sm mb-2", children: interrupt.reason }),
8092
+ interrupt.question && /* @__PURE__ */ jsx18("p", { className: "text-sm mb-2", children: interrupt.question }),
8093
+ /* @__PURE__ */ jsxs13("div", { className: "flex gap-2 mt-3", children: [
8094
+ /* @__PURE__ */ jsx18(
7724
8095
  "button",
7725
8096
  {
7726
8097
  onClick: onApprove,
@@ -7728,7 +8099,7 @@ var FloatingChat = memo11(function FloatingChat2({
7728
8099
  children: resolvedStrings.hitlApprove
7729
8100
  }
7730
8101
  ),
7731
- /* @__PURE__ */ jsx15(
8102
+ /* @__PURE__ */ jsx18(
7732
8103
  "button",
7733
8104
  {
7734
8105
  onClick: onReject,
@@ -7740,9 +8111,10 @@ var FloatingChat = memo11(function FloatingChat2({
7740
8111
  ] }),
7741
8112
  [resolvedStrings]
7742
8113
  );
7743
- return /* @__PURE__ */ jsxs10("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: [
7744
- resolvedHeader && /* @__PURE__ */ jsx15("div", { className: "flex-shrink-0", children: resolvedHeader }),
7745
- messages.length === 0 ? /* @__PURE__ */ jsx15("div", { className: "flex flex-1 items-center justify-center p-4", children: /* @__PURE__ */ jsx15("div", { className: "flex items-center justify-center", children: emptyLogoNode }) }) : /* @__PURE__ */ jsx15(
8114
+ return /* @__PURE__ */ jsxs13("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: [
8115
+ /* @__PURE__ */ jsx18(Resizer, { position: "left", minWidth: 240, maxWidth: 600 }),
8116
+ resolvedHeader && /* @__PURE__ */ jsx18("div", { className: "flex-shrink-0", children: resolvedHeader }),
8117
+ messages.length === 0 ? /* @__PURE__ */ jsx18("div", { className: "flex flex-1 items-center justify-center p-4", children: /* @__PURE__ */ jsx18("div", { className: "flex items-center justify-center", children: emptyLogoNode }) }) : /* @__PURE__ */ jsx18(
7746
8118
  MessageList,
7747
8119
  {
7748
8120
  messages,
@@ -7750,12 +8122,12 @@ var FloatingChat = memo11(function FloatingChat2({
7750
8122
  renderMessage: renderMessage || defaultRenderMessage
7751
8123
  }
7752
8124
  ),
7753
- pendingInterrupt && /* @__PURE__ */ jsx15("div", { className: "flex-shrink-0", children: (renderHitl || defaultRenderHitl)(
8125
+ pendingInterrupt && /* @__PURE__ */ jsx18("div", { className: "flex-shrink-0", children: (renderHitl || defaultRenderHitl)(
7754
8126
  pendingInterrupt,
7755
8127
  () => onApproveHitl?.(),
7756
8128
  () => onRejectHitl?.()
7757
8129
  ) }),
7758
- error && /* @__PURE__ */ jsx15("div", { className: "flex-shrink-0 px-3 pt-2", children: /* @__PURE__ */ jsx15(
8130
+ error && /* @__PURE__ */ jsx18("div", { className: "flex-shrink-0 px-3 pt-2", children: /* @__PURE__ */ jsx18(
7759
8131
  AlertBanner,
7760
8132
  {
7761
8133
  type: "error",
@@ -7763,7 +8135,7 @@ var FloatingChat = memo11(function FloatingChat2({
7763
8135
  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"}`
7764
8136
  }
7765
8137
  ) }),
7766
- /* @__PURE__ */ jsx15("div", { className: "flex-shrink-0 px-3 pb-3 pt-1 border-t chat-divider-border", children: /* @__PURE__ */ jsx15(
8138
+ /* @__PURE__ */ jsx18("div", { className: "flex-shrink-0 px-3 pb-3 pt-1 border-t chat-divider-border", children: /* @__PURE__ */ jsx18(
7767
8139
  ChatInput,
7768
8140
  {
7769
8141
  ref: chatInputRef,
@@ -7778,16 +8150,16 @@ var FloatingChat = memo11(function FloatingChat2({
7778
8150
  autoFocus: true
7779
8151
  }
7780
8152
  ) }),
7781
- footer && /* @__PURE__ */ jsx15("div", { className: "flex-shrink-0", children: footer })
8153
+ footer && /* @__PURE__ */ jsx18("div", { className: "flex-shrink-0", children: footer })
7782
8154
  ] });
7783
8155
  });
7784
8156
 
7785
8157
  // src/renderer/components/HistoryList.tsx
7786
- import { memo as memo12, useState as useState14, useEffect as useEffect17, useRef as useRef12 } from "react";
7787
- import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
8158
+ import { memo as memo12, useState as useState17, useEffect as useEffect20, useRef as useRef13 } from "react";
8159
+ import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
7788
8160
  function DeleteButton({ onClick, title, colors }) {
7789
- const [isHovered, setIsHovered] = useState14(false);
7790
- return /* @__PURE__ */ jsx16(
8161
+ const [isHovered, setIsHovered] = useState17(false);
8162
+ return /* @__PURE__ */ jsx19(
7791
8163
  "button",
7792
8164
  {
7793
8165
  onClick,
@@ -7808,7 +8180,7 @@ function DeleteButton({ onClick, title, colors }) {
7808
8180
  alignItems: "center",
7809
8181
  justifyContent: "center"
7810
8182
  },
7811
- children: /* @__PURE__ */ jsx16(
8183
+ children: /* @__PURE__ */ jsx19(
7812
8184
  "svg",
7813
8185
  {
7814
8186
  style: { width: "0.875rem", height: "0.875rem" },
@@ -7816,7 +8188,7 @@ function DeleteButton({ onClick, title, colors }) {
7816
8188
  fill: "none",
7817
8189
  stroke: "currentColor",
7818
8190
  strokeWidth: "1.5",
7819
- children: /* @__PURE__ */ jsx16(
8191
+ children: /* @__PURE__ */ jsx19(
7820
8192
  "path",
7821
8193
  {
7822
8194
  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",
@@ -7830,8 +8202,8 @@ function DeleteButton({ onClick, title, colors }) {
7830
8202
  );
7831
8203
  }
7832
8204
  function LoadMoreButton({ onClick, colors, children }) {
7833
- const [isHovered, setIsHovered] = useState14(false);
7834
- return /* @__PURE__ */ jsx16(
8205
+ const [isHovered, setIsHovered] = useState17(false);
8206
+ return /* @__PURE__ */ jsx19(
7835
8207
  "button",
7836
8208
  {
7837
8209
  onClick,
@@ -7892,11 +8264,11 @@ var HistoryList = memo12(function HistoryList2({
7892
8264
  isDarkMode = false,
7893
8265
  strings = {}
7894
8266
  }) {
7895
- const [hoveredId, setHoveredId] = useState14(null);
7896
- const loadMoreRef = useRef12(null);
7897
- const isLoadingRef = useRef12(isLoading);
8267
+ const [hoveredId, setHoveredId] = useState17(null);
8268
+ const loadMoreRef = useRef13(null);
8269
+ const isLoadingRef = useRef13(isLoading);
7898
8270
  isLoadingRef.current = isLoading;
7899
- useEffect17(() => {
8271
+ useEffect20(() => {
7900
8272
  if (!hasMore || loadError || !onLoadMore) return;
7901
8273
  const sentinel = loadMoreRef.current;
7902
8274
  if (!sentinel) return;
@@ -7920,7 +8292,7 @@ var HistoryList = memo12(function HistoryList2({
7920
8292
  deleteText: "#ef4444",
7921
8293
  loadingDot: isDarkMode ? "rgba(255, 255, 255, 0.3)" : "rgba(0, 0, 0, 0.2)"
7922
8294
  };
7923
- const loadingDots = /* @__PURE__ */ jsx16("div", { style: { display: "flex", justifyContent: "center", padding: "1.5rem 0" }, children: /* @__PURE__ */ jsx16("div", { style: { display: "flex", gap: "0.25rem" }, children: [0, 150, 300].map((delay) => /* @__PURE__ */ jsx16(
8295
+ const loadingDots = /* @__PURE__ */ jsx19("div", { style: { display: "flex", justifyContent: "center", padding: "1.5rem 0" }, children: /* @__PURE__ */ jsx19("div", { style: { display: "flex", gap: "0.25rem" }, children: [0, 150, 300].map((delay) => /* @__PURE__ */ jsx19(
7924
8296
  "span",
7925
8297
  {
7926
8298
  style: {
@@ -7938,13 +8310,13 @@ var HistoryList = memo12(function HistoryList2({
7938
8310
  return loadingDots;
7939
8311
  }
7940
8312
  if (conversations.length === 0) {
7941
- return /* @__PURE__ */ jsx16("div", { style: { textAlign: "center", color: colors.muted, padding: "1.5rem 0", fontSize: "0.875rem" }, children: strings.noHistory || "No conversations yet" });
8313
+ return /* @__PURE__ */ jsx19("div", { style: { textAlign: "center", color: colors.muted, padding: "1.5rem 0", fontSize: "0.875rem" }, children: strings.noHistory || "No conversations yet" });
7942
8314
  }
7943
- return /* @__PURE__ */ jsxs11("div", { style: { padding: "0.25rem 0.75rem 0" }, children: [
8315
+ return /* @__PURE__ */ jsxs14("div", { style: { padding: "0.25rem 0.75rem 0" }, children: [
7944
8316
  conversations.map((conv) => {
7945
8317
  const isSelected = conv.id === selectedId;
7946
8318
  const isHovered = conv.id === hoveredId;
7947
- return /* @__PURE__ */ jsxs11(
8319
+ return /* @__PURE__ */ jsxs14(
7948
8320
  "div",
7949
8321
  {
7950
8322
  style: {
@@ -7962,17 +8334,17 @@ var HistoryList = memo12(function HistoryList2({
7962
8334
  onMouseEnter: () => setHoveredId(conv.id),
7963
8335
  onMouseLeave: () => setHoveredId(null),
7964
8336
  children: [
7965
- /* @__PURE__ */ jsxs11("div", { style: { minWidth: 0, flex: 1 }, children: [
7966
- /* @__PURE__ */ jsx16("div", { style: {
8337
+ /* @__PURE__ */ jsxs14("div", { style: { minWidth: 0, flex: 1 }, children: [
8338
+ /* @__PURE__ */ jsx19("div", { style: {
7967
8339
  fontSize: "0.875rem",
7968
8340
  color: colors.text,
7969
8341
  overflow: "hidden",
7970
8342
  textOverflow: "ellipsis",
7971
8343
  whiteSpace: "nowrap"
7972
8344
  }, children: conv.title || "Untitled" }),
7973
- /* @__PURE__ */ jsx16("div", { style: { fontSize: "0.75rem", color: colors.muted }, children: formatRelativeTime(conv.updatedAt, strings) })
8345
+ /* @__PURE__ */ jsx19("div", { style: { fontSize: "0.75rem", color: colors.muted }, children: formatRelativeTime(conv.updatedAt, strings) })
7974
8346
  ] }),
7975
- isHovered && /* @__PURE__ */ jsx16(
8347
+ isHovered && /* @__PURE__ */ jsx19(
7976
8348
  DeleteButton,
7977
8349
  {
7978
8350
  onClick: (e) => {
@@ -7988,15 +8360,234 @@ var HistoryList = memo12(function HistoryList2({
7988
8360
  conv.id
7989
8361
  );
7990
8362
  }),
7991
- hasMore && /* @__PURE__ */ jsx16("div", { ref: loadMoreRef, style: { paddingTop: "0.5rem", textAlign: "center", minHeight: "2rem" }, children: isLoading ? loadingDots : loadError ? /* @__PURE__ */ jsx16(LoadMoreButton, { onClick: onLoadMore, colors, children: strings.loadMore || "Load more" }) : null })
8363
+ hasMore && /* @__PURE__ */ jsx19("div", { ref: loadMoreRef, style: { paddingTop: "0.5rem", textAlign: "center", minHeight: "2rem" }, children: isLoading ? loadingDots : loadError ? /* @__PURE__ */ jsx19(LoadMoreButton, { onClick: onLoadMore, colors, children: strings.loadMore || "Load more" }) : null })
7992
8364
  ] });
7993
8365
  });
7994
8366
 
8367
+ // src/renderer/components/HistoryModal.tsx
8368
+ import { memo as memo13, useEffect as useEffect21, useCallback as useCallback17, useRef as useRef14, useState as useState18 } from "react";
8369
+ import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
8370
+ var ANIMATION_DURATION = 120;
8371
+ var HistoryModal = memo13(function HistoryModal2({
8372
+ isOpen,
8373
+ onClose,
8374
+ title,
8375
+ closeLabel = "Close",
8376
+ children,
8377
+ isDarkMode = false
8378
+ }) {
8379
+ const modalRef = useRef14(null);
8380
+ const [isClosing, setIsClosing] = useState18(false);
8381
+ const [shouldRender, setShouldRender] = useState18(isOpen);
8382
+ useEffect21(() => {
8383
+ if (isOpen) {
8384
+ setShouldRender(true);
8385
+ setIsClosing(false);
8386
+ }
8387
+ }, [isOpen]);
8388
+ const handleClose = useCallback17(() => {
8389
+ setIsClosing(true);
8390
+ setTimeout(() => {
8391
+ setShouldRender(false);
8392
+ setIsClosing(false);
8393
+ onClose();
8394
+ }, ANIMATION_DURATION);
8395
+ }, [onClose]);
8396
+ useEffect21(() => {
8397
+ if (!shouldRender || isClosing) return;
8398
+ const handleKeyDown = (e) => {
8399
+ if (e.key === "Escape") {
8400
+ e.preventDefault();
8401
+ handleClose();
8402
+ }
8403
+ };
8404
+ document.addEventListener("keydown", handleKeyDown);
8405
+ return () => document.removeEventListener("keydown", handleKeyDown);
8406
+ }, [shouldRender, isClosing, handleClose]);
8407
+ useEffect21(() => {
8408
+ if (!isOpen || !modalRef.current) return;
8409
+ modalRef.current.focus();
8410
+ }, [isOpen]);
8411
+ const handleBackdropClick = useCallback17(
8412
+ (e) => {
8413
+ if (e.target === e.currentTarget && !isClosing) {
8414
+ handleClose();
8415
+ }
8416
+ },
8417
+ [handleClose, isClosing]
8418
+ );
8419
+ if (!shouldRender) return null;
8420
+ const closingClass = isClosing ? " chat-modal-closing" : "";
8421
+ return /* @__PURE__ */ jsx20(
8422
+ "div",
8423
+ {
8424
+ className: `chat-modal-backdrop${closingClass}`,
8425
+ style: {
8426
+ position: "absolute",
8427
+ inset: 0,
8428
+ zIndex: 50,
8429
+ display: "flex",
8430
+ alignItems: "center",
8431
+ justifyContent: "center",
8432
+ background: "rgba(0, 0, 0, 0.5)"
8433
+ },
8434
+ onClick: handleBackdropClick,
8435
+ children: /* @__PURE__ */ jsxs15(
8436
+ "div",
8437
+ {
8438
+ ref: modalRef,
8439
+ role: "dialog",
8440
+ "aria-modal": "true",
8441
+ "aria-labelledby": "history-modal-title",
8442
+ tabIndex: -1,
8443
+ className: `chat-modal-content${closingClass}`,
8444
+ style: {
8445
+ width: "80%",
8446
+ height: "70%",
8447
+ maxWidth: "600px",
8448
+ minHeight: "300px",
8449
+ background: "var(--chat-bg)",
8450
+ borderRadius: "12px",
8451
+ border: "1px solid var(--chat-border)",
8452
+ boxShadow: isDarkMode ? "0 25px 50px -12px rgba(0, 0, 0, 0.5)" : "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
8453
+ display: "flex",
8454
+ flexDirection: "column",
8455
+ overflow: "hidden",
8456
+ outline: "none"
8457
+ },
8458
+ onClick: (e) => e.stopPropagation(),
8459
+ children: [
8460
+ /* @__PURE__ */ jsxs15(
8461
+ "div",
8462
+ {
8463
+ style: {
8464
+ display: "flex",
8465
+ alignItems: "center",
8466
+ justifyContent: "space-between",
8467
+ padding: "8px 12px",
8468
+ borderBottom: "1px solid var(--chat-border)",
8469
+ flexShrink: 0
8470
+ },
8471
+ children: [
8472
+ /* @__PURE__ */ jsx20(
8473
+ "span",
8474
+ {
8475
+ id: "history-modal-title",
8476
+ style: {
8477
+ fontSize: "0.8125rem",
8478
+ fontWeight: 500,
8479
+ color: "var(--chat-text)"
8480
+ },
8481
+ children: title
8482
+ }
8483
+ ),
8484
+ /* @__PURE__ */ jsx20(
8485
+ "button",
8486
+ {
8487
+ onClick: handleClose,
8488
+ "aria-label": closeLabel,
8489
+ style: {
8490
+ display: "flex",
8491
+ alignItems: "center",
8492
+ justifyContent: "center",
8493
+ width: "22px",
8494
+ height: "22px",
8495
+ borderRadius: "4px",
8496
+ border: "none",
8497
+ background: "transparent",
8498
+ color: "var(--chat-muted)",
8499
+ cursor: "pointer",
8500
+ transition: "background 0.15s, color 0.15s"
8501
+ },
8502
+ onMouseEnter: (e) => {
8503
+ e.currentTarget.style.background = "var(--chat-hover)";
8504
+ e.currentTarget.style.color = "var(--chat-text)";
8505
+ },
8506
+ onMouseLeave: (e) => {
8507
+ e.currentTarget.style.background = "transparent";
8508
+ e.currentTarget.style.color = "var(--chat-muted)";
8509
+ },
8510
+ title: closeLabel,
8511
+ children: /* @__PURE__ */ jsx20(
8512
+ "svg",
8513
+ {
8514
+ width: "14",
8515
+ height: "14",
8516
+ viewBox: "0 0 24 24",
8517
+ fill: "none",
8518
+ stroke: "currentColor",
8519
+ strokeWidth: "2",
8520
+ strokeLinecap: "round",
8521
+ strokeLinejoin: "round",
8522
+ children: /* @__PURE__ */ jsx20("path", { d: "M18 6L6 18M6 6l12 12" })
8523
+ }
8524
+ )
8525
+ }
8526
+ )
8527
+ ]
8528
+ }
8529
+ ),
8530
+ /* @__PURE__ */ jsx20(
8531
+ "div",
8532
+ {
8533
+ style: {
8534
+ flex: 1,
8535
+ overflow: "auto",
8536
+ minHeight: 0
8537
+ },
8538
+ className: "chat-scrollbar",
8539
+ children
8540
+ }
8541
+ )
8542
+ ]
8543
+ }
8544
+ )
8545
+ }
8546
+ );
8547
+ });
8548
+
7995
8549
  // src/renderer/components/CompactChat.tsx
7996
- import { memo as memo13, useRef as useRef13, useState as useState15, useEffect as useEffect18, useCallback as useCallback14, useMemo as useMemo10 } from "react";
8550
+ import { memo as memo14, useRef as useRef15, useState as useState19, useEffect as useEffect22, useCallback as useCallback18, useMemo as useMemo12 } from "react";
7997
8551
  import { createPortal } from "react-dom";
7998
- import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
7999
- var CompactChat = memo13(function CompactChat2({
8552
+
8553
+ // src/renderer/components/PanelControls.tsx
8554
+ import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
8555
+ function PanelHeaderButtons({
8556
+ showModeToggle = true,
8557
+ showAttachToggle = true,
8558
+ locale = "en"
8559
+ }) {
8560
+ return /* @__PURE__ */ jsxs16(Fragment4, { children: [
8561
+ showModeToggle && /* @__PURE__ */ jsx21(ModeToggleButton, { locale }),
8562
+ showAttachToggle && /* @__PURE__ */ jsx21(AttachButton, { locale })
8563
+ ] });
8564
+ }
8565
+ function PanelResizer({
8566
+ showResizer = true,
8567
+ resizerPosition = "left",
8568
+ resizerMinWidth = 280,
8569
+ resizerMaxWidth = 600
8570
+ }) {
8571
+ if (!showResizer) return null;
8572
+ return /* @__PURE__ */ jsx21(
8573
+ Resizer,
8574
+ {
8575
+ position: resizerPosition,
8576
+ minWidth: resizerMinWidth,
8577
+ maxWidth: resizerMaxWidth
8578
+ }
8579
+ );
8580
+ }
8581
+ var PanelControls = {
8582
+ HeaderButtons: PanelHeaderButtons,
8583
+ Resizer: PanelResizer,
8584
+ ModeToggleButton,
8585
+ AttachButton
8586
+ };
8587
+
8588
+ // src/renderer/components/CompactChat.tsx
8589
+ import { Fragment as Fragment5, jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
8590
+ var CompactChat = memo14(function CompactChat2({
8000
8591
  adapter,
8001
8592
  config,
8002
8593
  logo,
@@ -8031,12 +8622,12 @@ var CompactChat = memo13(function CompactChat2({
8031
8622
  const { themeClass, isDarkMode: resolvedIsDarkMode } = useResolvedTheme(themeMode);
8032
8623
  const accentStyle = useAccentStyle(resolvedConfig?.accentColor);
8033
8624
  const resolvedLogo = logo ?? resolvedConfig?.logo;
8034
- const baseStrings = useMemo10(
8625
+ const baseStrings = useMemo12(
8035
8626
  () => resolveChatStrings(resolvedConfig?.locale, resolvedConfig?.strings),
8036
8627
  [resolvedConfig?.locale, resolvedConfig?.strings]
8037
8628
  );
8038
- const mergedStrings = useMemo10(() => ({ ...baseStrings, ...strings }), [baseStrings, strings]);
8039
- const headerConfig = useMemo10(
8629
+ const mergedStrings = useMemo12(() => ({ ...baseStrings, ...strings }), [baseStrings, strings]);
8630
+ const headerConfig = useMemo12(
8040
8631
  () => {
8041
8632
  if (!resolvedConfig) {
8042
8633
  return resolvedLogo ? { logo: resolvedLogo } : void 0;
@@ -8049,16 +8640,17 @@ var CompactChat = memo13(function CompactChat2({
8049
8640
  [resolvedConfig, resolvedLogo]
8050
8641
  );
8051
8642
  const { logoNode, showPin, showClose, isPinned, togglePin, resolvedOnClose } = useChatHeader(headerConfig);
8052
- const emptyLogoNode = useMemo10(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
8053
- const chatContainerRef = useRef13(null);
8054
- const chatInputRef = useRef13(null);
8055
- const [showHistory, setShowHistory] = useState15(false);
8056
- const [connectionAlert, setConnectionAlert] = useState15(null);
8057
- const portalContainerRef = useRef13(inputPortalContainer ?? null);
8643
+ const emptyLogoNode = useMemo12(() => resolveLogoNode(resolvedLogo, "empty"), [resolvedLogo]);
8644
+ const { isEmbedded, toggleMode, hide: hidePanel } = useChatPanel();
8645
+ const chatContainerRef = useRef15(null);
8646
+ const chatInputRef = useRef15(null);
8647
+ const [showHistory, setShowHistory] = useState19(false);
8648
+ const [connectionAlert, setConnectionAlert] = useState19(null);
8649
+ const portalContainerRef = useRef15(inputPortalContainer ?? null);
8058
8650
  portalContainerRef.current = inputPortalContainer ?? null;
8059
8651
  const shouldRenderInputExternally = !!inputPortalContainer;
8060
8652
  const inputPlaceholder = placeholder ?? mergedStrings.inputPlaceholder;
8061
- const headerTitle = showHistory ? mergedStrings.recentChats || "Recent Chats" : mergedStrings.chat || "Chat";
8653
+ const headerTitle = mergedStrings.chat || "Chat";
8062
8654
  const connection = useConnection({
8063
8655
  adapter,
8064
8656
  autoConnect,
@@ -8092,27 +8684,27 @@ var CompactChat = memo13(function CompactChat2({
8092
8684
  adapter,
8093
8685
  onError
8094
8686
  });
8095
- useEffect18(() => {
8687
+ useEffect22(() => {
8096
8688
  if (sendMessageRef) {
8097
8689
  sendMessageRef.current = chat.sendMessage;
8098
8690
  }
8099
8691
  }, [sendMessageRef, chat.sendMessage]);
8100
- useEffect18(() => {
8692
+ useEffect22(() => {
8101
8693
  if (newConversationRef) {
8102
8694
  newConversationRef.current = chat.newConversation;
8103
8695
  }
8104
8696
  }, [newConversationRef, chat.newConversation]);
8105
- useEffect18(() => {
8697
+ useEffect22(() => {
8106
8698
  if (parentFocusInputRef) {
8107
8699
  parentFocusInputRef.current = () => chatInputRef.current?.focus();
8108
8700
  }
8109
8701
  }, [parentFocusInputRef]);
8110
- useEffect18(() => {
8702
+ useEffect22(() => {
8111
8703
  if (parentSetTextRef) {
8112
8704
  parentSetTextRef.current = (text) => chatInputRef.current?.setValue(text);
8113
8705
  }
8114
8706
  }, [parentSetTextRef]);
8115
- useEffect18(() => {
8707
+ useEffect22(() => {
8116
8708
  if (onMessageReceived && chat.messages.length > 0) {
8117
8709
  const lastMessage = chat.messages[chat.messages.length - 1];
8118
8710
  if (lastMessage.role === "assistant" && !lastMessage.isStreaming) {
@@ -8120,12 +8712,12 @@ var CompactChat = memo13(function CompactChat2({
8120
8712
  }
8121
8713
  }
8122
8714
  }, [chat.messages, onMessageReceived]);
8123
- useEffect18(() => {
8715
+ useEffect22(() => {
8124
8716
  if (onLoadingChange) {
8125
8717
  onLoadingChange(chat.isLoading);
8126
8718
  }
8127
8719
  }, [chat.isLoading, onLoadingChange]);
8128
- useEffect18(() => {
8720
+ useEffect22(() => {
8129
8721
  if (onStateChange) {
8130
8722
  onStateChange({
8131
8723
  messages: chat.messages,
@@ -8133,19 +8725,19 @@ var CompactChat = memo13(function CompactChat2({
8133
8725
  });
8134
8726
  }
8135
8727
  }, [chat.messages, chat.conversationId, onStateChange]);
8136
- useEffect18(() => {
8728
+ useEffect22(() => {
8137
8729
  if (showHistory && connection.isConnected) {
8138
8730
  conversations.loadConversations();
8139
8731
  }
8140
8732
  }, [showHistory, connection.isConnected]);
8141
- const handleSelectConversation = useCallback14(
8733
+ const handleSelectConversation = useCallback18(
8142
8734
  async (id) => {
8143
8735
  await chat.loadConversation(id);
8144
8736
  setShowHistory(false);
8145
8737
  },
8146
8738
  [chat]
8147
8739
  );
8148
- const handleDeleteConversation = useCallback14(
8740
+ const handleDeleteConversation = useCallback18(
8149
8741
  async (id) => {
8150
8742
  await conversations.deleteConversation(id);
8151
8743
  if (id === chat.conversationId) {
@@ -8154,14 +8746,14 @@ var CompactChat = memo13(function CompactChat2({
8154
8746
  },
8155
8747
  [conversations, chat]
8156
8748
  );
8157
- const handleNewChat = useCallback14(() => {
8749
+ const handleNewChat = useCallback18(() => {
8158
8750
  chat.newConversation();
8159
8751
  setShowHistory(false);
8160
8752
  setTimeout(() => {
8161
8753
  chatInputRef.current?.focus();
8162
8754
  }, 0);
8163
8755
  }, [chat]);
8164
- useEffect18(() => {
8756
+ useEffect22(() => {
8165
8757
  const handleKeyDown = (e) => {
8166
8758
  const isMac2 = navigator.platform.includes("Mac");
8167
8759
  const modifierKey = isMac2 ? e.metaKey : e.ctrlKey;
@@ -8175,7 +8767,7 @@ var CompactChat = memo13(function CompactChat2({
8175
8767
  }, [handleNewChat]);
8176
8768
  const isMac = typeof navigator !== "undefined" && navigator.platform.includes("Mac");
8177
8769
  const shortcutKey = isMac ? "\u2318N" : "Ctrl+N";
8178
- const defaultRenderMessage = useCallback14((message) => {
8770
+ const defaultRenderMessage = useCallback18((message) => {
8179
8771
  if (message.role === "tool") return null;
8180
8772
  const isUser = message.role === "user";
8181
8773
  const hasToolCalls = message.toolCalls && message.toolCalls.length > 0;
@@ -8187,9 +8779,9 @@ var CompactChat = memo13(function CompactChat2({
8187
8779
  const hasThinking = message.thinking || message.isThinkingStreaming || message.currentThinking;
8188
8780
  const showThinkingSection = !isUser && !hasToolActivity && !showIntermediateSteps && hasThinking;
8189
8781
  const isToolCallsStreaming = message.isToolCallsStreaming ?? ((message.toolCalls?.some((tc) => tc.status === "running") ?? false) || (message.blocks?.some((b) => b.type === "tool_call" && b.toolStatus === "running") ?? false));
8190
- return /* @__PURE__ */ jsx17("div", { className: `flex ${isUser ? "justify-end" : "justify-start"} mb-4`, children: /* @__PURE__ */ jsxs12("div", { className: `text-left ${isUser ? "max-w-[80%]" : "w-full"}`, children: [
8191
- !isUser && showIntermediateSteps && message.blocks && /* @__PURE__ */ jsx17(IntermediateSteps, { blocks: message.blocks, strings: mergedStrings }),
8192
- showThinkingSection && /* @__PURE__ */ jsx17(
8782
+ return /* @__PURE__ */ jsx22("div", { className: `flex ${isUser ? "justify-end" : "justify-start"} mb-4`, children: /* @__PURE__ */ jsxs17("div", { className: `text-left ${isUser ? "max-w-[80%]" : "w-full"}`, children: [
8783
+ !isUser && showIntermediateSteps && message.blocks && /* @__PURE__ */ jsx22(IntermediateSteps, { blocks: message.blocks, strings: mergedStrings }),
8784
+ showThinkingSection && /* @__PURE__ */ jsx22(
8193
8785
  ThinkingSection,
8194
8786
  {
8195
8787
  thinking: message.thinking || "",
@@ -8200,7 +8792,7 @@ var CompactChat = memo13(function CompactChat2({
8200
8792
  strings: mergedStrings
8201
8793
  }
8202
8794
  ),
8203
- showStreamingTimeline && message.blocks && /* @__PURE__ */ jsx17(
8795
+ showStreamingTimeline && message.blocks && /* @__PURE__ */ jsx22(
8204
8796
  StreamingTimeline,
8205
8797
  {
8206
8798
  blocks: message.blocks,
@@ -8211,23 +8803,22 @@ var CompactChat = memo13(function CompactChat2({
8211
8803
  strings: mergedStrings
8212
8804
  }
8213
8805
  ),
8214
- /* @__PURE__ */ jsx17("div", { className: `relative group ${isUser ? "inline-block max-w-full" : "block w-full"}`, style: { fontSize: "0.875rem" }, children: /* @__PURE__ */ jsx17(
8806
+ /* @__PURE__ */ jsx22("div", { className: `relative group ${isUser ? "inline-block max-w-full" : "block w-full"}`, style: { fontSize: "0.875rem" }, children: /* @__PURE__ */ jsx22(
8215
8807
  "div",
8216
8808
  {
8217
8809
  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"}`,
8218
- children: isUser ? /* @__PURE__ */ jsx17("span", { className: "whitespace-pre-wrap", children: message.content }) : message.content && /* @__PURE__ */ jsx17(MarkdownRenderer, { content: message.content, isStreaming: message.isStreaming, className: "px-3" })
8810
+ children: isUser ? /* @__PURE__ */ jsx22("span", { className: "whitespace-pre-wrap", children: message.content }) : message.content && /* @__PURE__ */ jsx22(MarkdownRenderer, { content: message.content, isStreaming: message.isStreaming, className: "px-3" })
8219
8811
  }
8220
8812
  ) })
8221
8813
  ] }) });
8222
8814
  }, [mergedStrings]);
8223
- const containerClass = floating ? `chat-window-container ${themeClass} ${className}` : `flex h-full flex-col bg-[var(--chat-bg)] text-[var(--chat-text)] ${themeClass} ${className}`;
8224
- const baseColors = useMemo10(() => {
8815
+ 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}`;
8816
+ const baseColors = useMemo12(() => {
8225
8817
  if (!floating) return null;
8226
8818
  return getBaseColors(resolvedIsDarkMode);
8227
8819
  }, [floating, resolvedIsDarkMode]);
8228
- const containerStyle = useMemo10(() => {
8229
- if (!floating || !baseColors) return accentStyle;
8230
- return {
8820
+ const containerStyle = useMemo12(() => {
8821
+ const baseStyle = floating && baseColors ? {
8231
8822
  ...accentStyle,
8232
8823
  // Override CSS variables with tinted colors for consistency with app
8233
8824
  "--chat-bg": baseColors.bg,
@@ -8235,9 +8826,17 @@ var CompactChat = memo13(function CompactChat2({
8235
8826
  "--chat-card": baseColors.card,
8236
8827
  "--chat-window-bg": baseColors.bg,
8237
8828
  "--chat-window-border": resolvedIsDarkMode ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.1)"
8238
- };
8239
- }, [floating, baseColors, accentStyle, resolvedIsDarkMode]);
8240
- return /* @__PURE__ */ jsxs12(
8829
+ } : accentStyle;
8830
+ if (isEmbedded) {
8831
+ return {
8832
+ ...baseStyle,
8833
+ borderRadius: 0,
8834
+ boxShadow: "none"
8835
+ };
8836
+ }
8837
+ return baseStyle;
8838
+ }, [floating, baseColors, accentStyle, resolvedIsDarkMode, isEmbedded]);
8839
+ return /* @__PURE__ */ jsxs17(
8241
8840
  "div",
8242
8841
  {
8243
8842
  ref: chatContainerRef,
@@ -8245,103 +8844,172 @@ var CompactChat = memo13(function CompactChat2({
8245
8844
  style: containerStyle,
8246
8845
  "data-chat-font-size": resolvedConfig?.fontSize || "normal",
8247
8846
  children: [
8248
- !hideHeader && /* @__PURE__ */ jsxs12("header", { className: "flex h-9 flex-shrink-0 items-center px-2 border-b chat-divider-border", style: { WebkitAppRegion: "drag" }, children: [
8249
- /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1", style: { WebkitAppRegion: "no-drag" }, children: [
8250
- showHistory && /* @__PURE__ */ jsx17(
8251
- "button",
8252
- {
8253
- onClick: () => setShowHistory(false),
8254
- className: headerIconButtonClass,
8255
- title: "Back",
8256
- children: /* @__PURE__ */ jsx17("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ jsx17("path", { d: "M15 19l-7-7 7-7", strokeLinecap: "round", strokeLinejoin: "round" }) })
8257
- }
8258
- ),
8259
- headerLeft || /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
8260
- logoNode,
8261
- /* @__PURE__ */ jsx17("span", { className: "text-sm font-medium text-[var(--chat-text)]", children: headerTitle })
8262
- ] })
8263
- ] }),
8264
- /* @__PURE__ */ jsx17("div", { className: "flex-1" }),
8265
- /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-0.5", style: { WebkitAppRegion: "no-drag" }, children: [
8266
- /* @__PURE__ */ jsxs12("div", { className: "chat-tooltip-wrapper", children: [
8267
- /* @__PURE__ */ jsx17(
8847
+ /* @__PURE__ */ jsx22(PanelResizer, {}),
8848
+ !hideHeader && /* @__PURE__ */ jsx22("header", { className: "flex h-9 flex-shrink-0 items-center px-2 border-b chat-divider-border", style: { WebkitAppRegion: "drag" }, children: isEmbedded ? (
8849
+ // Embedded mode: left-aligned buttons (collapse, float, history, new chat)
8850
+ /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-0.5", style: { WebkitAppRegion: "no-drag" }, children: [
8851
+ /* @__PURE__ */ jsxs17("div", { className: "chat-tooltip-wrapper", children: [
8852
+ /* @__PURE__ */ jsx22(
8853
+ "button",
8854
+ {
8855
+ onClick: hidePanel,
8856
+ className: headerIconButtonClass,
8857
+ children: /* @__PURE__ */ jsxs17("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
8858
+ /* @__PURE__ */ jsx22("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
8859
+ /* @__PURE__ */ jsx22("path", { d: "M15 4v16", strokeLinecap: "round" })
8860
+ ] })
8861
+ }
8862
+ ),
8863
+ /* @__PURE__ */ jsx22("div", { className: "chat-tooltip", children: mergedStrings.collapseSidebar })
8864
+ ] }),
8865
+ /* @__PURE__ */ jsxs17("div", { className: "chat-tooltip-wrapper", children: [
8866
+ /* @__PURE__ */ jsx22(
8867
+ "button",
8868
+ {
8869
+ onClick: toggleMode,
8870
+ className: headerIconButtonClass,
8871
+ children: /* @__PURE__ */ jsxs17("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
8872
+ /* @__PURE__ */ jsx22("rect", { x: "8", y: "3", width: "13", height: "13", rx: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
8873
+ /* @__PURE__ */ jsx22("path", { d: "M5 8H4a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-1", strokeLinecap: "round", strokeLinejoin: "round" })
8874
+ ] })
8875
+ }
8876
+ ),
8877
+ /* @__PURE__ */ jsx22("div", { className: "chat-tooltip", children: mergedStrings.floatWindow })
8878
+ ] }),
8879
+ /* @__PURE__ */ jsxs17("div", { className: "chat-tooltip-wrapper", children: [
8880
+ /* @__PURE__ */ jsx22(
8881
+ "button",
8882
+ {
8883
+ onClick: () => setShowHistory(true),
8884
+ className: headerIconButtonClass,
8885
+ children: /* @__PURE__ */ jsx22("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ jsx22("path", { d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z", strokeLinecap: "round", strokeLinejoin: "round" }) })
8886
+ }
8887
+ ),
8888
+ /* @__PURE__ */ jsx22("div", { className: "chat-tooltip", children: mergedStrings.history || mergedStrings.recentChats })
8889
+ ] }),
8890
+ /* @__PURE__ */ jsxs17("div", { className: "chat-tooltip-wrapper", children: [
8891
+ /* @__PURE__ */ jsx22(
8268
8892
  "button",
8269
8893
  {
8270
8894
  onClick: handleNewChat,
8271
8895
  className: headerIconButtonClass,
8272
- children: /* @__PURE__ */ jsx17("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ jsx17("path", { d: "M12 5v14m-7-7h14", strokeLinecap: "round", strokeLinejoin: "round" }) })
8896
+ children: /* @__PURE__ */ jsx22("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ jsx22("path", { d: "M12 5v14m-7-7h14", strokeLinecap: "round", strokeLinejoin: "round" }) })
8273
8897
  }
8274
8898
  ),
8275
- /* @__PURE__ */ jsxs12("div", { className: "chat-tooltip", children: [
8276
- /* @__PURE__ */ jsx17("div", { children: mergedStrings.newChat || "New Chat" }),
8277
- /* @__PURE__ */ jsx17("div", { className: "chat-tooltip-shortcut", children: shortcutKey })
8899
+ /* @__PURE__ */ jsxs17("div", { className: "chat-tooltip", children: [
8900
+ /* @__PURE__ */ jsx22("div", { children: mergedStrings.newChat || "New Chat" }),
8901
+ /* @__PURE__ */ jsx22("div", { className: "chat-tooltip-shortcut", children: shortcutKey })
8278
8902
  ] })
8279
8903
  ] }),
8280
- !showHistory && /* @__PURE__ */ jsx17(
8281
- "button",
8282
- {
8283
- onClick: () => setShowHistory(true),
8284
- className: headerIconButtonClass,
8285
- title: mergedStrings.recentChats || "Recent Chats",
8286
- children: /* @__PURE__ */ jsx17("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ jsx17("path", { d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z", strokeLinecap: "round", strokeLinejoin: "round" }) })
8287
- }
8288
- ),
8289
- showPin && /* @__PURE__ */ jsx17(
8290
- "button",
8291
- {
8292
- onClick: togglePin,
8293
- className: headerIconButtonClass,
8294
- title: isPinned ? mergedStrings.unpin : mergedStrings.pin,
8295
- children: /* @__PURE__ */ jsx17("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: isPinned ? (
8296
- // Pin (active state) - lucide pin
8297
- /* @__PURE__ */ jsxs12(Fragment4, { children: [
8298
- /* @__PURE__ */ jsx17("path", { d: "M12 17v5" }),
8299
- /* @__PURE__ */ jsx17("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" })
8300
- ] })
8301
- ) : (
8302
- // PinOff (inactive state) - lucide pin-off
8303
- /* @__PURE__ */ jsxs12(Fragment4, { children: [
8304
- /* @__PURE__ */ jsx17("path", { d: "M12 17v5" }),
8305
- /* @__PURE__ */ jsx17("path", { d: "M15 9.34V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H7.89" }),
8306
- /* @__PURE__ */ jsx17("path", { d: "m2 2 20 20" }),
8307
- /* @__PURE__ */ jsx17("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" })
8308
- ] })
8309
- ) })
8310
- }
8311
- ),
8312
- showClose && /* @__PURE__ */ jsx17(
8313
- "button",
8314
- {
8315
- onClick: resolvedOnClose,
8316
- className: headerIconButtonClass,
8317
- title: mergedStrings.close,
8318
- children: /* @__PURE__ */ jsx17("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ jsx17("path", { d: "M6 6l12 12M18 6l-12 12", strokeLinecap: "round", strokeLinejoin: "round" }) })
8319
- }
8320
- ),
8321
8904
  headerRight
8322
8905
  ] })
8323
- ] }),
8324
- showHistory ? /* @__PURE__ */ jsx17("div", { className: "flex-1 overflow-y-auto chat-scrollbar pt-2", children: /* @__PURE__ */ jsx17(
8325
- HistoryList,
8906
+ ) : (
8907
+ // Floating mode: original layout with logo, title, and right-aligned buttons
8908
+ /* @__PURE__ */ jsxs17(Fragment5, { children: [
8909
+ /* @__PURE__ */ jsx22("div", { className: "flex items-center gap-1", style: { WebkitAppRegion: "no-drag" }, children: headerLeft || /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-2", children: [
8910
+ logoNode,
8911
+ /* @__PURE__ */ jsx22("span", { className: "text-sm font-medium text-[var(--chat-text)]", children: headerTitle })
8912
+ ] }) }),
8913
+ /* @__PURE__ */ jsx22("div", { className: "flex-1" }),
8914
+ /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-0.5", style: { WebkitAppRegion: "no-drag" }, children: [
8915
+ /* @__PURE__ */ jsx22(PanelHeaderButtons, { locale: resolvedConfig?.locale }),
8916
+ /* @__PURE__ */ jsxs17("div", { className: "chat-tooltip-wrapper", children: [
8917
+ /* @__PURE__ */ jsx22(
8918
+ "button",
8919
+ {
8920
+ onClick: handleNewChat,
8921
+ className: headerIconButtonClass,
8922
+ children: /* @__PURE__ */ jsx22("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ jsx22("path", { d: "M12 5v14m-7-7h14", strokeLinecap: "round", strokeLinejoin: "round" }) })
8923
+ }
8924
+ ),
8925
+ /* @__PURE__ */ jsxs17("div", { className: "chat-tooltip", children: [
8926
+ /* @__PURE__ */ jsx22("div", { children: mergedStrings.newChat || "New Chat" }),
8927
+ /* @__PURE__ */ jsx22("div", { className: "chat-tooltip-shortcut", children: shortcutKey })
8928
+ ] })
8929
+ ] }),
8930
+ /* @__PURE__ */ jsxs17("div", { className: "chat-tooltip-wrapper", children: [
8931
+ /* @__PURE__ */ jsx22(
8932
+ "button",
8933
+ {
8934
+ onClick: () => setShowHistory(true),
8935
+ className: headerIconButtonClass,
8936
+ children: /* @__PURE__ */ jsx22("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ jsx22("path", { d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z", strokeLinecap: "round", strokeLinejoin: "round" }) })
8937
+ }
8938
+ ),
8939
+ /* @__PURE__ */ jsx22("div", { className: "chat-tooltip", children: mergedStrings.recentChats || "Recent Chats" })
8940
+ ] }),
8941
+ showPin && /* @__PURE__ */ jsxs17("div", { className: "chat-tooltip-wrapper", children: [
8942
+ /* @__PURE__ */ jsx22(
8943
+ "button",
8944
+ {
8945
+ onClick: togglePin,
8946
+ className: headerIconButtonClass,
8947
+ children: /* @__PURE__ */ jsx22("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: isPinned ? (
8948
+ // Pin (active state) - lucide pin
8949
+ /* @__PURE__ */ jsxs17(Fragment5, { children: [
8950
+ /* @__PURE__ */ jsx22("path", { d: "M12 17v5" }),
8951
+ /* @__PURE__ */ jsx22("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" })
8952
+ ] })
8953
+ ) : (
8954
+ // PinOff (inactive state) - lucide pin-off
8955
+ /* @__PURE__ */ jsxs17(Fragment5, { children: [
8956
+ /* @__PURE__ */ jsx22("path", { d: "M12 17v5" }),
8957
+ /* @__PURE__ */ jsx22("path", { d: "M15 9.34V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H7.89" }),
8958
+ /* @__PURE__ */ jsx22("path", { d: "m2 2 20 20" }),
8959
+ /* @__PURE__ */ jsx22("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" })
8960
+ ] })
8961
+ ) })
8962
+ }
8963
+ ),
8964
+ /* @__PURE__ */ jsx22("div", { className: "chat-tooltip", children: isPinned ? mergedStrings.unpin : mergedStrings.pin })
8965
+ ] }),
8966
+ showClose && /* @__PURE__ */ jsxs17("div", { className: "chat-tooltip-wrapper", children: [
8967
+ /* @__PURE__ */ jsx22(
8968
+ "button",
8969
+ {
8970
+ onClick: resolvedOnClose,
8971
+ className: headerIconButtonClass,
8972
+ children: /* @__PURE__ */ jsx22("svg", { className: headerIconClass, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: /* @__PURE__ */ jsx22("path", { d: "M6 6l12 12M18 6l-12 12", strokeLinecap: "round", strokeLinejoin: "round" }) })
8973
+ }
8974
+ ),
8975
+ /* @__PURE__ */ jsx22("div", { className: "chat-tooltip", children: mergedStrings.close })
8976
+ ] }),
8977
+ headerRight
8978
+ ] })
8979
+ ] })
8980
+ ) }),
8981
+ /* @__PURE__ */ jsx22(
8982
+ HistoryModal,
8326
8983
  {
8327
- conversations: conversations.conversations,
8328
- selectedId: chat.conversationId,
8329
- isLoading: conversations.isLoading,
8330
- hasMore: conversations.hasMore,
8331
- loadError: conversations.loadError,
8332
- onSelect: handleSelectConversation,
8333
- onDelete: handleDeleteConversation,
8334
- onLoadMore: conversations.loadMore,
8984
+ isOpen: showHistory,
8985
+ onClose: () => setShowHistory(false),
8986
+ title: mergedStrings.recentChats || "Recent Chats",
8987
+ closeLabel: mergedStrings.close || "Close",
8335
8988
  isDarkMode: resolvedIsDarkMode,
8336
- strings: {
8337
- noHistory: mergedStrings.noHistory,
8338
- loadMore: mergedStrings.loadMore,
8339
- today: mergedStrings.today,
8340
- yesterday: mergedStrings.yesterday,
8341
- delete: mergedStrings.delete
8342
- }
8989
+ children: /* @__PURE__ */ jsx22(
8990
+ HistoryList,
8991
+ {
8992
+ conversations: conversations.conversations,
8993
+ selectedId: chat.conversationId,
8994
+ isLoading: conversations.isLoading,
8995
+ hasMore: conversations.hasMore,
8996
+ loadError: conversations.loadError,
8997
+ onSelect: handleSelectConversation,
8998
+ onDelete: handleDeleteConversation,
8999
+ onLoadMore: conversations.loadMore,
9000
+ isDarkMode: resolvedIsDarkMode,
9001
+ strings: {
9002
+ noHistory: mergedStrings.noHistory,
9003
+ loadMore: mergedStrings.loadMore,
9004
+ today: mergedStrings.today,
9005
+ yesterday: mergedStrings.yesterday,
9006
+ delete: mergedStrings.delete
9007
+ }
9008
+ }
9009
+ )
8343
9010
  }
8344
- ) }) : chat.messages.length === 0 ? /* @__PURE__ */ jsx17("div", { className: "flex flex-1 items-center justify-center p-4", children: emptyState ?? /* @__PURE__ */ jsx17("div", { className: "flex items-center justify-center", children: emptyLogoNode }) }) : /* @__PURE__ */ jsx17(
9011
+ ),
9012
+ chat.messages.length === 0 ? /* @__PURE__ */ jsx22("div", { className: "flex flex-1 items-center justify-center p-4", children: emptyState ?? /* @__PURE__ */ jsx22("div", { className: "flex items-center justify-center", children: emptyLogoNode }) }) : /* @__PURE__ */ jsx22(
8345
9013
  MessageList,
8346
9014
  {
8347
9015
  messages: chat.messages,
@@ -8351,83 +9019,80 @@ var CompactChat = memo13(function CompactChat2({
8351
9019
  ),
8352
9020
  (() => {
8353
9021
  if (hideInput && !shouldRenderInputExternally) return null;
8354
- const disableInput = showHistory || !!chat.pendingInterrupt || chat.isLoading && !chat.isStreaming;
8355
- const inputElement = /* @__PURE__ */ jsx17(
9022
+ const disableInput = !!chat.pendingInterrupt || chat.isLoading && !chat.isStreaming;
9023
+ const inputElement = /* @__PURE__ */ jsx22(
8356
9024
  ChatInput,
8357
9025
  {
8358
9026
  ref: chatInputRef,
8359
9027
  onSend: chat.sendMessage,
8360
9028
  onStop: chat.stopStreaming,
8361
- placeholder: showHistory ? mergedStrings.selectConversation : inputPlaceholder,
9029
+ placeholder: inputPlaceholder,
8362
9030
  sendLabel: mergedStrings.inputSend,
8363
9031
  stopLabel: mergedStrings.inputStop,
8364
9032
  disabled: disableInput,
8365
9033
  isStreaming: chat.isStreaming,
8366
9034
  isLoading: chat.isLoading,
8367
- autoFocus: !showHistory,
8368
- className: showHistory ? "opacity-50" : ""
9035
+ autoFocus: true
8369
9036
  }
8370
9037
  );
8371
9038
  if (shouldRenderInputExternally && portalContainerRef.current) {
8372
9039
  return createPortal(inputElement, portalContainerRef.current);
8373
9040
  }
8374
- return /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-2 px-3 pb-3 pt-1", children: [
8375
- !showHistory && /* @__PURE__ */ jsxs12(Fragment4, { children: [
8376
- alert ? /* @__PURE__ */ jsx17(
8377
- AlertBanner,
8378
- {
8379
- type: alert.type,
8380
- message: alert.message,
8381
- action: alert.action,
8382
- onDismiss: alert.dismissible ? onAlertDismiss : void 0,
8383
- 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"}`
8384
- }
8385
- ) : connectionAlert ? /* @__PURE__ */ jsx17(
8386
- AlertBanner,
8387
- {
8388
- type: connectionAlert.type,
8389
- message: connectionAlert.message,
8390
- action: connectionAlert.action,
8391
- onDismiss: connectionAlert.dismissible ? () => setConnectionAlert(null) : void 0,
8392
- 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"}`
8393
- }
8394
- ) : chat.error && /* @__PURE__ */ jsx17(
8395
- AlertBanner,
8396
- {
8397
- type: "error",
8398
- message: chat.error,
8399
- onDismiss: () => chat.setError(null),
8400
- 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"}`
8401
- }
8402
- ),
8403
- chat.pendingInterrupt && /* @__PURE__ */ jsx17(
8404
- HitlCard,
8405
- {
8406
- interrupt: chat.pendingInterrupt,
8407
- onApprove: chat.approveHitl,
8408
- onReject: chat.rejectHitl,
8409
- onSubmit: chat.submitHitlInput,
8410
- isDarkMode: resolvedIsDarkMode,
8411
- strings: {
8412
- approve: mergedStrings.hitlApprove,
8413
- reject: mergedStrings.hitlReject,
8414
- submit: mergedStrings.hitlSubmit,
8415
- cancel: mergedStrings.hitlCancel,
8416
- rememberChoice: mergedStrings.hitlRememberChoice,
8417
- requiredField: mergedStrings.hitlRequiredField,
8418
- timeoutIn: mergedStrings.hitlTimeoutIn,
8419
- seconds: mergedStrings.hitlSeconds,
8420
- executeTool: mergedStrings.hitlExecuteTool,
8421
- toolLabel: mergedStrings.hitlToolLabel,
8422
- argsLabel: mergedStrings.hitlArgsLabel,
8423
- defaultPrefix: mergedStrings.hitlDefaultPrefix,
8424
- enterResponse: mergedStrings.hitlEnterResponse,
8425
- approvalRequest: mergedStrings.hitlApprovalRequest,
8426
- inputRequest: mergedStrings.hitlInputRequest
8427
- }
9041
+ return /* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-2 px-3 pb-3 pt-1", children: [
9042
+ alert ? /* @__PURE__ */ jsx22(
9043
+ AlertBanner,
9044
+ {
9045
+ type: alert.type,
9046
+ message: alert.message,
9047
+ action: alert.action,
9048
+ onDismiss: alert.dismissible ? onAlertDismiss : void 0,
9049
+ 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"}`
9050
+ }
9051
+ ) : connectionAlert ? /* @__PURE__ */ jsx22(
9052
+ AlertBanner,
9053
+ {
9054
+ type: connectionAlert.type,
9055
+ message: connectionAlert.message,
9056
+ action: connectionAlert.action,
9057
+ onDismiss: connectionAlert.dismissible ? () => setConnectionAlert(null) : void 0,
9058
+ 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"}`
9059
+ }
9060
+ ) : chat.error ? /* @__PURE__ */ jsx22(
9061
+ AlertBanner,
9062
+ {
9063
+ type: "error",
9064
+ message: chat.error,
9065
+ onDismiss: () => chat.setError(null),
9066
+ 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"}`
9067
+ }
9068
+ ) : null,
9069
+ chat.pendingInterrupt && /* @__PURE__ */ jsx22(
9070
+ HitlCard,
9071
+ {
9072
+ interrupt: chat.pendingInterrupt,
9073
+ onApprove: chat.approveHitl,
9074
+ onReject: chat.rejectHitl,
9075
+ onSubmit: chat.submitHitlInput,
9076
+ isDarkMode: resolvedIsDarkMode,
9077
+ strings: {
9078
+ approve: mergedStrings.hitlApprove,
9079
+ reject: mergedStrings.hitlReject,
9080
+ submit: mergedStrings.hitlSubmit,
9081
+ cancel: mergedStrings.hitlCancel,
9082
+ rememberChoice: mergedStrings.hitlRememberChoice,
9083
+ requiredField: mergedStrings.hitlRequiredField,
9084
+ timeoutIn: mergedStrings.hitlTimeoutIn,
9085
+ seconds: mergedStrings.hitlSeconds,
9086
+ executeTool: mergedStrings.hitlExecuteTool,
9087
+ toolLabel: mergedStrings.hitlToolLabel,
9088
+ argsLabel: mergedStrings.hitlArgsLabel,
9089
+ defaultPrefix: mergedStrings.hitlDefaultPrefix,
9090
+ enterResponse: mergedStrings.hitlEnterResponse,
9091
+ approvalRequest: mergedStrings.hitlApprovalRequest,
9092
+ inputRequest: mergedStrings.hitlInputRequest
8428
9093
  }
8429
- )
8430
- ] }),
9094
+ }
9095
+ ),
8431
9096
  inputElement
8432
9097
  ] });
8433
9098
  })()
@@ -8437,16 +9102,23 @@ var CompactChat = memo13(function CompactChat2({
8437
9102
  });
8438
9103
  export {
8439
9104
  AlertBanner,
9105
+ AttachButton,
8440
9106
  ChatInput,
8441
9107
  CompactChat,
8442
9108
  FloatingChat,
8443
9109
  HistoryList,
9110
+ HistoryModal,
8444
9111
  HitlCard,
8445
9112
  I18nProvider,
8446
9113
  IntermediateSteps,
8447
9114
  MarkdownRenderer,
8448
9115
  MessageBubble,
8449
9116
  MessageList,
9117
+ ModeToggleButton,
9118
+ PanelControls,
9119
+ PanelHeaderButtons,
9120
+ PanelResizer,
9121
+ Resizer,
8450
9122
  SanqianChat,
8451
9123
  SanqianChatMessage,
8452
9124
  SanqianMessageList,
@@ -8462,7 +9134,9 @@ export {
8462
9134
  ensureFullChatStyles,
8463
9135
  getTranslations,
8464
9136
  resolveChatStrings,
9137
+ useAttachState,
8465
9138
  useChat,
9139
+ useChatPanel,
8466
9140
  useChatStyles,
8467
9141
  useConnection,
8468
9142
  useConversations,