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

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 (227) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/changelog/v1.json +9 -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 +1 -1
  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)/group/_layout/GroupIdSync.tsx +6 -1
  138. package/src/app/[variants]/(main)/group/_layout/Sidebar/GroupConfig/AgentProfilePopup.tsx +29 -21
  139. package/src/app/[variants]/(main)/group/_layout/Sidebar/GroupConfig/GroupMember.tsx +1 -0
  140. package/src/app/[variants]/(main)/group/_layout/Sidebar/GroupConfig/GroupMemberItem.tsx +35 -18
  141. package/src/app/[variants]/(main)/group/_layout/Sidebar/Header/AddTopicButon.tsx +2 -10
  142. package/src/app/[variants]/(main)/group/_layout/Sidebar/Header/Nav.tsx +10 -2
  143. package/src/app/[variants]/(main)/group/_layout/Sidebar/Header/index.tsx +1 -2
  144. package/src/app/[variants]/(main)/group/profile/features/AgentBuilder/AgentBuilderProvider.tsx +1 -0
  145. package/src/app/[variants]/(main)/group/profile/features/AgentBuilder/TopicSelector.tsx +15 -9
  146. package/src/app/[variants]/(main)/group/profile/features/AgentBuilder/index.tsx +12 -6
  147. package/src/app/[variants]/(main)/group/profile/features/{ProfileEditor/AgentHeader.tsx → GroupProfile/GroupHeader.tsx} +22 -29
  148. package/src/app/[variants]/(main)/group/profile/features/GroupProfile/index.tsx +96 -0
  149. package/src/app/[variants]/(main)/group/profile/features/Header/AgentBuilderToggle.tsx +3 -4
  150. package/src/app/[variants]/(main)/group/profile/features/Header/AutoSaveHint.tsx +11 -7
  151. package/src/app/[variants]/(main)/group/profile/features/Header/ChromeTabs/index.tsx +147 -0
  152. package/src/app/[variants]/(main)/group/profile/features/Header/index.tsx +104 -13
  153. package/src/app/[variants]/(main)/group/profile/features/MemberProfile/AgentHeader.tsx +222 -0
  154. package/src/app/[variants]/(main)/group/profile/features/MemberProfile/index.tsx +155 -0
  155. package/src/app/[variants]/(main)/group/profile/features/ProfileHydration.tsx +63 -5
  156. package/src/app/[variants]/(main)/group/profile/index.tsx +34 -37
  157. package/src/app/[variants]/(mobile)/(home)/_layout/SessionHydration.tsx +1 -1
  158. package/src/app/[variants]/(mobile)/(home)/features/SessionListContent/List/Item/index.tsx +1 -1
  159. package/src/features/AgentBuilder/index.tsx +16 -1
  160. package/src/features/Conversation/Messages/AssistantGroup/Tool/Inspector/StatusIndicator.tsx +3 -2
  161. package/src/features/EditorCanvas/EditorCanvas.test.tsx +206 -0
  162. package/src/features/EditorCanvas/EditorDataMode.tsx +53 -19
  163. package/src/features/EditorModal/index.tsx +2 -2
  164. package/src/features/NavPanel/components/SessionHydration.tsx +1 -1
  165. package/src/features/ShareModal/ShareImage/ChatList/index.tsx +1 -1
  166. package/src/features/ShareModal/SharePdf/index.tsx +1 -1
  167. package/src/hooks/useBidirectionalQuerySync.ts +112 -0
  168. package/src/locales/default/chat.ts +10 -0
  169. package/src/locales/default/plugin.ts +22 -1
  170. package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +45 -45
  171. package/src/server/modules/KeyVaultsEncrypt/index.ts +6 -6
  172. package/src/server/modules/S3/index.ts +1 -1
  173. package/src/server/routers/lambda/agent.ts +24 -0
  174. package/src/server/routers/lambda/agentGroup.ts +39 -0
  175. package/src/services/agent.ts +22 -0
  176. package/src/services/chatGroup/index.ts +14 -0
  177. package/src/store/agent/selectors/selectors.ts +3 -0
  178. package/src/store/agentGroup/initialState.ts +6 -0
  179. package/src/store/agentGroup/selectors/byId.ts +3 -1
  180. package/src/store/agentGroup/selectors/current.ts +2 -2
  181. package/src/store/agentGroup/slices/lifecycle.ts +18 -0
  182. package/src/store/chat/agents/__tests__/createAgentExecutors/fixtures/mockStore.ts +1 -1
  183. package/src/store/chat/slices/aiAgent/actions/__tests__/agentGroup.test.ts +4 -1
  184. package/src/store/chat/slices/aiAgent/actions/agentGroup.ts +1 -1
  185. package/src/store/chat/slices/aiChat/actions/__tests__/conversationLifecycle.test.ts +65 -0
  186. package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +2 -1
  187. package/src/store/chat/slices/builtinTool/actions/__tests__/search.test.ts +1 -1
  188. package/src/store/chat/slices/builtinTool/actions/index.ts +1 -6
  189. package/src/store/chat/slices/message/action.test.ts +5 -5
  190. package/src/store/chat/slices/message/actions/publicApi.ts +5 -5
  191. package/src/store/chat/slices/message/initialState.ts +0 -5
  192. package/src/store/chat/slices/message/selectors/displayMessage.test.ts +4 -4
  193. package/src/store/chat/slices/plugin/action.test.ts +54 -19
  194. package/src/store/chat/slices/plugin/actions/pluginTypes.ts +15 -21
  195. package/src/store/chat/slices/topic/action.test.ts +74 -24
  196. package/src/store/chat/slices/topic/action.ts +21 -13
  197. package/src/store/chat/slices/topic/selectors.test.ts +1 -1
  198. package/src/store/global/initialState.ts +10 -0
  199. package/src/store/global/selectors/systemStatus.ts +5 -0
  200. package/src/store/groupProfile/action.ts +168 -0
  201. package/src/store/groupProfile/index.ts +16 -0
  202. package/src/{app/[variants]/(main)/group/profile/features/store → store/groupProfile}/initialState.ts +17 -0
  203. package/src/store/groupProfile/selectors.ts +13 -0
  204. package/src/store/tool/slices/builtin/executors/index.ts +4 -0
  205. package/src/styles/text.ts +16 -0
  206. package/src/tools/inspectors.ts +13 -0
  207. package/src/tools/renders.ts +3 -0
  208. package/src/tools/streamings.ts +8 -0
  209. package/src/app/[variants]/(main)/group/profile/features/EditorCanvas/TypoBar.tsx +0 -129
  210. package/src/app/[variants]/(main)/group/profile/features/EditorCanvas/index.tsx +0 -138
  211. package/src/app/[variants]/(main)/group/profile/features/EditorCanvas/useSlashItems.tsx +0 -139
  212. package/src/app/[variants]/(main)/group/profile/features/ProfileEditor/index.tsx +0 -82
  213. package/src/app/[variants]/(main)/group/profile/features/ProfileProvider.tsx +0 -20
  214. package/src/app/[variants]/(main)/group/profile/features/StoreUpdater.tsx +0 -24
  215. package/src/app/[variants]/(main)/group/profile/features/store/action.ts +0 -163
  216. package/src/app/[variants]/(main)/group/profile/features/store/index.ts +0 -23
  217. package/src/app/[variants]/(main)/group/profile/features/store/selectors.ts +0 -7
  218. package/src/features/EditorModal/EditorCanvas.tsx +0 -84
  219. package/src/features/EditorModal/Typobar.tsx +0 -139
  220. package/src/store/chat/slices/builtinTool/actions/agentBuilder.ts +0 -192
  221. package/src/store/chat/slices/builtinTool/actions/groupAgentBuilder.ts +0 -242
  222. package/src/tools/executionRuntimes.ts +0 -14
  223. /package/src/app/[variants]/(main)/group/profile/features/{ProfileEditor → MemberProfile}/AgentTool.tsx +0 -0
  224. /package/src/app/[variants]/(main)/group/profile/features/{ProfileEditor → MemberProfile}/MentionList/MentionDropdown.tsx +0 -0
  225. /package/src/app/[variants]/(main)/group/profile/features/{ProfileEditor → MemberProfile}/MentionList/index.tsx +0 -0
  226. /package/src/app/[variants]/(main)/group/profile/features/{ProfileEditor → MemberProfile}/MentionList/types.ts +0 -0
  227. /package/src/app/[variants]/(main)/group/profile/features/{ProfileEditor → MemberProfile}/MentionList/useMentionItems.tsx +0 -0
@@ -0,0 +1,112 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useRef } from 'react';
4
+
5
+ import { parseAsString, useQueryState } from '@/hooks/useQueryParam';
6
+
7
+ interface UseBidirectionalQuerySyncOptions {
8
+ /**
9
+ * Default value when query is not present
10
+ */
11
+ defaultValue: string;
12
+ }
13
+
14
+ /**
15
+ * Hook for bidirectional sync between URL query parameter and store state.
16
+ * Prevents infinite loops by tracking the source of changes.
17
+ *
18
+ * @param queryKey - The URL query parameter key
19
+ * @param storeValue - Current value from the store
20
+ * @param setStoreValue - Function to update store value (setState or action)
21
+ * @param options - Configuration with required defaultValue
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * // In a component
26
+ * const activeTabId = useGroupProfileStore((s) => s.activeTabId);
27
+ *
28
+ * useBidirectionalQuerySync('tab', activeTabId, (value) => {
29
+ * useGroupProfileStore.setState({ activeTabId: value });
30
+ * }, { defaultValue: 'group' });
31
+ * ```
32
+ */
33
+ export const useBidirectionalQuerySync = (
34
+ queryKey: string,
35
+ storeValue: string,
36
+ setStoreValue: (value: string) => void,
37
+ options: UseBidirectionalQuerySyncOptions,
38
+ ) => {
39
+ const { defaultValue } = options;
40
+
41
+ const [queryValue, setQueryValue] = useQueryState(
42
+ queryKey,
43
+ parseAsString.withDefault(defaultValue),
44
+ );
45
+
46
+ // Track if the change came from URL to prevent sync loops
47
+ const isUrlChangeRef = useRef(false);
48
+
49
+ // Sync URL → Store (when URL changes)
50
+ useEffect(() => {
51
+ if (queryValue !== storeValue) {
52
+ isUrlChangeRef.current = true;
53
+ setStoreValue(queryValue);
54
+ }
55
+ }, [queryValue, setStoreValue]);
56
+
57
+ // Sync Store → URL (when store changes, but not from URL)
58
+ useEffect(() => {
59
+ if (isUrlChangeRef.current) {
60
+ isUrlChangeRef.current = false;
61
+ return;
62
+ }
63
+ if (storeValue !== queryValue) {
64
+ setQueryValue(storeValue);
65
+ }
66
+ }, [storeValue, queryValue, setQueryValue]);
67
+ };
68
+
69
+ /**
70
+ * Hook for bidirectional sync with optional/undefined store values.
71
+ * Useful when the store value can be undefined (like activeTopicId).
72
+ *
73
+ * @example
74
+ * ```tsx
75
+ * const activeTopicId = useChatStore((s) => s.activeTopicId);
76
+ *
77
+ * useBidirectionalQuerySyncOptional('bt', activeTopicId, (value) => {
78
+ * useChatStore.setState({ activeTopicId: value });
79
+ * });
80
+ * ```
81
+ */
82
+ export const useBidirectionalQuerySyncOptional = (
83
+ queryKey: string,
84
+ storeValue: string | undefined,
85
+ setStoreValue: (value: string | undefined) => void,
86
+ ) => {
87
+ const [queryValue, setQueryValue] = useQueryState(queryKey);
88
+
89
+ // Track if the change came from URL to prevent sync loops
90
+ const isUrlChangeRef = useRef(false);
91
+
92
+ // Sync URL → Store (when URL changes)
93
+ useEffect(() => {
94
+ const urlValue = queryValue ?? undefined;
95
+ if (urlValue !== storeValue) {
96
+ isUrlChangeRef.current = true;
97
+ setStoreValue(urlValue);
98
+ }
99
+ }, [queryValue, setStoreValue]);
100
+
101
+ // Sync Store → URL (when store changes, but not from URL)
102
+ useEffect(() => {
103
+ if (isUrlChangeRef.current) {
104
+ isUrlChangeRef.current = false;
105
+ return;
106
+ }
107
+ const urlValue = queryValue ?? undefined;
108
+ if (storeValue !== urlValue) {
109
+ setQueryValue(storeValue ?? null);
110
+ }
111
+ }, [storeValue, queryValue, setQueryValue]);
112
+ };
@@ -87,11 +87,21 @@ export default {
87
87
  'group.desc': 'Move a task forward with multiple Agents in one shared space.',
88
88
  'group.memberTooltip': 'There are {{count}} members in the group',
89
89
  'group.orchestratorThinking': 'Orchestrator is thinking...',
90
+ 'group.profile.contentPlaceholder':
91
+ 'Set the group objectives/work modes here. This information will be shared with all group members.',
92
+ 'group.profile.external': 'External',
93
+ 'group.profile.externalAgentWarning':
94
+ 'This is an external agent. Changes made here will directly modify the original agent configuration.',
95
+ 'group.profile.groupSettings': 'Group Settings',
96
+ 'group.profile.supervisor': 'Supervisor',
97
+ 'group.profile.supervisorPlaceholder':
98
+ 'The supervisor coordinates different agents. Setting supervisor information here enables more precise workflow coordination.',
90
99
  'group.removeMember': 'Remove Member',
91
100
  'group.title': 'Group',
92
101
  'groupDescription': 'Group description',
93
102
  'groupSidebar.agentProfile.chat': 'Chat',
94
103
  'groupSidebar.agentProfile.model': 'Model',
104
+ 'groupSidebar.agentProfile.settings': 'Settings',
95
105
  'groupSidebar.members.addMember': 'Add Member',
96
106
  'groupSidebar.members.enableOrchestrator': 'Enable Orchestrator',
97
107
  'groupSidebar.members.memberSettings': 'Member Settings',
@@ -5,6 +5,7 @@ export default {
5
5
  'builtins.lobe-agent-builder.apiName.getConfig': 'Get config',
6
6
  'builtins.lobe-agent-builder.apiName.getMeta': 'Get metadata',
7
7
  'builtins.lobe-agent-builder.apiName.getPrompt': 'Get system prompt',
8
+ 'builtins.lobe-agent-builder.apiName.installPlugin': 'Install Skill',
8
9
  'builtins.lobe-agent-builder.apiName.searchMarketTools': 'Search Skill market',
9
10
  'builtins.lobe-agent-builder.apiName.searchOfficialTools': 'Search official Skills',
10
11
  'builtins.lobe-agent-builder.apiName.setModel': 'Set model',
@@ -15,6 +16,12 @@ export default {
15
16
  'builtins.lobe-agent-builder.apiName.updateConfig': 'Update config',
16
17
  'builtins.lobe-agent-builder.apiName.updateMeta': 'Update metadata',
17
18
  'builtins.lobe-agent-builder.apiName.updatePrompt': 'Update system prompt',
19
+ 'builtins.lobe-agent-builder.inspector.chars': ' chars',
20
+ 'builtins.lobe-agent-builder.inspector.disablePlugin': 'Disable',
21
+ 'builtins.lobe-agent-builder.inspector.enablePlugin': 'Enable',
22
+ 'builtins.lobe-agent-builder.inspector.modelsCount': '{{count}} models',
23
+ 'builtins.lobe-agent-builder.inspector.noResults': 'No results',
24
+ 'builtins.lobe-agent-builder.inspector.togglePlugin': 'Toggle',
18
25
  'builtins.lobe-agent-builder.title': 'Agent Builder Expert',
19
26
  'builtins.lobe-cloud-sandbox.apiName.editLocalFile': 'Edit file',
20
27
  'builtins.lobe-cloud-sandbox.apiName.executeCode': 'Execute code',
@@ -31,13 +38,27 @@ export default {
31
38
  'builtins.lobe-cloud-sandbox.apiName.searchLocalFiles': 'Search files',
32
39
  'builtins.lobe-cloud-sandbox.apiName.writeLocalFile': 'Write file',
33
40
  'builtins.lobe-cloud-sandbox.title': 'Cloud Sandbox',
41
+ 'builtins.lobe-group-agent-builder.apiName.batchCreateAgents': 'Batch create agents',
42
+ 'builtins.lobe-group-agent-builder.apiName.createAgent': 'Create agent',
34
43
  'builtins.lobe-group-agent-builder.apiName.getAvailableModels': 'Get available models',
35
44
  'builtins.lobe-group-agent-builder.apiName.installPlugin': 'Install Skill',
36
45
  'builtins.lobe-group-agent-builder.apiName.inviteAgent': 'Invite member',
37
46
  'builtins.lobe-group-agent-builder.apiName.removeAgent': 'Remove member',
47
+ 'builtins.lobe-group-agent-builder.apiName.searchAgent': 'Search agents',
38
48
  'builtins.lobe-group-agent-builder.apiName.searchMarketTools': 'Search Skill market',
39
49
  'builtins.lobe-group-agent-builder.apiName.updateAgentConfig': 'Update agent config',
40
- 'builtins.lobe-group-agent-builder.apiName.updatePrompt': 'Update system prompt',
50
+ 'builtins.lobe-group-agent-builder.apiName.updateAgentPrompt': 'Update agent prompt',
51
+ 'builtins.lobe-group-agent-builder.apiName.updateGroup': 'Update group',
52
+ 'builtins.lobe-group-agent-builder.apiName.updateGroupPrompt': 'Update group prompt',
53
+ 'builtins.lobe-group-agent-builder.apiName.updateSupervisorPrompt': 'Update supervisor prompt',
54
+ 'builtins.lobe-group-agent-builder.inspector.agents': 'agents',
55
+ 'builtins.lobe-group-agent-builder.inspector.avatar': 'Avatar',
56
+ 'builtins.lobe-group-agent-builder.inspector.backgroundColor': 'Background color',
57
+ 'builtins.lobe-group-agent-builder.inspector.description': 'Description',
58
+ 'builtins.lobe-group-agent-builder.inspector.noResults': 'No results',
59
+ 'builtins.lobe-group-agent-builder.inspector.openingMessage': 'Opening message',
60
+ 'builtins.lobe-group-agent-builder.inspector.openingQuestions': 'Opening questions',
61
+ 'builtins.lobe-group-agent-builder.inspector.title': 'Title',
41
62
  'builtins.lobe-group-agent-builder.title': 'Group Builder Expert',
42
63
  'builtins.lobe-group-management.apiName.broadcast': 'All speak',
43
64
  'builtins.lobe-group-management.apiName.createAgent': 'Add group member',
@@ -60,7 +60,7 @@ export const createRuntimeExecutors = (
60
60
  throw new Error('Model and provider are required for call_llm instruction');
61
61
  }
62
62
 
63
- // 类型断言确保 payload 的正确性
63
+ // Type assertion to ensure payload correctness
64
64
  const operationLogId = `${operationId}:${stepIndex}`;
65
65
 
66
66
  const stagePrefix = `[${operationLogId}][call_llm]`;
@@ -94,7 +94,7 @@ export const createRuntimeExecutors = (
94
94
  log(`${stagePrefix} Created new assistant message: %s`, assistantMessageItem.id);
95
95
  }
96
96
 
97
- // 发布流式开始事件
97
+ // Publish stream start event
98
98
  await streamManager.publishStreamEvent(operationId, {
99
99
  data: {
100
100
  assistantMessage: assistantMessageItem,
@@ -121,10 +121,10 @@ export const createRuntimeExecutors = (
121
121
  let hasContentImages = false;
122
122
  let hasReasoningImages = false;
123
123
 
124
- // 初始化 ModelRuntime (从数据库读取用户的 keyVaults)
124
+ // Initialize ModelRuntime (read user's keyVaults from database)
125
125
  const modelRuntime = await initModelRuntimeFromDB(ctx.serverDB, ctx.userId!, provider);
126
126
 
127
- // 构造 ChatStreamPayload
127
+ // Construct ChatStreamPayload
128
128
  const chatPayload = {
129
129
  messages: llmPayload.messages,
130
130
  model,
@@ -138,7 +138,7 @@ export const createRuntimeExecutors = (
138
138
  llmPayload.tools?.length ?? 0,
139
139
  );
140
140
 
141
- // Buffer:累积 text reasoning,每 50ms 发送一次
141
+ // Buffer: accumulate text and reasoning, send every 50ms
142
142
  const BUFFER_INTERVAL = 50;
143
143
  let textBuffer = '';
144
144
  let reasoningBuffer = '';
@@ -154,7 +154,7 @@ export const createRuntimeExecutors = (
154
154
  if (!!delta) {
155
155
  log(`[${operationLogId}] flushTextBuffer:`, delta);
156
156
 
157
- // 构建标准 Agent Runtime 事件
157
+ // Build standard Agent Runtime event
158
158
  events.push({
159
159
  chunk: { text: delta, type: 'text' },
160
160
  type: 'llm_stream',
@@ -203,11 +203,11 @@ export const createRuntimeExecutors = (
203
203
  }
204
204
  };
205
205
 
206
- // 调用 model-runtime chat
206
+ // Call model-runtime chat
207
207
  const response = await modelRuntime.chat(chatPayload, {
208
208
  callback: {
209
209
  onCompletion: async (data) => {
210
- // 捕获 usage (可能包含 cost,也可能不包含)
210
+ // Capture usage (may or may not include cost)
211
211
  if (data.usage) {
212
212
  currentStepUsage = data.usage;
213
213
  }
@@ -232,7 +232,7 @@ export const createRuntimeExecutors = (
232
232
 
233
233
  textBuffer += text;
234
234
 
235
- // 如果没有定时器,创建一个
235
+ // If no timer exists, create one
236
236
  if (!textBufferTimer) {
237
237
  textBufferTimer = setTimeout(async () => {
238
238
  await flushTextBuffer();
@@ -249,10 +249,10 @@ export const createRuntimeExecutors = (
249
249
  );
250
250
  thinkingContent += reasoning;
251
251
 
252
- // Buffer reasoning 内容
252
+ // Buffer reasoning content
253
253
  reasoningBuffer += reasoning;
254
254
 
255
- // 如果没有定时器,创建一个
255
+ // If no timer exists, create one
256
256
  if (!reasoningBufferTimer) {
257
257
  reasoningBufferTimer = setTimeout(async () => {
258
258
  await flushReasoningBuffer();
@@ -266,7 +266,7 @@ export const createRuntimeExecutors = (
266
266
  toolsCalling = payload;
267
267
  tool_calls = raw;
268
268
 
269
- // 如果有 textBuffer,先推一次
269
+ // If textBuffer exists, flush it first
270
270
  if (!!textBuffer) {
271
271
  await flushTextBuffer();
272
272
  }
@@ -280,13 +280,13 @@ export const createRuntimeExecutors = (
280
280
  user: ctx.userId,
281
281
  });
282
282
 
283
- // 消费流确保所有回调执行完成
283
+ // Consume stream to ensure all callbacks complete execution
284
284
  await consumeStreamUntilDone(response);
285
285
 
286
286
  await flushTextBuffer();
287
287
  await flushReasoningBuffer();
288
288
 
289
- // 清理定时器并 flush 剩余 buffer
289
+ // Clean up timers and flush remaining buffers
290
290
  if (textBufferTimer) {
291
291
  clearTimeout(textBufferTimer);
292
292
  textBufferTimer = null;
@@ -309,18 +309,18 @@ export const createRuntimeExecutors = (
309
309
  log(`[${operationLogId}][toolsCalling] `, toolsCalling);
310
310
  }
311
311
 
312
- // 日志输出 usage
312
+ // Log usage information
313
313
  if (currentStepUsage) {
314
314
  log(`[${operationLogId}][usage] %O`, currentStepUsage);
315
315
  }
316
316
 
317
- // 添加一个完整的 llm_stream 事件(包含所有流式块)
317
+ // Add a complete llm_stream event (including all streaming chunks)
318
318
  events.push({
319
319
  result: { content, reasoning: thinkingContent, tool_calls, usage: currentStepUsage },
320
320
  type: 'llm_result',
321
321
  });
322
322
 
323
- // 发布流式结束事件
323
+ // Publish stream end event
324
324
  await streamManager.publishStreamEvent(operationId, {
325
325
  data: {
326
326
  finalContent: content,
@@ -336,7 +336,7 @@ export const createRuntimeExecutors = (
336
336
 
337
337
  log('[%s:%d] call_llm completed', operationId, stepIndex);
338
338
 
339
- // ===== 1. 先保存原始 usage message.metadata =====
339
+ // ===== 1. First save original usage to message.metadata =====
340
340
  // Determine final content - use serialized parts if has images, otherwise plain text
341
341
  const finalContent = hasContentImages ? serializePartsForStorage(contentParts) : content;
342
342
 
@@ -377,7 +377,7 @@ export const createRuntimeExecutors = (
377
377
  console.error('[call_llm] Failed to update message:', error);
378
378
  }
379
379
 
380
- // ===== 2. 然后累加到 AgentState =====
380
+ // ===== 2. Then accumulate to AgentState =====
381
381
  let newState = structuredClone(state);
382
382
 
383
383
  newState.messages.push({
@@ -387,7 +387,7 @@ export const createRuntimeExecutors = (
387
387
  });
388
388
 
389
389
  if (currentStepUsage) {
390
- // 使用 UsageCounter 统一累加 usage cost
390
+ // Use UsageCounter to uniformly accumulate usage and cost
391
391
  const { usage, cost } = UsageCounter.accumulateLLM({
392
392
  cost: newState.cost,
393
393
  model: llmPayload.model,
@@ -423,7 +423,7 @@ export const createRuntimeExecutors = (
423
423
  },
424
424
  };
425
425
  } catch (error) {
426
- // 发布错误事件
426
+ // Publish error event
427
427
  await streamManager.publishStreamEvent(operationId, {
428
428
  data: {
429
429
  error: (error as Error).message,
@@ -441,7 +441,7 @@ export const createRuntimeExecutors = (
441
441
  }
442
442
  },
443
443
  /**
444
- * 工具执行
444
+ * Tool execution
445
445
  */
446
446
  call_tool: async (instruction, state) => {
447
447
  const { payload } = instruction as Extract<AgentInstruction, { type: 'call_tool' }>;
@@ -451,7 +451,7 @@ export const createRuntimeExecutors = (
451
451
  const operationLogId = `${operationId}:${stepIndex}`;
452
452
  log(`[${operationLogId}] payload: %O`, payload);
453
453
 
454
- // 发布工具执行开始事件
454
+ // Publish tool execution start event
455
455
  await streamManager.publishStreamEvent(operationId, {
456
456
  data: payload,
457
457
  stepIndex,
@@ -477,7 +477,7 @@ export const createRuntimeExecutors = (
477
477
  executionResult,
478
478
  );
479
479
 
480
- // 发布工具执行结果事件
480
+ // Publish tool execution result event
481
481
  await streamManager.publishStreamEvent(operationId, {
482
482
  data: {
483
483
  executionTime,
@@ -490,7 +490,7 @@ export const createRuntimeExecutors = (
490
490
  type: 'tool_end',
491
491
  });
492
492
 
493
- // 最终更新数据库
493
+ // Finally update database
494
494
  let toolMessageId: string | undefined;
495
495
  try {
496
496
  const toolMessage = await ctx.messageModel.create({
@@ -520,10 +520,10 @@ export const createRuntimeExecutors = (
520
520
 
521
521
  events.push({ id: chatToolPayload.id, result: executionResult, type: 'tool_result' });
522
522
 
523
- // 获取工具单价
523
+ // Get tool unit price
524
524
  const toolCost = TOOL_PRICING[toolName] || 0;
525
525
 
526
- // 使用 UsageCounter 统一累加 tool usage
526
+ // Use UsageCounter to uniformly accumulate tool usage
527
527
  const { usage, cost } = UsageCounter.accumulateTool({
528
528
  cost: newState.cost,
529
529
  executionTime,
@@ -536,10 +536,10 @@ export const createRuntimeExecutors = (
536
536
  newState.usage = usage;
537
537
  if (cost) newState.cost = cost;
538
538
 
539
- // 查找当前工具的统计信息
539
+ // Find current tool statistics
540
540
  const currentToolStats = usage.tools.byTool.find((t) => t.name === toolName);
541
541
 
542
- // 日志输出 usage
542
+ // Log usage information
543
543
  log(
544
544
  `[${operationLogId}][tool usage] %s: calls=%d, time=%dms, success=%s, cost=$%s`,
545
545
  toolName,
@@ -581,7 +581,7 @@ export const createRuntimeExecutors = (
581
581
  },
582
582
  };
583
583
  } catch (error) {
584
- // 发布工具执行错误事件
584
+ // Publish tool execution error event
585
585
  await streamManager.publishStreamEvent(operationId, {
586
586
  data: {
587
587
  error: (error as Error).message,
@@ -603,12 +603,12 @@ export const createRuntimeExecutors = (
603
603
 
604
604
  return {
605
605
  events,
606
- newState: state, // 状态不变
606
+ newState: state, // State unchanged
607
607
  };
608
608
  }
609
609
  },
610
610
  /**
611
- * 完成 runtime 运行
611
+ * Complete runtime execution
612
612
  */
613
613
  finish: async (instruction, state) => {
614
614
  const { reason, reasonDetail } = instruction as Extract<AgentInstruction, { type: 'finish' }>;
@@ -616,7 +616,7 @@ export const createRuntimeExecutors = (
616
616
 
617
617
  log('[%s:%d] Finishing execution: (%s)', operationId, stepIndex, reason);
618
618
 
619
- // 发布执行完成事件
619
+ // Publish execution complete event
620
620
  await streamManager.publishStreamEvent(operationId, {
621
621
  data: {
622
622
  finalState: { ...state, status: 'done' },
@@ -645,7 +645,7 @@ export const createRuntimeExecutors = (
645
645
  },
646
646
 
647
647
  /**
648
- * 人工审批
648
+ * Human approval
649
649
  */
650
650
  request_human_approve: async (instruction, state) => {
651
651
  const { pendingToolsCalling } = instruction as Extract<
@@ -656,7 +656,7 @@ export const createRuntimeExecutors = (
656
656
 
657
657
  log('[%s:%d] Requesting human approval for %O', operationId, stepIndex, pendingToolsCalling);
658
658
 
659
- // 发布人工审批请求事件
659
+ // Publish human approval request event
660
660
  await streamManager.publishStreamEvent(operationId, {
661
661
  data: {
662
662
  pendingToolsCalling,
@@ -672,9 +672,9 @@ export const createRuntimeExecutors = (
672
672
  newState.status = 'waiting_for_human';
673
673
  newState.pendingToolsCalling = pendingToolsCalling;
674
674
 
675
- // 通过流式系统通知前端显示审批 UI
675
+ // Notify frontend to display approval UI through streaming system
676
676
  await streamManager.publishStreamChunk(operationId, stepIndex, {
677
- // 使用 operationId 作为 messageId
677
+ // Use operationId as messageId
678
678
  chunkType: 'tools_calling',
679
679
  toolsCalling: pendingToolsCalling as any,
680
680
  });
@@ -698,13 +698,13 @@ export const createRuntimeExecutors = (
698
698
  return {
699
699
  events,
700
700
  newState,
701
- // 不提供 nextContext,因为需要等待人工干预
701
+ // Do not provide nextContext as it requires waiting for human intervention
702
702
  };
703
703
  },
704
704
 
705
705
  /**
706
- * 解决被取消的工具调用
707
- * 为取消的工具调用创建带有 'aborted' 干预状态的工具消息
706
+ * Resolve aborted tool calls
707
+ * Create tool messages with 'aborted' intervention status for canceled tool calls
708
708
  */
709
709
  resolve_aborted_tools: async (instruction, state) => {
710
710
  const { payload } = instruction as Extract<AgentInstruction, { type: 'resolve_aborted_tools' }>;
@@ -714,7 +714,7 @@ export const createRuntimeExecutors = (
714
714
 
715
715
  log('[%s:%d] Resolving %d aborted tools', operationId, stepIndex, toolsCalling.length);
716
716
 
717
- // 发布工具取消事件
717
+ // Publish tool cancellation event
718
718
  await streamManager.publishStreamEvent(operationId, {
719
719
  data: {
720
720
  parentMessageId,
@@ -727,7 +727,7 @@ export const createRuntimeExecutors = (
727
727
 
728
728
  const newState = structuredClone(state);
729
729
 
730
- // 为每个取消的工具调用创建 tool message
730
+ // Create tool message for each canceled tool call
731
731
  for (const toolPayload of toolsCalling) {
732
732
  const toolName = `${toolPayload.identifier}/${toolPayload.apiName}`;
733
733
  log('[%s:%d] Creating aborted tool message for %s', operationId, stepIndex, toolName);
@@ -753,7 +753,7 @@ export const createRuntimeExecutors = (
753
753
  toolName,
754
754
  );
755
755
 
756
- // 更新 state messages
756
+ // Update state messages
757
757
  newState.messages.push({
758
758
  content: 'Tool execution was aborted by user.',
759
759
  role: 'tool',
@@ -770,11 +770,11 @@ export const createRuntimeExecutors = (
770
770
 
771
771
  log('[%s:%d] All aborted tool messages created', operationId, stepIndex);
772
772
 
773
- // 标记状态为完成
773
+ // Mark status as complete
774
774
  newState.lastModified = new Date().toISOString();
775
775
  newState.status = 'done';
776
776
 
777
- // 发布完成事件
777
+ // Publish completion event
778
778
  await streamManager.publishStreamEvent(operationId, {
779
779
  data: {
780
780
  finalState: newState,
@@ -21,7 +21,7 @@ export class KeyVaultsGateKeeper {
21
21
  If you don't have it, please run \`openssl rand -base64 32\` to create one.
22
22
  `);
23
23
 
24
- const rawKey = Buffer.from(KEY_VAULTS_SECRET, 'base64'); // 确保密钥是32字节(256位)
24
+ const rawKey = Buffer.from(KEY_VAULTS_SECRET, 'base64'); // Ensure key is 32 bytes (256 bits)
25
25
  const aesKey = await crypto.subtle.importKey(
26
26
  'raw',
27
27
  rawKey,
@@ -36,7 +36,7 @@ If you don't have it, please run \`openssl rand -base64 32\` to create one.
36
36
  * encrypt user private data
37
37
  */
38
38
  encrypt = async (keyVault: string): Promise<string> => {
39
- const iv = crypto.getRandomValues(new Uint8Array(12)); // 对于GCM,推荐使用12字节的IV
39
+ const iv = crypto.getRandomValues(new Uint8Array(12)); // For GCM, 12-byte IV is recommended
40
40
  const encodedKeyVault = new TextEncoder().encode(keyVault);
41
41
 
42
42
  const encryptedData = await crypto.subtle.encrypt(
@@ -49,13 +49,13 @@ If you don't have it, please run \`openssl rand -base64 32\` to create one.
49
49
  );
50
50
 
51
51
  const buffer = Buffer.from(encryptedData);
52
- const authTag = buffer.slice(-16); // 认证标签在加密数据的最后16字节
53
- const encrypted = buffer.slice(0, -16); // 剩下的是加密数据
52
+ const authTag = buffer.slice(-16); // Authentication tag is in the last 16 bytes of encrypted data
53
+ const encrypted = buffer.slice(0, -16); // The rest is encrypted data
54
54
 
55
55
  return `${Buffer.from(iv).toString('hex')}:${authTag.toString('hex')}:${encrypted.toString('hex')}`;
56
56
  };
57
57
 
58
- // 假设密钥和加密数据是从外部获取的
58
+ // Assuming key and encrypted data are obtained from external sources
59
59
  decrypt = async (encryptedData: string): Promise<DecryptionResult> => {
60
60
  const parts = encryptedData.split(':');
61
61
  if (parts.length !== 3) {
@@ -66,7 +66,7 @@ If you don't have it, please run \`openssl rand -base64 32\` to create one.
66
66
  const authTag = Buffer.from(parts[1], 'hex');
67
67
  const encrypted = Buffer.from(parts[2], 'hex');
68
68
 
69
- // 合并加密数据和认证标签
69
+ // Combine encrypted data and authentication tag
70
70
  const combined = Buffer.concat([encrypted, authTag]);
71
71
 
72
72
  try {
@@ -153,7 +153,7 @@ export class S3 {
153
153
  });
154
154
  }
155
155
 
156
- // 添加一个新方法用于上传二进制内容
156
+ // Add a new method for uploading binary content
157
157
  public async uploadBuffer(path: string, buffer: Buffer, contentType?: string) {
158
158
  const command = new PutObjectCommand({
159
159
  ACL: this.setAcl ? 'public-read' : undefined,
@@ -3,6 +3,7 @@ import { type KnowledgeItem, KnowledgeType } from '@lobechat/types';
3
3
  import { z } from 'zod';
4
4
 
5
5
  import { AgentModel } from '@/database/models/agent';
6
+ import { ChatGroupModel } from '@/database/models/chatGroup';
6
7
  import { FileModel } from '@/database/models/file';
7
8
  import { KnowledgeBaseModel } from '@/database/models/knowledgeBase';
8
9
  import { SessionModel } from '@/database/models/session';
@@ -20,6 +21,7 @@ const agentProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
20
21
  ctx: {
21
22
  agentModel: new AgentModel(ctx.serverDB, ctx.userId),
22
23
  agentService: new AgentService(ctx.serverDB, ctx.userId),
24
+ chatGroupModel: new ChatGroupModel(ctx.serverDB, ctx.userId),
23
25
  fileModel: new FileModel(ctx.serverDB, ctx.userId),
24
26
  knowledgeBaseModel: new KnowledgeBaseModel(ctx.serverDB, ctx.userId),
25
27
  sessionModel: new SessionModel(ctx.serverDB, ctx.userId),
@@ -108,6 +110,28 @@ export const agentRouter = router({
108
110
  );
109
111
  }),
110
112
 
113
+ /**
114
+ * Create an agent without session.
115
+ * Used for Group Agent Builder to create agents for groups.
116
+ * Returns only the agent ID.
117
+ */
118
+ createAgentOnly: agentProcedure
119
+ .input(
120
+ z.object({
121
+ config: z.object({}).passthrough().optional(),
122
+ groupId: z.string(),
123
+ }),
124
+ )
125
+ .mutation(async ({ input, ctx }) => {
126
+ // Create the agent entity only (no session)
127
+ const agent = await ctx.agentModel.create(input.config ?? {});
128
+
129
+ // Add the agent to the group
130
+ await ctx.chatGroupModel.addAgentToGroup(input.groupId, agent.id);
131
+
132
+ return { agentId: agent.id };
133
+ }),
134
+
111
135
  deleteAgentFile: agentProcedure
112
136
  .input(
113
137
  z.object({
@@ -37,6 +37,45 @@ export const agentGroupRouter = router({
37
37
  return ctx.chatGroupModel.addAgentsToGroup(input.groupId, input.agentIds);
38
38
  }),
39
39
 
40
+ /**
41
+ * Batch create virtual agents and add them to an existing group.
42
+ * This is more efficient than calling createAgentOnly multiple times.
43
+ */
44
+ batchCreateAgentsInGroup: agentGroupProcedure
45
+ .input(
46
+ z.object({
47
+ agents: z.array(
48
+ insertAgentSchema
49
+ .omit({
50
+ chatConfig: true,
51
+ openingMessage: true,
52
+ openingQuestions: true,
53
+ tts: true,
54
+ userId: true,
55
+ })
56
+ .partial(),
57
+ ),
58
+ groupId: z.string(),
59
+ }),
60
+ )
61
+ .mutation(async ({ input, ctx }) => {
62
+ // Batch create virtual agents
63
+ const agentConfigs = input.agents.map((agent) => ({
64
+ ...agent,
65
+ plugins: agent.plugins as string[] | undefined,
66
+ tags: agent.tags as string[] | undefined,
67
+ virtual: true,
68
+ }));
69
+
70
+ const createdAgents = await ctx.agentModel.batchCreate(agentConfigs);
71
+ const agentIds = createdAgents.map((agent) => agent.id);
72
+
73
+ // Add all agents to the group
74
+ await ctx.chatGroupModel.addAgentsToGroup(input.groupId, agentIds);
75
+
76
+ return { agentIds, agents: createdAgents };
77
+ }),
78
+
40
79
  /**
41
80
  * Check agents before removal to identify virtual agents that will be permanently deleted.
42
81
  * This allows the frontend to show a confirmation dialog.