@lobehub/lobehub 2.0.0-next.273 → 2.0.0-next.275

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.
Files changed (237) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/changelog/v1.json +18 -0
  3. package/locales/ar/chat.json +7 -0
  4. package/locales/ar/models.json +2 -3
  5. package/locales/ar/plugin.json +22 -1
  6. package/locales/bg-BG/chat.json +7 -0
  7. package/locales/bg-BG/models.json +3 -3
  8. package/locales/bg-BG/plugin.json +22 -1
  9. package/locales/de-DE/chat.json +7 -0
  10. package/locales/de-DE/models.json +3 -4
  11. package/locales/de-DE/plugin.json +22 -1
  12. package/locales/en-US/chat.json +7 -0
  13. package/locales/en-US/models.json +5 -5
  14. package/locales/en-US/plugin.json +22 -1
  15. package/locales/es-ES/chat.json +7 -0
  16. package/locales/es-ES/models.json +3 -4
  17. package/locales/es-ES/plugin.json +22 -1
  18. package/locales/fa-IR/chat.json +7 -0
  19. package/locales/fa-IR/models.json +3 -4
  20. package/locales/fa-IR/plugin.json +22 -1
  21. package/locales/fr-FR/chat.json +7 -0
  22. package/locales/fr-FR/models.json +50 -3
  23. package/locales/fr-FR/plugin.json +22 -1
  24. package/locales/it-IT/chat.json +7 -0
  25. package/locales/it-IT/models.json +3 -3
  26. package/locales/it-IT/plugin.json +22 -1
  27. package/locales/ja-JP/chat.json +7 -0
  28. package/locales/ja-JP/models.json +43 -4
  29. package/locales/ja-JP/plugin.json +22 -1
  30. package/locales/ko-KR/chat.json +7 -0
  31. package/locales/ko-KR/models.json +3 -4
  32. package/locales/ko-KR/plugin.json +22 -1
  33. package/locales/nl-NL/chat.json +7 -0
  34. package/locales/nl-NL/models.json +51 -3
  35. package/locales/nl-NL/plugin.json +22 -1
  36. package/locales/pl-PL/chat.json +7 -0
  37. package/locales/pl-PL/models.json +3 -3
  38. package/locales/pl-PL/plugin.json +22 -1
  39. package/locales/pt-BR/chat.json +7 -0
  40. package/locales/pt-BR/models.json +3 -4
  41. package/locales/pt-BR/plugin.json +22 -1
  42. package/locales/ru-RU/chat.json +7 -0
  43. package/locales/ru-RU/models.json +3 -4
  44. package/locales/ru-RU/plugin.json +22 -1
  45. package/locales/tr-TR/chat.json +7 -0
  46. package/locales/tr-TR/models.json +3 -4
  47. package/locales/tr-TR/plugin.json +22 -1
  48. package/locales/vi-VN/chat.json +7 -0
  49. package/locales/vi-VN/models.json +3 -3
  50. package/locales/vi-VN/plugin.json +22 -1
  51. package/locales/zh-CN/chat.json +7 -0
  52. package/locales/zh-CN/models.json +54 -4
  53. package/locales/zh-CN/plugin.json +22 -1
  54. package/locales/zh-TW/chat.json +7 -0
  55. package/locales/zh-TW/models.json +43 -4
  56. package/locales/zh-TW/plugin.json +22 -1
  57. package/package.json +2 -2
  58. package/packages/builtin-tool-agent-builder/package.json +1 -0
  59. package/packages/builtin-tool-agent-builder/src/client/Inspector/GetAvailableModels/index.tsx +66 -0
  60. package/packages/builtin-tool-agent-builder/src/client/Inspector/InstallPlugin/index.tsx +63 -0
  61. package/packages/builtin-tool-agent-builder/src/client/Inspector/SearchMarketTools/index.tsx +64 -0
  62. package/packages/builtin-tool-agent-builder/src/client/Inspector/UpdateConfig/index.tsx +94 -0
  63. package/packages/builtin-tool-agent-builder/src/client/Inspector/UpdatePrompt/index.tsx +96 -0
  64. package/packages/builtin-tool-agent-builder/src/client/Inspector/index.ts +29 -0
  65. package/packages/builtin-tool-agent-builder/src/client/index.ts +13 -0
  66. package/packages/builtin-tool-agent-builder/src/executor.ts +132 -0
  67. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/ExecuteCode/index.tsx +5 -14
  68. package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/RunCommand/index.tsx +5 -13
  69. package/packages/builtin-tool-group-agent-builder/package.json +7 -1
  70. package/packages/builtin-tool-group-agent-builder/src/ExecutionRuntime/index.ts +331 -87
  71. package/packages/builtin-tool-group-agent-builder/src/client/Inspector/BatchCreateAgents/index.tsx +110 -0
  72. package/packages/builtin-tool-group-agent-builder/src/client/Inspector/CreateAgent/index.tsx +72 -0
  73. package/packages/builtin-tool-group-agent-builder/src/client/Inspector/InviteAgent/index.tsx +57 -0
  74. package/packages/builtin-tool-group-agent-builder/src/client/Inspector/RemoveAgent/index.tsx +57 -0
  75. package/packages/builtin-tool-group-agent-builder/src/client/Inspector/SearchAgent/index.tsx +66 -0
  76. package/packages/builtin-tool-group-agent-builder/src/client/Inspector/UpdateAgentPrompt/index.tsx +120 -0
  77. package/packages/builtin-tool-group-agent-builder/src/client/Inspector/UpdateGroup/index.tsx +87 -0
  78. package/packages/builtin-tool-group-agent-builder/src/client/Inspector/UpdateGroupPrompt/index.tsx +99 -0
  79. package/packages/builtin-tool-group-agent-builder/src/client/Inspector/index.ts +52 -0
  80. package/packages/builtin-tool-group-agent-builder/src/client/Render/BatchCreateAgents.tsx +103 -0
  81. package/packages/builtin-tool-group-agent-builder/src/client/Render/UpdateAgentPrompt/index.tsx +36 -0
  82. package/packages/builtin-tool-group-agent-builder/src/client/Render/UpdateGroupPrompt/index.tsx +36 -0
  83. package/packages/builtin-tool-group-agent-builder/src/client/Render/index.ts +16 -0
  84. package/packages/builtin-tool-group-agent-builder/src/client/Streaming/BatchCreateAgents/index.tsx +88 -0
  85. package/packages/builtin-tool-group-agent-builder/src/client/Streaming/UpdateAgentPrompt/index.tsx +37 -0
  86. package/packages/builtin-tool-group-agent-builder/src/client/Streaming/UpdateGroupPrompt/index.tsx +35 -0
  87. package/packages/builtin-tool-group-agent-builder/src/client/Streaming/index.ts +22 -0
  88. package/packages/builtin-tool-group-agent-builder/src/client/index.ts +26 -0
  89. package/packages/builtin-tool-group-agent-builder/src/executor.ts +284 -0
  90. package/packages/builtin-tool-group-agent-builder/src/index.ts +1 -14
  91. package/packages/builtin-tool-group-agent-builder/src/manifest.ts +160 -15
  92. package/packages/builtin-tool-group-agent-builder/src/systemRole.ts +232 -46
  93. package/packages/builtin-tool-group-agent-builder/src/types.ts +191 -41
  94. package/packages/builtin-tool-group-management/src/client/Inspector/Broadcast/index.tsx +2 -2
  95. package/packages/builtin-tool-group-management/src/manifest.ts +1 -1
  96. package/packages/builtin-tool-gtd/src/client/Inspector/ClearTodos/index.tsx +5 -11
  97. package/packages/builtin-tool-gtd/src/client/Inspector/CompleteTodos/index.tsx +3 -9
  98. package/packages/builtin-tool-gtd/src/client/Inspector/CreatePlan/index.tsx +6 -15
  99. package/packages/builtin-tool-gtd/src/client/Inspector/CreateTodos/index.tsx +3 -9
  100. package/packages/builtin-tool-gtd/src/client/Inspector/ExecTask/index.tsx +6 -17
  101. package/packages/builtin-tool-gtd/src/client/Inspector/RemoveTodos/index.tsx +3 -9
  102. package/packages/builtin-tool-gtd/src/client/Inspector/UpdatePlan/index.tsx +3 -9
  103. package/packages/builtin-tool-gtd/src/client/Inspector/UpdateTodos/index.tsx +3 -9
  104. package/packages/builtin-tool-knowledge-base/src/client/Inspector/ReadKnowledge/index.tsx +4 -16
  105. package/packages/builtin-tool-knowledge-base/src/client/Inspector/SearchKnowledgeBase/index.tsx +5 -16
  106. package/packages/builtin-tool-local-system/src/client/Inspector/EditLocalFile/index.tsx +4 -12
  107. package/packages/builtin-tool-local-system/src/client/Inspector/GlobLocalFiles/index.tsx +5 -13
  108. package/packages/builtin-tool-local-system/src/client/Inspector/GrepContent/index.tsx +5 -16
  109. package/packages/builtin-tool-local-system/src/client/Inspector/ListLocalFiles/index.tsx +5 -16
  110. package/packages/builtin-tool-local-system/src/client/Inspector/ReadLocalFile/index.tsx +5 -16
  111. package/packages/builtin-tool-local-system/src/client/Inspector/RenameLocalFile/index.tsx +5 -11
  112. package/packages/builtin-tool-local-system/src/client/Inspector/RunCommand/index.tsx +5 -13
  113. package/packages/builtin-tool-local-system/src/client/Inspector/SearchLocalFiles/index.tsx +5 -16
  114. package/packages/builtin-tool-local-system/src/client/Inspector/WriteLocalFile/index.tsx +6 -15
  115. package/packages/builtin-tool-notebook/src/client/Inspector/CreateDocument/index.tsx +7 -15
  116. package/packages/builtin-tool-page-agent/src/client/Inspector/EditTitle/index.tsx +5 -14
  117. package/packages/builtin-tool-page-agent/src/client/Inspector/GetPageContent/index.tsx +7 -8
  118. package/packages/builtin-tool-page-agent/src/client/Inspector/InitPage/index.tsx +4 -10
  119. package/packages/builtin-tool-page-agent/src/client/Inspector/ModifyNodes/index.tsx +3 -9
  120. package/packages/builtin-tool-page-agent/src/client/Inspector/ReplaceText/index.tsx +5 -11
  121. package/packages/builtin-tool-web-browsing/src/client/Inspector/CrawlMultiPages/index.tsx +6 -15
  122. package/packages/builtin-tool-web-browsing/src/client/Inspector/CrawlSinglePage/index.tsx +6 -15
  123. package/packages/builtin-tool-web-browsing/src/client/Inspector/Search/index.tsx +4 -15
  124. package/packages/database/src/models/chatGroup.ts +1 -1
  125. package/packages/model-bank/src/aiModels/aihubmix.ts +2 -1
  126. package/packages/model-bank/src/aiModels/google.ts +2 -1
  127. package/packages/model-bank/src/aiModels/infiniai.ts +9 -6
  128. package/packages/model-bank/src/aiModels/minimax.ts +9 -5
  129. package/packages/model-bank/src/aiModels/ollamacloud.ts +4 -2
  130. package/packages/model-bank/src/aiModels/vertexai.ts +2 -1
  131. package/packages/types/src/agentGroup/index.ts +8 -0
  132. package/patches/@upstash__qstash.patch +13 -1
  133. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Header/Nav.tsx +1 -1
  134. package/src/app/[variants]/(main)/agent/cron/[cronId]/index.tsx +4 -3
  135. package/src/app/[variants]/(main)/agent/profile/features/ProfileEditor/index.tsx +1 -1
  136. package/src/app/[variants]/(main)/agent/profile/features/store/action.ts +18 -21
  137. package/src/app/[variants]/(main)/community/(detail)/features/MakedownRender.tsx +8 -6
  138. package/src/app/[variants]/(main)/group/_layout/GroupIdSync.tsx +6 -1
  139. package/src/app/[variants]/(main)/group/_layout/Sidebar/GroupConfig/AgentProfilePopup.tsx +29 -21
  140. package/src/app/[variants]/(main)/group/_layout/Sidebar/GroupConfig/GroupMember.tsx +1 -0
  141. package/src/app/[variants]/(main)/group/_layout/Sidebar/GroupConfig/GroupMemberItem.tsx +35 -18
  142. package/src/app/[variants]/(main)/group/_layout/Sidebar/Header/AddTopicButon.tsx +2 -10
  143. package/src/app/[variants]/(main)/group/_layout/Sidebar/Header/Nav.tsx +10 -2
  144. package/src/app/[variants]/(main)/group/_layout/Sidebar/Header/index.tsx +1 -2
  145. package/src/app/[variants]/(main)/group/profile/features/AgentBuilder/AgentBuilderProvider.tsx +1 -0
  146. package/src/app/[variants]/(main)/group/profile/features/AgentBuilder/TopicSelector.tsx +15 -9
  147. package/src/app/[variants]/(main)/group/profile/features/AgentBuilder/index.tsx +12 -6
  148. package/src/app/[variants]/(main)/group/profile/features/{ProfileEditor/AgentHeader.tsx → GroupProfile/GroupHeader.tsx} +22 -29
  149. package/src/app/[variants]/(main)/group/profile/features/GroupProfile/index.tsx +96 -0
  150. package/src/app/[variants]/(main)/group/profile/features/Header/AgentBuilderToggle.tsx +3 -4
  151. package/src/app/[variants]/(main)/group/profile/features/Header/AutoSaveHint.tsx +11 -7
  152. package/src/app/[variants]/(main)/group/profile/features/Header/ChromeTabs/index.tsx +147 -0
  153. package/src/app/[variants]/(main)/group/profile/features/Header/index.tsx +104 -13
  154. package/src/app/[variants]/(main)/group/profile/features/MemberProfile/AgentHeader.tsx +222 -0
  155. package/src/app/[variants]/(main)/group/profile/features/MemberProfile/index.tsx +155 -0
  156. package/src/app/[variants]/(main)/group/profile/features/ProfileHydration.tsx +63 -5
  157. package/src/app/[variants]/(main)/group/profile/index.tsx +34 -37
  158. package/src/app/[variants]/(main)/settings/proxy/features/ProxyForm.tsx +156 -253
  159. package/src/app/[variants]/(main)/settings/proxy/index.tsx +1 -3
  160. package/src/app/[variants]/(mobile)/(home)/_layout/SessionHydration.tsx +1 -1
  161. package/src/app/[variants]/(mobile)/(home)/features/SessionListContent/List/Item/index.tsx +1 -1
  162. package/src/features/AgentBuilder/index.tsx +16 -1
  163. package/src/features/Conversation/Messages/AssistantGroup/Tool/Inspector/StatusIndicator.tsx +3 -2
  164. package/src/features/Conversation/Messages/User/useMarkdown.tsx +1 -0
  165. package/src/features/EditorCanvas/EditorCanvas.test.tsx +206 -0
  166. package/src/features/EditorCanvas/EditorDataMode.tsx +53 -19
  167. package/src/features/EditorModal/index.tsx +2 -2
  168. package/src/features/NavPanel/components/SessionHydration.tsx +1 -1
  169. package/src/features/PageEditor/EditorCanvas/useAskCopilotItem.tsx +10 -6
  170. package/src/features/PageEditor/Header/index.tsx +12 -10
  171. package/src/features/PageEditor/Header/useMenu.tsx +45 -48
  172. package/src/features/RightPanel/ToggleRightPanelButton.tsx +3 -1
  173. package/src/features/ShareModal/ShareImage/ChatList/index.tsx +1 -1
  174. package/src/features/ShareModal/SharePdf/index.tsx +1 -1
  175. package/src/hooks/useBidirectionalQuerySync.ts +112 -0
  176. package/src/locales/default/chat.ts +10 -0
  177. package/src/locales/default/plugin.ts +22 -1
  178. package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +45 -45
  179. package/src/server/modules/KeyVaultsEncrypt/index.ts +6 -6
  180. package/src/server/modules/S3/index.ts +1 -1
  181. package/src/server/routers/lambda/agent.ts +24 -0
  182. package/src/server/routers/lambda/agentGroup.ts +39 -0
  183. package/src/services/agent.ts +22 -0
  184. package/src/services/chatGroup/index.ts +14 -0
  185. package/src/store/agent/selectors/selectors.ts +3 -0
  186. package/src/store/agentGroup/initialState.ts +6 -0
  187. package/src/store/agentGroup/selectors/byId.ts +3 -1
  188. package/src/store/agentGroup/selectors/current.ts +2 -2
  189. package/src/store/agentGroup/slices/lifecycle.ts +18 -0
  190. package/src/store/chat/agents/__tests__/createAgentExecutors/fixtures/mockStore.ts +1 -1
  191. package/src/store/chat/slices/aiAgent/actions/__tests__/agentGroup.test.ts +4 -1
  192. package/src/store/chat/slices/aiAgent/actions/agentGroup.ts +1 -1
  193. package/src/store/chat/slices/aiChat/actions/__tests__/conversationLifecycle.test.ts +65 -0
  194. package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +2 -1
  195. package/src/store/chat/slices/builtinTool/actions/__tests__/search.test.ts +1 -1
  196. package/src/store/chat/slices/builtinTool/actions/index.ts +1 -6
  197. package/src/store/chat/slices/message/action.test.ts +5 -5
  198. package/src/store/chat/slices/message/actions/publicApi.ts +5 -5
  199. package/src/store/chat/slices/message/initialState.ts +0 -5
  200. package/src/store/chat/slices/message/selectors/displayMessage.test.ts +4 -4
  201. package/src/store/chat/slices/plugin/action.test.ts +54 -19
  202. package/src/store/chat/slices/plugin/actions/pluginTypes.ts +15 -21
  203. package/src/store/chat/slices/topic/action.test.ts +74 -24
  204. package/src/store/chat/slices/topic/action.ts +21 -13
  205. package/src/store/chat/slices/topic/selectors.test.ts +1 -1
  206. package/src/store/global/initialState.ts +10 -0
  207. package/src/store/global/selectors/systemStatus.ts +5 -0
  208. package/src/store/groupProfile/action.ts +168 -0
  209. package/src/store/groupProfile/index.ts +16 -0
  210. package/src/{app/[variants]/(main)/group/profile/features/store → store/groupProfile}/initialState.ts +17 -0
  211. package/src/store/groupProfile/selectors.ts +13 -0
  212. package/src/store/tool/slices/builtin/executors/index.ts +4 -0
  213. package/src/styles/text.ts +16 -0
  214. package/src/tools/inspectors.ts +13 -0
  215. package/src/tools/renders.ts +3 -0
  216. package/src/tools/streamings.ts +8 -0
  217. package/tests/mocks/lru_map.ts +40 -0
  218. package/vitest.config.mts +9 -1
  219. package/src/app/[variants]/(main)/group/profile/features/EditorCanvas/TypoBar.tsx +0 -129
  220. package/src/app/[variants]/(main)/group/profile/features/EditorCanvas/index.tsx +0 -138
  221. package/src/app/[variants]/(main)/group/profile/features/EditorCanvas/useSlashItems.tsx +0 -139
  222. package/src/app/[variants]/(main)/group/profile/features/ProfileEditor/index.tsx +0 -82
  223. package/src/app/[variants]/(main)/group/profile/features/ProfileProvider.tsx +0 -20
  224. package/src/app/[variants]/(main)/group/profile/features/StoreUpdater.tsx +0 -24
  225. package/src/app/[variants]/(main)/group/profile/features/store/action.ts +0 -163
  226. package/src/app/[variants]/(main)/group/profile/features/store/index.ts +0 -23
  227. package/src/app/[variants]/(main)/group/profile/features/store/selectors.ts +0 -7
  228. package/src/features/EditorModal/EditorCanvas.tsx +0 -84
  229. package/src/features/EditorModal/Typobar.tsx +0 -139
  230. package/src/store/chat/slices/builtinTool/actions/agentBuilder.ts +0 -192
  231. package/src/store/chat/slices/builtinTool/actions/groupAgentBuilder.ts +0 -242
  232. package/src/tools/executionRuntimes.ts +0 -14
  233. /package/src/app/[variants]/(main)/group/profile/features/{ProfileEditor → MemberProfile}/AgentTool.tsx +0 -0
  234. /package/src/app/[variants]/(main)/group/profile/features/{ProfileEditor → MemberProfile}/MentionList/MentionDropdown.tsx +0 -0
  235. /package/src/app/[variants]/(main)/group/profile/features/{ProfileEditor → MemberProfile}/MentionList/index.tsx +0 -0
  236. /package/src/app/[variants]/(main)/group/profile/features/{ProfileEditor → MemberProfile}/MentionList/types.ts +0 -0
  237. /package/src/app/[variants]/(main)/group/profile/features/{ProfileEditor → MemberProfile}/MentionList/useMentionItems.tsx +0 -0
@@ -1,15 +1,73 @@
1
- import { memo } from 'react';
1
+ 'use client';
2
2
 
3
- import { useRegisterFilesHotkeys, useSaveDocumentHotkey } from '@/hooks/useHotkeys';
3
+ import { useEditor, useEditorState } from '@lobehub/editor/react';
4
+ import { useUnmount } from 'ahooks';
5
+ import { memo, useEffect, useRef } from 'react';
6
+ import { createStoreUpdater } from 'zustand-utils';
4
7
 
5
- import { useProfileStore } from './store';
8
+ import { useRegisterFilesHotkeys, useSaveDocumentHotkey } from '@/hooks/useHotkeys';
9
+ import { parseAsString, useQueryState } from '@/hooks/useQueryParam';
10
+ import { useChatStore } from '@/store/chat';
11
+ import { useGroupProfileStore } from '@/store/groupProfile';
6
12
 
7
13
  const ProfileHydration = memo(() => {
8
- // Initialize agent builder builtin agent
9
- const flushSave = useProfileStore((s) => s.flushSave);
14
+ const editor = useEditor();
15
+ const editorState = useEditorState(editor);
16
+ const flushSave = useGroupProfileStore((s) => s.flushSave);
17
+
18
+ const storeUpdater = createStoreUpdater(useGroupProfileStore);
19
+
20
+ // Sync editor to store
21
+ storeUpdater('editor', editor);
22
+ // Sync editorState to store
23
+ storeUpdater('editorState', editorState);
24
+ // Sync tab query param to store
25
+ const [activeTabId] = useQueryState('tab', parseAsString.withDefault('group'));
26
+ storeUpdater('activeTabId', activeTabId);
27
+
28
+ // Bidirectional sync between URL query 'bt' and chatStore.activeTopicId
29
+ const [builderTopicId, setBuilderTopicId] = useQueryState('bt');
30
+ const activeTopicId = useChatStore((s) => s.activeTopicId);
31
+
32
+ // Track if the change came from URL to prevent sync loops
33
+ const isUrlChangeRef = useRef(false);
34
+
35
+ // Sync URL → Store (when URL changes)
36
+ useEffect(() => {
37
+ const urlTopicId = builderTopicId ?? undefined;
38
+ if (urlTopicId !== activeTopicId) {
39
+ isUrlChangeRef.current = true;
40
+ useChatStore.setState({ activeTopicId: urlTopicId });
41
+ }
42
+ }, [builderTopicId]);
43
+
44
+ // Sync Store → URL (when store changes, but not from URL)
45
+ useEffect(() => {
46
+ if (isUrlChangeRef.current) {
47
+ isUrlChangeRef.current = false;
48
+ return;
49
+ }
50
+ const urlTopicId = builderTopicId ?? undefined;
51
+ if (activeTopicId !== urlTopicId) {
52
+ setBuilderTopicId(activeTopicId ?? null);
53
+ }
54
+ }, [activeTopicId]);
55
+
56
+ // Register hotkeys
10
57
  useRegisterFilesHotkeys();
11
58
  useSaveDocumentHotkey(flushSave);
12
59
 
60
+ // Clear state when unmounting
61
+ useUnmount(() => {
62
+ useGroupProfileStore.setState({
63
+ activeTabId: 'group',
64
+ editor: undefined,
65
+ editorState: undefined,
66
+ saveStateMap: {},
67
+ });
68
+ useChatStore.setState({ activeTopicId: undefined });
69
+ });
70
+
13
71
  return null;
14
72
  });
15
73
 
@@ -7,58 +7,55 @@ import Loading from '@/components/Loading/BrandTextLoading';
7
7
  import WideScreenContainer from '@/features/WideScreenContainer';
8
8
  import { useAgentGroupStore } from '@/store/agentGroup';
9
9
  import { agentGroupSelectors } from '@/store/agentGroup/selectors';
10
+ import { useGroupProfileStore } from '@/store/groupProfile';
10
11
 
11
12
  import AgentBuilder from './features/AgentBuilder';
13
+ import GroupProfileSettings from './features/GroupProfile';
12
14
  import Header from './features/Header';
13
- import ProfileEditor from './features/ProfileEditor';
15
+ import MemberProfile from './features/MemberProfile';
14
16
  import ProfileHydration from './features/ProfileHydration';
15
- import ProfileProvider from './features/ProfileProvider';
16
- import { useProfileStore } from './features/store';
17
17
 
18
18
  const ProfileArea = memo(() => {
19
- const editor = useProfileStore((s) => s.editor);
19
+ const editor = useGroupProfileStore((s) => s.editor);
20
+ const activeTabId = useGroupProfileStore((s) => s.activeTabId);
20
21
  const isGroupsLoading = useAgentGroupStore(agentGroupSelectors.isGroupsInit);
21
22
 
23
+ const isGroupTab = activeTabId === 'group';
24
+
22
25
  return (
23
- <>
24
- <Flexbox flex={1} height={'100%'}>
25
- {isGroupsLoading ? (
26
- <Loading debugId="ProfileArea" />
27
- ) : (
28
- <>
29
- <Header />
30
- <Flexbox
31
- height={'100%'}
32
- horizontal
33
- onClick={() => {
34
- editor?.focus();
35
- }}
36
- style={{ cursor: 'text', display: 'flex', overflowY: 'auto', position: 'relative' }}
37
- width={'100%'}
38
- >
39
- <WideScreenContainer>
40
- <ProfileEditor />
41
- </WideScreenContainer>
42
- </Flexbox>
43
- </>
44
- )}
45
- </Flexbox>
46
- <Suspense fallback={null}>
47
- <ProfileHydration />
48
- </Suspense>
49
- </>
26
+ <Flexbox flex={1} height={'100%'} style={{ minWidth: 0, overflow: 'hidden' }}>
27
+ {isGroupsLoading ? (
28
+ <Loading debugId="ProfileArea" />
29
+ ) : (
30
+ <>
31
+ <Header />
32
+ <Flexbox
33
+ height={'100%'}
34
+ horizontal
35
+ onClick={() => {
36
+ editor?.focus();
37
+ }}
38
+ style={{ cursor: 'text', display: 'flex', overflowY: 'auto', position: 'relative' }}
39
+ width={'100%'}
40
+ >
41
+ <WideScreenContainer>
42
+ {isGroupTab ? <GroupProfileSettings /> : <MemberProfile />}
43
+ </WideScreenContainer>
44
+ </Flexbox>
45
+ </>
46
+ )}
47
+ </Flexbox>
50
48
  );
51
49
  });
52
50
 
53
51
  const GroupProfile: FC = () => {
54
52
  return (
55
53
  <Suspense fallback={<Loading debugId="GroupProfile" />}>
56
- <ProfileProvider>
57
- <Flexbox height={'100%'} horizontal width={'100%'}>
58
- <ProfileArea />
59
- <AgentBuilder />
60
- </Flexbox>
61
- </ProfileProvider>
54
+ <ProfileHydration />
55
+ <Flexbox height={'100%'} horizontal width={'100%'}>
56
+ <ProfileArea />
57
+ <AgentBuilder />
58
+ </Flexbox>
62
59
  </Suspense>
63
60
  );
64
61
  };
@@ -1,12 +1,13 @@
1
1
  'use client';
2
2
 
3
3
  import { type NetworkProxySettings } from '@lobechat/electron-client-ipc';
4
- import { Alert, Block, Flexbox, Skeleton, Text , Button } from '@lobehub/ui';
5
- import { App, Divider, Form, Input, Radio, Space, Switch } from 'antd';
6
- import isEqual from 'fast-deep-equal';
4
+ import { Alert, Flexbox, Form, type FormGroupItemType, Icon, Skeleton } from '@lobehub/ui';
5
+ import { Form as AntdForm, Button, Input, Radio, Space, Switch } from 'antd';
6
+ import { Loader2Icon } from 'lucide-react';
7
7
  import { useCallback, useEffect, useState } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
9
9
 
10
+ import { FORM_STYLE } from '@/const/layoutTokens';
10
11
  import { desktopSettingsService } from '@/services/electron/settings';
11
12
  import { useElectronStore } from '@/store/electron';
12
13
 
@@ -19,15 +20,15 @@ interface ProxyTestResult {
19
20
  const ProxyForm = () => {
20
21
  const { t } = useTranslation('electron');
21
22
  const [form] = Form.useForm();
22
- const { message } = App.useApp();
23
23
  const [testUrl, setTestUrl] = useState('https://www.google.com');
24
24
  const [isTesting, setIsTesting] = useState(false);
25
25
  const [isSaving, setIsSaving] = useState(false);
26
26
  const [testResult, setTestResult] = useState<ProxyTestResult | null>(null);
27
27
  const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
28
+ const [loading, setLoading] = useState(false);
28
29
 
29
- const isEnableProxy = Form.useWatch('enableProxy', form);
30
- const proxyRequireAuth = Form.useWatch('proxyRequireAuth', form);
30
+ const isEnableProxy = AntdForm.useWatch('enableProxy', form);
31
+ const proxyRequireAuth = AntdForm.useWatch('proxyRequireAuth', form);
31
32
 
32
33
  const [setProxySettings, useGetProxySettings] = useElectronStore((s) => [
33
34
  s.setProxySettings,
@@ -44,19 +45,12 @@ const ProxyForm = () => {
44
45
 
45
46
  // 监听表单变化
46
47
  const handleValuesChange = useCallback(() => {
48
+ setLoading(true);
47
49
  setHasUnsavedChanges(true);
48
50
  setTestResult(null); // 清除之前的测试结果
51
+ setLoading(false);
49
52
  }, []);
50
53
 
51
- const updateFormValue = (value: any) => {
52
- const preValues = form.getFieldsValue();
53
- form.setFieldsValue(value);
54
- const newValues = form.getFieldsValue();
55
- if (isEqual(newValues, preValues)) return;
56
-
57
- handleValuesChange();
58
- };
59
-
60
54
  // 保存配置
61
55
  const handleSave = useCallback(async () => {
62
56
  try {
@@ -64,15 +58,12 @@ const ProxyForm = () => {
64
58
  const values = await form.validateFields();
65
59
  await setProxySettings(values);
66
60
  setHasUnsavedChanges(false);
67
- message.success(t('proxy.saveSuccess'));
68
- } catch (error) {
69
- if (error instanceof Error) {
70
- message.error(t('proxy.saveFailed', { error: error.message }));
71
- }
61
+ } catch {
62
+ // validation error
72
63
  } finally {
73
64
  setIsSaving(false);
74
65
  }
75
- }, [form, t, message]);
66
+ }, [form, setProxySettings]);
76
67
 
77
68
  // 重置配置
78
69
  const handleReset = useCallback(() => {
@@ -107,240 +98,159 @@ const ProxyForm = () => {
107
98
  success: false,
108
99
  };
109
100
  setTestResult(result);
110
- message.error(t('proxy.testFailed'));
111
101
  } finally {
112
102
  setIsTesting(false);
113
103
  }
114
- }, [proxySettings, testUrl]);
104
+ }, [proxySettings, testUrl, form]);
115
105
 
116
- if (isLoading) return <Skeleton />;
106
+ if (isLoading) return <Skeleton active paragraph={{ rows: 5 }} title={false} />;
117
107
 
118
- return (
119
- <Form
120
- disabled={isSaving}
121
- form={form}
122
- layout="vertical"
123
- onValuesChange={handleValuesChange}
124
- requiredMark={false}
125
- >
126
- <Flexbox gap={24}>
127
- {/* 基本代理设置 */}
128
- <Block
129
- paddingBlock={16}
130
- paddingInline={24}
131
- style={{ borderRadius: 12 }}
132
- variant={'outlined'}
133
- >
134
- <Form.Item name="enableProxy" noStyle valuePropName="checked">
135
- <Flexbox align={'center'} horizontal justify={'space-between'}>
136
- <Flexbox>
137
- <Text as={'h4'}>{t('proxy.enable')}</Text>
138
- <Text type={'secondary'}>{t('proxy.enableDesc')}</Text>
139
- </Flexbox>
140
- <Switch
141
- checked={isEnableProxy}
142
- onChange={(checked) => {
143
- updateFormValue({ enableProxy: checked });
144
- }}
145
- />
146
- </Flexbox>
147
- </Form.Item>
148
- </Block>
108
+ const enableProxyGroup: FormGroupItemType = {
109
+ children: [
110
+ {
111
+ children: <Switch />,
112
+ desc: t('proxy.enableDesc'),
113
+ label: t('proxy.enable'),
114
+ layout: 'horizontal',
115
+ minWidth: undefined,
116
+ name: 'enableProxy',
117
+ valuePropName: 'checked',
118
+ },
119
+ ],
120
+ extra: loading && <Icon icon={Loader2Icon} size={16} spin style={{ opacity: 0.5 }} />,
121
+ title: t('proxy.enable'),
122
+ };
149
123
 
150
- {/* 认证设置 */}
151
- <Block
152
- paddingBlock={16}
153
- paddingInline={24}
154
- style={{ borderRadius: 12 }}
155
- variant={'outlined'}
156
- >
157
- <Flexbox gap={24}>
158
- <Flexbox>
159
- <Text as={'h4'}>{t('proxy.basicSettings')}</Text>
160
- <Text type={'secondary'}>{t('proxy.basicSettingsDesc')}</Text>
161
- </Flexbox>
162
- <Flexbox>
163
- <Form.Item
164
- dependencies={['enableProxy']}
165
- label={t('proxy.type')}
166
- name="proxyType"
167
- rules={[
168
- ({ getFieldValue }) => ({
169
- message: t('proxy.validation.typeRequired'),
170
- required: getFieldValue('enableProxy'),
171
- }),
172
- ]}
173
- >
174
- <Radio.Group disabled={!form.getFieldValue('enableProxy')}>
175
- <Radio value="http">HTTP</Radio>
176
- <Radio value="https">HTTPS</Radio>
177
- <Radio value="socks5">SOCKS5</Radio>
178
- </Radio.Group>
179
- </Form.Item>
124
+ const basicSettingsGroup: FormGroupItemType = {
125
+ children: [
126
+ {
127
+ children: (
128
+ <Radio.Group disabled={!isEnableProxy}>
129
+ <Radio value="http">HTTP</Radio>
130
+ <Radio value="https">HTTPS</Radio>
131
+ <Radio value="socks5">SOCKS5</Radio>
132
+ </Radio.Group>
133
+ ),
134
+ label: t('proxy.type'),
135
+ minWidth: undefined,
136
+ name: 'proxyType',
137
+ },
138
+ {
139
+ children: <Input disabled={!isEnableProxy} placeholder="127.0.0.1" />,
140
+ desc: t('proxy.validation.serverRequired'),
141
+ label: t('proxy.server'),
142
+ name: 'proxyServer',
143
+ },
144
+ {
145
+ children: <Input disabled={!isEnableProxy} placeholder="7890" style={{ width: 120 }} />,
146
+ desc: t('proxy.validation.portRequired'),
147
+ label: t('proxy.port'),
148
+ name: 'proxyPort',
149
+ },
150
+ ],
151
+ extra: loading && <Icon icon={Loader2Icon} size={16} spin style={{ opacity: 0.5 }} />,
152
+ title: t('proxy.basicSettings'),
153
+ };
180
154
 
181
- <Space.Compact style={{ width: '100%' }}>
182
- <Form.Item
183
- dependencies={['enableProxy']}
184
- label={t('proxy.server')}
185
- name="proxyServer"
186
- rules={[
187
- ({ getFieldValue }) => ({
188
- message: t('proxy.validation.serverRequired'),
189
- required: getFieldValue('enableProxy'),
190
- }),
191
- {
192
- message: t('proxy.validation.serverInvalid'),
193
- pattern:
194
- /^((25[0-5]|2[0-4]\d|[01]?\d{1,2})\.){3}(25[0-5]|2[0-4]\d|[01]?\d{1,2})$|^[\dA-Za-z]([\dA-Za-z-]*[\dA-Za-z])?(\.[\dA-Za-z]([\dA-Za-z-]*[\dA-Za-z])?)*$/,
195
- },
196
- ]}
197
- style={{ flex: 1, marginBottom: 0 }}
198
- >
199
- <Input disabled={!form.getFieldValue('enableProxy')} placeholder="127.0.0.1" />
200
- </Form.Item>
155
+ const authGroup: FormGroupItemType = {
156
+ children: [
157
+ {
158
+ children: <Switch disabled={!isEnableProxy} />,
159
+ desc: t('proxy.authDesc'),
160
+ label: t('proxy.auth'),
161
+ layout: 'horizontal',
162
+ minWidth: undefined,
163
+ name: 'proxyRequireAuth',
164
+ valuePropName: 'checked',
165
+ },
166
+ ...(proxyRequireAuth && isEnableProxy
167
+ ? [
168
+ {
169
+ children: <Input placeholder={t('proxy.username_placeholder')} />,
170
+ label: t('proxy.username'),
171
+ name: 'proxyUsername',
172
+ },
173
+ {
174
+ children: <Input.Password placeholder={t('proxy.password_placeholder')} />,
175
+ label: t('proxy.password'),
176
+ name: 'proxyPassword',
177
+ },
178
+ ]
179
+ : []),
180
+ ],
181
+ extra: loading && <Icon icon={Loader2Icon} size={16} spin style={{ opacity: 0.5 }} />,
182
+ title: t('proxy.authSettings'),
183
+ };
201
184
 
202
- <Form.Item
203
- dependencies={['enableProxy']}
204
- label={t('proxy.port')}
205
- name="proxyPort"
206
- rules={[
207
- ({ getFieldValue }) => ({
208
- message: t('proxy.validation.portRequired'),
209
- required: getFieldValue('enableProxy'),
210
- }),
211
- {
212
- message: t('proxy.validation.portInvalid'),
213
- pattern:
214
- /^([1-9]\d{0,3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/,
215
- },
216
- ]}
217
- style={{ marginBottom: 0, width: 120 }}
218
- >
219
- <Input disabled={!form.getFieldValue('enableProxy')} placeholder="7890" />
220
- </Form.Item>
221
- </Space.Compact>
222
- </Flexbox>
223
- <Divider size={'small'} />
224
- <Flexbox gap={12}>
225
- <Form.Item
226
- dependencies={['enableProxy']}
227
- name="proxyRequireAuth"
228
- noStyle
229
- valuePropName="checked"
230
- >
231
- <Flexbox align={'center'} horizontal justify={'space-between'}>
232
- <Flexbox>
233
- <Text as={'h5'}>{t('proxy.auth')}</Text>
234
- <Text type={'secondary'}>{t('proxy.authDesc')}</Text>
185
+ const testGroup: FormGroupItemType = {
186
+ children: [
187
+ {
188
+ children: (
189
+ <Flexbox gap={8}>
190
+ <Space.Compact style={{ width: '100%' }}>
191
+ <Input
192
+ onChange={(e) => setTestUrl(e.target.value)}
193
+ placeholder={t('proxy.testUrlPlaceholder')}
194
+ style={{ flex: 1 }}
195
+ value={testUrl}
196
+ />
197
+ <Button loading={isTesting} onClick={handleTest} type="default">
198
+ {t('proxy.testButton')}
199
+ </Button>
200
+ </Space.Compact>
201
+ {/* 测试结果显示 */}
202
+ {!testResult ? null : testResult.success ? (
203
+ <Alert
204
+ closable
205
+ title={
206
+ <Flexbox align="center" gap={8} horizontal>
207
+ {t('proxy.testSuccessWithTime', { time: testResult.responseTime })}
235
208
  </Flexbox>
236
- <Switch
237
- checked={proxyRequireAuth}
238
- disabled={!isEnableProxy}
239
- onChange={(checked) => {
240
- updateFormValue({ proxyRequireAuth: checked });
241
- }}
242
- />
243
- </Flexbox>
244
- </Form.Item>
245
-
246
- <Form.Item
247
- dependencies={['proxyRequireAuth', 'enableProxy']}
248
- label={t('proxy.username')}
249
- name="proxyUsername"
250
- rules={[
251
- ({ getFieldValue }) => ({
252
- message: t('proxy.validation.usernameRequired'),
253
- required: getFieldValue('proxyRequireAuth') && getFieldValue('enableProxy'),
254
- }),
255
- ]}
256
- style={{
257
- display:
258
- form.getFieldValue('proxyRequireAuth') && form.getFieldValue('enableProxy')
259
- ? 'block'
260
- : 'none',
261
- }}
262
- >
263
- <Input placeholder={t('proxy.username_placeholder')} />
264
- </Form.Item>
265
-
266
- <Form.Item
267
- dependencies={['proxyRequireAuth', 'enableProxy']}
268
- label={t('proxy.password')}
269
- name="proxyPassword"
270
- rules={[
271
- ({ getFieldValue }) => ({
272
- message: t('proxy.validation.passwordRequired'),
273
- required: getFieldValue('proxyRequireAuth') && getFieldValue('enableProxy'),
274
- }),
275
- ]}
276
- style={{
277
- display:
278
- form.getFieldValue('proxyRequireAuth') && form.getFieldValue('enableProxy')
279
- ? 'block'
280
- : 'none',
281
- }}
282
- >
283
- <Input.Password placeholder={t('proxy.password_placeholder')} />
284
- </Form.Item>
285
- </Flexbox>
209
+ }
210
+ type={'success'}
211
+ />
212
+ ) : (
213
+ <Alert
214
+ closable
215
+ title={
216
+ <Flexbox align="center" gap={8} horizontal>
217
+ {t('proxy.testFailed')}: {testResult.message}
218
+ </Flexbox>
219
+ }
220
+ type={'error'}
221
+ variant={'outlined'}
222
+ />
223
+ )}
286
224
  </Flexbox>
287
- </Block>
288
-
289
- {/* 连接测试 */}
225
+ ),
226
+ desc: t('proxy.testDescription'),
227
+ label: t('proxy.testUrl'),
228
+ minWidth: undefined,
229
+ },
230
+ ],
231
+ extra: loading && <Icon icon={Loader2Icon} size={16} spin style={{ opacity: 0.5 }} />,
232
+ title: t('proxy.connectionTest'),
233
+ };
290
234
 
291
- <Block
292
- paddingBlock={16}
293
- paddingInline={24}
294
- style={{ borderRadius: 12 }}
295
- variant={'outlined'}
296
- >
297
- <Flexbox gap={24}>
298
- <Flexbox>
299
- <Text as={'h4'}>{t('proxy.connectionTest')}</Text>
300
- <Text type={'secondary'}>{t('proxy.testDescription')}</Text>
301
- </Flexbox>
302
- <Form.Item label={t('proxy.testUrl')}>
303
- <Flexbox gap={8}>
304
- <Space.Compact style={{ width: '100%' }}>
305
- <Input
306
- onChange={(e) => setTestUrl(e.target.value)}
307
- placeholder={t('proxy.testUrlPlaceholder')}
308
- style={{ flex: 1 }}
309
- value={testUrl}
310
- />
311
- <Button loading={isTesting} onClick={handleTest} type="default">
312
- {t('proxy.testButton')}
313
- </Button>
314
- </Space.Compact>
315
- {/* 测试结果显示 */}
316
- {!testResult ? null : testResult.success ? (
317
- <Alert
318
- closable
319
- title={
320
- <Flexbox align="center" gap={8} horizontal>
321
- {t('proxy.testSuccessWithTime', { time: testResult.responseTime })}
322
- </Flexbox>
323
- }
324
- type={'success'}
325
- />
326
- ) : (
327
- <Alert
328
- closable
329
- title={
330
- <Flexbox align="center" gap={8} horizontal>
331
- {t('proxy.testFailed')}: {testResult.message}
332
- </Flexbox>
333
- }
334
- type={'error'}
335
- variant={'outlined'}
336
- />
337
- )}
338
- </Flexbox>
339
- </Form.Item>
340
- </Flexbox>
341
- </Block>
342
- {/* 操作按钮 */}
343
- <Space>
235
+ return (
236
+ <Flexbox gap={24}>
237
+ <Form
238
+ collapsible={false}
239
+ form={form}
240
+ initialValues={proxySettings}
241
+ items={[enableProxyGroup, basicSettingsGroup, authGroup, testGroup]}
242
+ itemsType={'group'}
243
+ onValuesChange={handleValuesChange}
244
+ variant={'filled'}
245
+ {...FORM_STYLE}
246
+ />
247
+ <Flexbox align="end" justify="flex-end">
248
+ {hasUnsavedChanges && (
249
+ <span style={{ color: 'var(--ant-color-warning)', marginBottom: 8 }}>
250
+ {t('proxy.unsavedChanges')}
251
+ </span>
252
+ )}
253
+ <Flexbox gap={8} horizontal>
344
254
  <Button
345
255
  disabled={!hasUnsavedChanges}
346
256
  loading={isSaving}
@@ -349,19 +259,12 @@ const ProxyForm = () => {
349
259
  >
350
260
  {t('proxy.saveButton')}
351
261
  </Button>
352
-
353
262
  <Button disabled={!hasUnsavedChanges || isSaving} onClick={handleReset}>
354
263
  {t('proxy.resetButton')}
355
264
  </Button>
356
-
357
- {hasUnsavedChanges && (
358
- <Text style={{ marginLeft: 8 }} type="warning">
359
- {t('proxy.unsavedChanges')}
360
- </Text>
361
- )}
362
- </Space>
265
+ </Flexbox>
363
266
  </Flexbox>
364
- </Form>
267
+ </Flexbox>
365
268
  );
366
269
  };
367
270