@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
@@ -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.
@@ -51,6 +51,15 @@ export interface CreateAgentResult {
51
51
  sessionId: string;
52
52
  }
53
53
 
54
+ export interface CreateAgentOnlyParams {
55
+ config?: PartialDeep<AgentItem>;
56
+ groupId: string;
57
+ }
58
+
59
+ export interface CreateAgentOnlyResult {
60
+ agentId: string;
61
+ }
62
+
54
63
  class AgentService {
55
64
  /**
56
65
  * Check if an agent with the given marketIdentifier already exists
@@ -80,6 +89,19 @@ class AgentService {
80
89
  });
81
90
  };
82
91
 
92
+ /**
93
+ * Create a virtual agent without session.
94
+ * Used for Group Agent Builder to create virtual agents for groups.
95
+ */
96
+ createAgentOnly = async (params: CreateAgentOnlyParams): Promise<CreateAgentOnlyResult> => {
97
+ const normalizedConfig = normalizeMarketAgentModel(params.config);
98
+
99
+ return lambdaClient.agent.createAgentOnly.mutate({
100
+ config: normalizedConfig as any,
101
+ groupId: params.groupId,
102
+ });
103
+ };
104
+
83
105
  createAgentKnowledgeBase = async (
84
106
  agentId: string,
85
107
  knowledgeBaseId: string,
@@ -85,6 +85,20 @@ class ChatGroupService {
85
85
  return lambdaClient.group.addAgentsToGroup.mutate({ agentIds, groupId });
86
86
  };
87
87
 
88
+ /**
89
+ * Batch create virtual agents and add them to an existing group.
90
+ * This is more efficient than calling createAgentOnly multiple times.
91
+ */
92
+ batchCreateAgentsInGroup = (
93
+ groupId: string,
94
+ agents: GroupMemberConfig[],
95
+ ) => {
96
+ return lambdaClient.group.batchCreateAgentsInGroup.mutate({
97
+ agents: agents as Partial<AgentItem>[],
98
+ groupId,
99
+ });
100
+ };
101
+
88
102
  removeAgentsFromGroup = (groupId: string, agentIds: string[]) => {
89
103
  return lambdaClient.group.removeAgentsFromGroup.mutate({ agentIds, groupId });
90
104
  };
@@ -260,6 +260,8 @@ const currentAgentLocalSystemConfig = (s: AgentStoreState): LocalSystemConfig |
260
260
  const currentAgentWorkingDirectory = (s: AgentStoreState): string | undefined =>
261
261
  currentAgentLocalSystemConfig(s)?.workingDirectory;
262
262
 
263
+ const isCurrentAgentExternal = (s: AgentStoreState): boolean => !currentAgentData(s)?.virtual;
264
+
263
265
  export const agentSelectors = {
264
266
  currentAgentAvatar,
265
267
  currentAgentBackgroundColor,
@@ -293,6 +295,7 @@ export const agentSelectors = {
293
295
  inboxAgentModel,
294
296
  isAgentConfigLoading,
295
297
  isAgentModeEnabled,
298
+ isCurrentAgentExternal,
296
299
  openingMessage,
297
300
  openingQuestions,
298
301
  };
@@ -1,13 +1,19 @@
1
1
  import type { AgentGroupDetail } from '@lobechat/types';
2
+ import type { ParsedQuery } from 'query-string';
2
3
 
3
4
  import type { ChatGroupItem } from '@/database/schemas/chatGroup';
4
5
 
6
+ export interface QueryRouter {
7
+ push: (url: string, options?: { query?: ParsedQuery }) => void;
8
+ }
9
+
5
10
  export interface ChatGroupState {
6
11
  activeGroupId?: string;
7
12
  activeThreadAgentId: string;
8
13
  groupMap: Record<string, AgentGroupDetail>;
9
14
  groups: ChatGroupItem[];
10
15
  groupsInit: boolean;
16
+ router?: QueryRouter;
11
17
  showGroupSetting: boolean;
12
18
  /**
13
19
  * Content being streamed for system prompt update (for GroupAgentBuilder)
@@ -19,6 +19,8 @@ const groupConfig = (groupId: string) => (s: ChatGroupStore) => {
19
19
  const groupMeta = (groupId: string) => (s: ChatGroupStore) => {
20
20
  const group = groupById(groupId)(s);
21
21
  return merge(DEFAULT_CHAT_GROUP_META_CONFIG, {
22
+ avatar: group?.avatar || undefined,
23
+ backgroundColor: group?.backgroundColor || undefined,
22
24
  description: group?.description || '',
23
25
  title: group?.title || '',
24
26
  });
@@ -26,7 +28,7 @@ const groupMeta = (groupId: string) => (s: ChatGroupStore) => {
26
28
 
27
29
  const groupAgents =
28
30
  (groupId: string) =>
29
- (s: ChatGroupStore): AgentItem[] => {
31
+ (s: ChatGroupStore): AgentGroupMember[] => {
30
32
  const group = groupById(groupId)(s);
31
33
  return group?.agents || [];
32
34
  };
@@ -3,7 +3,7 @@ import {
3
3
  DEFAULT_CHAT_GROUP_CHAT_CONFIG,
4
4
  DEFAULT_CHAT_GROUP_META_CONFIG,
5
5
  } from '@lobechat/const';
6
- import type { AgentGroupDetail, AgentGroupMember, AgentItem } from '@lobechat/types';
6
+ import type { AgentGroupDetail, AgentGroupMember } from '@lobechat/types';
7
7
 
8
8
  import type { ChatGroupState } from '../initialState';
9
9
  import type { ChatGroupStore } from '../store';
@@ -36,7 +36,7 @@ const currentGroupMeta = (s: ChatGroupStore) => {
36
36
  return groupId ? agentGroupByIdSelectors.groupMeta(groupId)(s) : DEFAULT_CHAT_GROUP_META_CONFIG;
37
37
  };
38
38
 
39
- const currentGroupAgents = (s: ChatGroupStore): AgentItem[] => {
39
+ const currentGroupAgents = (s: ChatGroupStore): AgentGroupMember[] => {
40
40
  const groupId = activeGroupId(s);
41
41
  return groupId ? agentGroupByIdSelectors.groupAgents(groupId)(s) : [];
42
42
  };
@@ -1,8 +1,10 @@
1
1
  import type { NewChatGroup } from '@lobechat/types';
2
+ import urlJoin from 'url-join';
2
3
  import { type StateCreator } from 'zustand/vanilla';
3
4
 
4
5
  import { chatGroupService } from '@/services/chatGroup';
5
6
  import { type ChatGroupStore } from '@/store/agentGroup/store';
7
+ import { useChatStore } from '@/store/chat';
6
8
  import { getSessionStoreState } from '@/store/session';
7
9
 
8
10
  export interface ChatGroupLifecycleAction {
@@ -11,6 +13,11 @@ export interface ChatGroupLifecycleAction {
11
13
  agentIds?: string[],
12
14
  silent?: boolean,
13
15
  ) => Promise<string>;
16
+ /**
17
+ * Switch to a new topic in the group
18
+ * Clears activeTopicId and navigates to group root
19
+ */
20
+ switchToNewTopic: () => void;
14
21
  }
15
22
 
16
23
  export const chatGroupLifecycleSlice: StateCreator<
@@ -48,4 +55,15 @@ export const chatGroupLifecycleSlice: StateCreator<
48
55
 
49
56
  return group.id;
50
57
  },
58
+
59
+ switchToNewTopic: () => {
60
+ const { activeGroupId, router } = get();
61
+ if (!activeGroupId || !router) return;
62
+
63
+ useChatStore.setState({ activeTopicId: undefined });
64
+
65
+ router.push(urlJoin('/group', activeGroupId), {
66
+ query: { bt: null, tab: null, thread: null, topic: null },
67
+ });
68
+ },
51
69
  });
@@ -15,7 +15,7 @@ export const createMockStore = (overrides: Partial<ChatStore> = {}): ChatStore =
15
15
 
16
16
  const store = {
17
17
  // Other store properties (add as needed)
18
- activeId: 'test-session',
18
+ activeAgentId: 'test-session',
19
19
 
20
20
  activeTopicId: 'test-topic',
21
21
 
@@ -556,7 +556,10 @@ describe('agentGroup actions', () => {
556
556
  });
557
557
  });
558
558
 
559
- expect(result.current.switchTopic).toHaveBeenCalledWith(TEST_IDS.TOPIC_ID, true);
559
+ expect(result.current.switchTopic).toHaveBeenCalledWith(TEST_IDS.TOPIC_ID, {
560
+ clearNewKey: true,
561
+ skipRefreshMessage: true,
562
+ });
560
563
  });
561
564
 
562
565
  it('should not switch topic when using existing topic', async () => {
@@ -118,7 +118,7 @@ export const agentGroupSlice: StateCreator<
118
118
 
119
119
  // 4. Switch to new topic if created
120
120
  if (result.isCreateNewTopic && result.topicId) {
121
- await get().switchTopic(result.topicId, true);
121
+ await get().switchTopic(result.topicId, { clearNewKey: true, skipRefreshMessage: true });
122
122
  }
123
123
 
124
124
  // 5. Create execContext with updated topicId from server response
@@ -3,6 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
3
 
4
4
  import { aiChatService } from '@/services/aiChat';
5
5
  import * as agentGroupStore from '@/store/agentGroup';
6
+ import { messageMapKey } from '@/store/chat/utils/messageMapKey';
6
7
  import { getSessionStoreState } from '@/store/session';
7
8
 
8
9
  import { useChatStore } from '../../../../store';
@@ -353,5 +354,69 @@ describe('ConversationLifecycle actions', () => {
353
354
  );
354
355
  });
355
356
  });
357
+
358
+ describe('new topic creation cleanup', () => {
359
+ it('should clear _new key data when new topic is created', async () => {
360
+ const { result } = renderHook(() => useChatStore());
361
+ const agentId = TEST_IDS.SESSION_ID;
362
+ const newTopicId = 'created-topic-id';
363
+
364
+ // Setup initial state: messages exist in the _new key (no topicId)
365
+ const newKey = messageMapKey({ agentId, topicId: null });
366
+ const existingMessages = [
367
+ createMockMessage({ id: 'old-msg-1', role: 'user' }),
368
+ createMockMessage({ id: 'old-msg-2', role: 'assistant' }),
369
+ ];
370
+
371
+ await act(async () => {
372
+ useChatStore.setState({
373
+ activeAgentId: agentId,
374
+ activeTopicId: undefined,
375
+ messagesMap: {
376
+ [newKey]: existingMessages,
377
+ },
378
+ dbMessagesMap: {
379
+ [newKey]: existingMessages,
380
+ },
381
+ });
382
+ });
383
+
384
+ // Verify messages exist in _new key before sending
385
+ expect(useChatStore.getState().messagesMap[newKey]).toHaveLength(2);
386
+
387
+ // Mock server response with new topic creation
388
+ vi.spyOn(aiChatService, 'sendMessageInServer').mockResolvedValue({
389
+ messages: [
390
+ createMockMessage({ id: 'new-user-msg', role: 'user', topicId: newTopicId }),
391
+ createMockMessage({ id: 'new-assistant-msg', role: 'assistant', topicId: newTopicId }),
392
+ ],
393
+ topics: { items: [{ id: newTopicId, title: 'New Topic' }], total: 1 },
394
+ topicId: newTopicId,
395
+ isCreateNewTopic: true,
396
+ assistantMessageId: 'new-assistant-msg',
397
+ userMessageId: 'new-user-msg',
398
+ } as any);
399
+
400
+ // Mock switchTopic to verify it's called correctly
401
+ const switchTopicSpy = vi.spyOn(result.current, 'switchTopic');
402
+
403
+ await act(async () => {
404
+ await result.current.sendMessage({
405
+ message: TEST_CONTENT.USER_MESSAGE,
406
+ context: { agentId, topicId: null, threadId: null },
407
+ });
408
+ });
409
+
410
+ // switchTopic should be called with the new topicId and clearNewKey option
411
+ expect(switchTopicSpy).toHaveBeenCalledWith(newTopicId, {
412
+ clearNewKey: true,
413
+ skipRefreshMessage: true,
414
+ });
415
+
416
+ // After new topic creation, the _new key should be cleared
417
+ const messagesInNewKey = useChatStore.getState().messagesMap[newKey];
418
+ expect(messagesInNewKey ?? []).toHaveLength(0);
419
+ });
420
+ });
356
421
  });
357
422
  });
@@ -286,7 +286,8 @@ export const conversationLifecycle: StateCreator<
286
286
  });
287
287
 
288
288
  if (data.isCreateNewTopic && data.topicId) {
289
- await get().switchTopic(data.topicId, true);
289
+ // clearNewKey: true ensures the _new key data is cleared after topic creation
290
+ await get().switchTopic(data.topicId, { clearNewKey: true, skipRefreshMessage: true });
290
291
  }
291
292
  } catch (e) {
292
293
  console.error(e);
@@ -43,7 +43,7 @@ describe('search actions', () => {
43
43
  invokeBuiltinTool: vi.fn(),
44
44
  });
45
45
 
46
- // Default mock for dbMessageSelectors - returns undefined to use activeId/activeTopicId
46
+ // Default mock for dbMessageSelectors - returns undefined to use activeAgentId/activeTopicId
47
47
  vi.spyOn(dbMessageSelectors, 'getDbMessageById').mockImplementation(() => () => undefined);
48
48
  });
49
49
 
@@ -2,13 +2,10 @@ import { type StateCreator } from 'zustand/vanilla';
2
2
 
3
3
  import { type ChatStore } from '@/store/chat/store';
4
4
 
5
- import { type AgentBuilderAction, agentBuilderSlice } from './agentBuilder';
6
- import { type GroupAgentBuilderAction, groupAgentBuilderSlice } from './groupAgentBuilder';
7
5
  import { type ChatCodeInterpreterAction, codeInterpreterSlice } from './interpreter';
8
6
  import { type SearchAction, searchSlice } from './search';
9
7
 
10
- export interface ChatBuiltinToolAction
11
- extends SearchAction, ChatCodeInterpreterAction, AgentBuilderAction, GroupAgentBuilderAction {}
8
+ export interface ChatBuiltinToolAction extends SearchAction, ChatCodeInterpreterAction {}
12
9
 
13
10
  export const chatToolSlice: StateCreator<
14
11
  ChatStore,
@@ -18,6 +15,4 @@ export const chatToolSlice: StateCreator<
18
15
  > = (...params) => ({
19
16
  ...searchSlice(...params),
20
17
  ...codeInterpreterSlice(...params),
21
- ...agentBuilderSlice(...params),
22
- ...groupAgentBuilderSlice(...params),
23
18
  });
@@ -75,7 +75,7 @@ afterEach(() => {
75
75
 
76
76
  describe('chatMessage actions', () => {
77
77
  describe('addAIMessage', () => {
78
- it('should return early if activeId is undefined', async () => {
78
+ it('should return early if activeAgentId is undefined', async () => {
79
79
  useChatStore.setState({ activeAgentId: undefined });
80
80
  const { result } = renderHook(() => useChatStore());
81
81
  const updateMessageInputSpy = vi.spyOn(result.current, 'updateMessageInput');
@@ -117,7 +117,7 @@ describe('chatMessage actions', () => {
117
117
  });
118
118
 
119
119
  describe('addUserMessage', () => {
120
- it('should return early if activeId is undefined', async () => {
120
+ it('should return early if activeAgentId is undefined', async () => {
121
121
  useChatStore.setState({ activeAgentId: undefined });
122
122
  const { result } = renderHook(() => useChatStore());
123
123
  const updateMessageInputSpy = vi.spyOn(result.current, 'updateMessageInput');
@@ -739,7 +739,7 @@ describe('chatMessage actions', () => {
739
739
  useChatStore.setState({ refreshMessages: realRefreshMessages });
740
740
 
741
741
  const { result } = renderHook(() => useChatStore());
742
- const activeId = useChatStore.getState().activeAgentId;
742
+ const activeAgentId = useChatStore.getState().activeAgentId;
743
743
  const activeTopicId = useChatStore.getState().activeTopicId;
744
744
 
745
745
  // 在这里,我们不需要再次模拟 mutate,因为它已经在顶部被模拟了
@@ -750,13 +750,13 @@ describe('chatMessage actions', () => {
750
750
  // 确保 mutate 调用了正确的参数(session 和 group 两次)
751
751
  expect(mutate).toHaveBeenCalledWith([
752
752
  'SWR_USE_FETCH_MESSAGES',
753
- activeId,
753
+ activeAgentId,
754
754
  activeTopicId,
755
755
  'session',
756
756
  ]);
757
757
  expect(mutate).toHaveBeenCalledWith([
758
758
  'SWR_USE_FETCH_MESSAGES',
759
- activeId,
759
+ activeAgentId,
760
760
  activeTopicId,
761
761
  'group',
762
762
  ]);
@@ -235,16 +235,16 @@ export const messagePublicApi: StateCreator<
235
235
  },
236
236
 
237
237
  clearMessage: async () => {
238
- const { activeId, activeTopicId, activeGroupId, refreshTopic, switchTopic } = get();
238
+ const { activeAgentId, activeTopicId, activeGroupId, refreshTopic, switchTopic } = get();
239
239
 
240
240
  // For group sessions, we need to clear group messages using groupId
241
- // For regular sessions, we clear session messages using sessionId
241
+ // For regular sessions, we clear session messages using agentId
242
242
  if (activeGroupId) {
243
243
  // For group chat, activeGroupId is the groupId
244
244
  await messageService.removeMessagesByGroup(activeGroupId, activeTopicId);
245
245
  } else {
246
- // For regular session, activeId is the sessionId
247
- await messageService.removeMessagesByAssistant(activeId, activeTopicId);
246
+ // For regular session, activeAgentId is the agentId
247
+ await messageService.removeMessagesByAssistant(activeAgentId, activeTopicId);
248
248
  }
249
249
 
250
250
  if (activeTopicId) {
@@ -256,7 +256,7 @@ export const messagePublicApi: StateCreator<
256
256
  get().replaceMessages([]);
257
257
 
258
258
  // after remove topic , go back to default topic
259
- switchTopic();
259
+ switchTopic(null);
260
260
  },
261
261
 
262
262
  clearAllMessages: async () => {
@@ -4,10 +4,6 @@ import { type ChatGroupAgentItem } from '@/database/schemas/chatGroup';
4
4
 
5
5
  export interface ChatMessageState {
6
6
  activeAgentId: string;
7
- /**
8
- * @deprecated
9
- */
10
- activeId: string;
11
7
  /**
12
8
  * Raw messages from database (flat structure)
13
9
  */
@@ -37,7 +33,6 @@ export interface ChatMessageState {
37
33
 
38
34
  export const initialMessageState: ChatMessageState = {
39
35
  activeAgentId: '',
40
- activeId: 'inbox',
41
36
  dbMessagesMap: {},
42
37
  groupAgentMaps: {},
43
38
  isCreatingMessage: false,
@@ -288,7 +288,7 @@ describe('displayMessageSelectors', () => {
288
288
  });
289
289
 
290
290
  describe('currentDisplayChatKey', () => {
291
- it('should generate correct key with activeId only', () => {
291
+ it('should generate correct key with activeAgentId only', () => {
292
292
  const state: Partial<ChatStore> = {
293
293
  activeAgentId: 'testId',
294
294
  activeTopicId: undefined,
@@ -297,7 +297,7 @@ describe('displayMessageSelectors', () => {
297
297
  expect(result).toBe(messageMapKey({ agentId: 'testId', topicId: undefined }));
298
298
  });
299
299
 
300
- it('should generate correct key with both activeId and activeTopicId', () => {
300
+ it('should generate correct key with both activeAgentId and activeTopicId', () => {
301
301
  const state: Partial<ChatStore> = {
302
302
  activeAgentId: 'testId',
303
303
  activeTopicId: 'topicId',
@@ -306,7 +306,7 @@ describe('displayMessageSelectors', () => {
306
306
  expect(result).toBe(messageMapKey({ agentId: 'testId', topicId: 'topicId' }));
307
307
  });
308
308
 
309
- it('should generate key with undefined activeId', () => {
309
+ it('should generate key with undefined activeAgentId', () => {
310
310
  const state: Partial<ChatStore> = {
311
311
  activeAgentId: undefined,
312
312
  activeTopicId: 'topicId',
@@ -315,7 +315,7 @@ describe('displayMessageSelectors', () => {
315
315
  expect(result).toBe(messageMapKey({ agentId: undefined as any, topicId: 'topicId' }));
316
316
  });
317
317
 
318
- it('should generate key with empty string activeId', () => {
318
+ it('should generate key with empty string activeAgentId', () => {
319
319
  const state: Partial<ChatStore> = {
320
320
  activeAgentId: '',
321
321
  activeTopicId: undefined,
@@ -381,18 +381,27 @@ describe('ChatPluginAction', () => {
381
381
  });
382
382
 
383
383
  describe('invokeBuiltinTool', () => {
384
- it('should invoke the builtin tool action with parsed arguments', async () => {
384
+ it('should invoke Tool Store executor with parsed arguments', async () => {
385
385
  const payload = {
386
+ identifier: 'test-tool',
386
387
  apiName: 'mockBuiltinAction',
387
388
  arguments: JSON.stringify({ input: 'test', value: 123 }),
388
389
  } as ChatToolPayload;
389
390
 
390
391
  const messageId = 'message-id';
391
- const mockActionFn = vi.fn().mockResolvedValue(undefined);
392
+ const mockInvokeBuiltinTool = vi.fn().mockResolvedValue({
393
+ content: 'result',
394
+ success: true,
395
+ });
392
396
 
393
- useChatStore.setState({
394
- mockBuiltinAction: mockActionFn,
395
- } as any);
397
+ // Mock hasExecutor to return true
398
+ const hasExecutorModule = await import('@/store/tool/slices/builtin/executors');
399
+ vi.spyOn(hasExecutorModule, 'hasExecutor').mockReturnValue(true);
400
+
401
+ // Mock Tool Store's invokeBuiltinTool
402
+ vi.spyOn(useToolStore.getState(), 'invokeBuiltinTool').mockImplementation(
403
+ mockInvokeBuiltinTool,
404
+ );
396
405
 
397
406
  const { result } = renderHook(() => useChatStore());
398
407
 
@@ -400,52 +409,70 @@ describe('ChatPluginAction', () => {
400
409
  await result.current.invokeBuiltinTool(messageId, payload);
401
410
  });
402
411
 
403
- // Verify that the builtin action was called with correct arguments
404
- expect(mockActionFn).toHaveBeenCalledWith(messageId, { input: 'test', value: 123 });
412
+ // Verify that Tool Store's invokeBuiltinTool was called with correct arguments
413
+ expect(mockInvokeBuiltinTool).toHaveBeenCalledWith(
414
+ 'test-tool',
415
+ 'mockBuiltinAction',
416
+ { input: 'test', value: 123 },
417
+ expect.objectContaining({
418
+ messageId,
419
+ }),
420
+ );
405
421
  });
406
422
 
407
- it('should not invoke action if apiName does not exist in store', async () => {
423
+ it('should not throw error if executor does not exist', async () => {
408
424
  const payload = {
425
+ identifier: 'non-existent-tool',
409
426
  apiName: 'nonExistentAction',
410
427
  arguments: JSON.stringify({ key: 'value' }),
411
428
  } as ChatToolPayload;
412
429
 
413
430
  const messageId = 'message-id';
414
431
 
432
+ // Mock hasExecutor to return false
433
+ const hasExecutorModule = await import('@/store/tool/slices/builtin/executors');
434
+ vi.spyOn(hasExecutorModule, 'hasExecutor').mockReturnValue(false);
435
+
436
+ const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
437
+
415
438
  const { result } = renderHook(() => useChatStore());
416
439
 
417
440
  await act(async () => {
418
441
  await result.current.invokeBuiltinTool(messageId, payload);
419
442
  });
420
443
 
421
- // Should not throw error, just return early
444
+ // Should log error but not throw
445
+ expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('No executor found'));
446
+
447
+ consoleErrorSpy.mockRestore();
422
448
  });
423
449
 
424
- it('should not invoke action if arguments cannot be parsed', async () => {
450
+ it('should return error result if arguments cannot be parsed', async () => {
425
451
  const payload = {
452
+ identifier: 'test-tool',
426
453
  apiName: 'mockBuiltinAction',
427
454
  arguments: 'invalid json',
428
455
  } as ChatToolPayload;
429
456
 
430
457
  const messageId = 'message-id';
431
- const mockActionFn = vi.fn().mockResolvedValue(undefined);
432
-
433
- useChatStore.setState({
434
- mockBuiltinAction: mockActionFn,
435
- } as any);
436
458
 
437
459
  const { result } = renderHook(() => useChatStore());
438
460
 
461
+ let returnValue: any;
439
462
  await act(async () => {
440
- await result.current.invokeBuiltinTool(messageId, payload);
463
+ returnValue = await result.current.invokeBuiltinTool(messageId, payload);
441
464
  });
442
465
 
443
- // Should not call the action if arguments can't be parsed
444
- expect(mockActionFn).not.toHaveBeenCalled();
466
+ // Should return error result for invalid JSON
467
+ expect(returnValue).toEqual({ error: 'Invalid arguments', success: false });
445
468
  });
446
469
 
447
470
  describe('registerAfterCompletion with Tool Store executor', () => {
448
471
  it('should create registerAfterCompletion when root execAgentRuntime operation exists', async () => {
472
+ // Mock hasExecutor to return true
473
+ const hasExecutorModule = await import('@/store/tool/slices/builtin/executors');
474
+ vi.spyOn(hasExecutorModule, 'hasExecutor').mockReturnValue(true);
475
+
449
476
  // Setup: Create operation hierarchy
450
477
  // execAgentRuntime -> toolCalling -> executeToolCall
451
478
  const { result } = renderHook(() => useChatStore());
@@ -527,6 +554,10 @@ describe('ChatPluginAction', () => {
527
554
  });
528
555
 
529
556
  it('should not pass registerAfterCompletion when no root operation exists', async () => {
557
+ // Mock hasExecutor to return true
558
+ const hasExecutorModule = await import('@/store/tool/slices/builtin/executors');
559
+ vi.spyOn(hasExecutorModule, 'hasExecutor').mockReturnValue(true);
560
+
530
561
  const { result } = renderHook(() => useChatStore());
531
562
  const messageId = 'tool-message-id';
532
563
 
@@ -558,6 +589,10 @@ describe('ChatPluginAction', () => {
558
589
  });
559
590
 
560
591
  it('should find root operation through multiple levels of hierarchy', async () => {
592
+ // Mock hasExecutor to return true
593
+ const hasExecutorModule = await import('@/store/tool/slices/builtin/executors');
594
+ vi.spyOn(hasExecutorModule, 'hasExecutor').mockReturnValue(true);
595
+
561
596
  const { result } = renderHook(() => useChatStore());
562
597
 
563
598
  let execAgentRuntimeOpId: string;
@@ -1147,7 +1182,7 @@ describe('ChatPluginAction', () => {
1147
1182
  });
1148
1183
  });
1149
1184
 
1150
- it('should fallback to activeId/activeTopicId when context not provided', async () => {
1185
+ it('should fallback to activeAgentId/activeTopicId when context not provided', async () => {
1151
1186
  const { result } = renderHook(() => useChatStore());
1152
1187
  const messageId = 'message-id';
1153
1188
  const pluginState = { key: 'value' };