@lobehub/lobehub 2.0.0-next.306 → 2.0.0-next.308
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.
- package/.vscode/settings.json +18 -3
- package/CHANGELOG.md +61 -0
- package/changelog/v1.json +21 -0
- package/locales/ar/agentGroup.json +5 -0
- package/locales/ar/chat.json +26 -0
- package/locales/ar/models.json +43 -5
- package/locales/ar/plugin.json +4 -5
- package/locales/ar/setting.json +11 -0
- package/locales/ar/subscription.json +2 -0
- package/locales/ar/tool.json +2 -0
- package/locales/bg-BG/agentGroup.json +5 -0
- package/locales/bg-BG/chat.json +26 -0
- package/locales/bg-BG/models.json +49 -3
- package/locales/bg-BG/plugin.json +4 -5
- package/locales/bg-BG/setting.json +11 -0
- package/locales/bg-BG/subscription.json +2 -0
- package/locales/bg-BG/tool.json +2 -0
- package/locales/de-DE/agentGroup.json +5 -0
- package/locales/de-DE/chat.json +26 -0
- package/locales/de-DE/models.json +48 -5
- package/locales/de-DE/plugin.json +4 -5
- package/locales/de-DE/setting.json +11 -0
- package/locales/de-DE/subscription.json +2 -0
- package/locales/de-DE/tool.json +2 -0
- package/locales/en-US/models.json +8 -6
- package/locales/en-US/plugin.json +2 -4
- package/locales/en-US/setting.json +10 -11
- package/locales/en-US/tool.json +2 -0
- package/locales/es-ES/agentGroup.json +5 -0
- package/locales/es-ES/chat.json +26 -0
- package/locales/es-ES/models.json +43 -5
- package/locales/es-ES/plugin.json +4 -5
- package/locales/es-ES/setting.json +11 -0
- package/locales/es-ES/subscription.json +2 -0
- package/locales/es-ES/tool.json +2 -0
- package/locales/fa-IR/agentGroup.json +5 -0
- package/locales/fa-IR/chat.json +26 -0
- package/locales/fa-IR/models.json +42 -5
- package/locales/fa-IR/plugin.json +4 -5
- package/locales/fa-IR/setting.json +11 -0
- package/locales/fa-IR/subscription.json +2 -0
- package/locales/fa-IR/tool.json +2 -0
- package/locales/fr-FR/agentGroup.json +5 -0
- package/locales/fr-FR/chat.json +26 -0
- package/locales/fr-FR/models.json +5 -5
- package/locales/fr-FR/plugin.json +4 -5
- package/locales/fr-FR/setting.json +11 -0
- package/locales/fr-FR/subscription.json +2 -0
- package/locales/fr-FR/tool.json +2 -0
- package/locales/it-IT/agentGroup.json +5 -0
- package/locales/it-IT/chat.json +26 -0
- package/locales/it-IT/models.json +1 -3
- package/locales/it-IT/plugin.json +4 -5
- package/locales/it-IT/setting.json +11 -0
- package/locales/it-IT/subscription.json +2 -0
- package/locales/it-IT/tool.json +2 -0
- package/locales/ja-JP/agentGroup.json +5 -0
- package/locales/ja-JP/chat.json +26 -0
- package/locales/ja-JP/models.json +1 -5
- package/locales/ja-JP/plugin.json +4 -5
- package/locales/ja-JP/setting.json +11 -0
- package/locales/ja-JP/subscription.json +2 -0
- package/locales/ja-JP/tool.json +2 -0
- package/locales/ko-KR/agentGroup.json +5 -0
- package/locales/ko-KR/chat.json +26 -0
- package/locales/ko-KR/models.json +1 -3
- package/locales/ko-KR/plugin.json +4 -5
- package/locales/ko-KR/setting.json +11 -0
- package/locales/ko-KR/subscription.json +2 -0
- package/locales/ko-KR/tool.json +2 -0
- package/locales/nl-NL/agentGroup.json +5 -0
- package/locales/nl-NL/chat.json +26 -0
- package/locales/nl-NL/models.json +35 -3
- package/locales/nl-NL/plugin.json +4 -5
- package/locales/nl-NL/setting.json +11 -0
- package/locales/nl-NL/subscription.json +2 -0
- package/locales/nl-NL/tool.json +2 -0
- package/locales/pl-PL/agentGroup.json +5 -0
- package/locales/pl-PL/chat.json +26 -0
- package/locales/pl-PL/models.json +1 -3
- package/locales/pl-PL/plugin.json +4 -5
- package/locales/pl-PL/setting.json +11 -0
- package/locales/pl-PL/subscription.json +2 -0
- package/locales/pl-PL/tool.json +2 -0
- package/locales/pt-BR/agentGroup.json +5 -0
- package/locales/pt-BR/chat.json +26 -0
- package/locales/pt-BR/models.json +50 -5
- package/locales/pt-BR/plugin.json +4 -5
- package/locales/pt-BR/setting.json +11 -0
- package/locales/pt-BR/subscription.json +2 -0
- package/locales/pt-BR/tool.json +2 -0
- package/locales/ru-RU/agentGroup.json +5 -0
- package/locales/ru-RU/chat.json +26 -0
- package/locales/ru-RU/models.json +22 -3
- package/locales/ru-RU/plugin.json +4 -5
- package/locales/ru-RU/setting.json +11 -0
- package/locales/ru-RU/subscription.json +2 -0
- package/locales/ru-RU/tool.json +2 -0
- package/locales/tr-TR/agentGroup.json +5 -0
- package/locales/tr-TR/chat.json +26 -0
- package/locales/tr-TR/models.json +36 -3
- package/locales/tr-TR/plugin.json +4 -5
- package/locales/tr-TR/setting.json +11 -0
- package/locales/tr-TR/subscription.json +2 -0
- package/locales/tr-TR/tool.json +2 -0
- package/locales/vi-VN/agentGroup.json +5 -0
- package/locales/vi-VN/chat.json +26 -0
- package/locales/vi-VN/models.json +1 -1
- package/locales/vi-VN/plugin.json +4 -5
- package/locales/vi-VN/setting.json +11 -0
- package/locales/vi-VN/subscription.json +2 -0
- package/locales/vi-VN/tool.json +2 -0
- package/locales/zh-CN/models.json +52 -5
- package/locales/zh-CN/plugin.json +5 -7
- package/locales/zh-CN/setting.json +10 -11
- package/locales/zh-CN/tool.json +2 -2
- package/locales/zh-TW/agentGroup.json +5 -0
- package/locales/zh-TW/chat.json +26 -0
- package/locales/zh-TW/models.json +54 -5
- package/locales/zh-TW/plugin.json +4 -5
- package/locales/zh-TW/setting.json +11 -0
- package/locales/zh-TW/subscription.json +2 -0
- package/locales/zh-TW/tool.json +2 -0
- package/package.json +2 -2
- package/packages/builtin-agents/src/agents/group-supervisor/index.ts +1 -7
- package/packages/builtin-tool-group-agent-builder/src/ExecutionRuntime/index.ts +29 -0
- package/packages/builtin-tool-group-agent-builder/src/executor.ts +18 -0
- package/packages/builtin-tool-group-agent-builder/src/manifest.ts +17 -0
- package/packages/builtin-tool-group-agent-builder/src/types.ts +10 -0
- package/packages/builtin-tool-group-management/src/client/Inspector/ExecuteAgentTask/index.tsx +52 -8
- package/packages/builtin-tool-group-management/src/client/Render/ExecuteTask/index.tsx +2 -21
- package/packages/builtin-tool-group-management/src/executor.test.ts +6 -16
- package/packages/builtin-tool-group-management/src/executor.ts +8 -47
- package/packages/builtin-tool-group-management/src/manifest.ts +5 -18
- package/packages/builtin-tool-group-management/src/systemRole.ts +1 -8
- package/packages/builtin-tool-group-management/src/types.ts +2 -10
- package/packages/builtin-tool-local-system/src/ExecutionRuntime/index.ts +70 -31
- package/packages/builtin-tool-local-system/src/client/Render/WriteFile/index.tsx +48 -5
- package/packages/builtin-tool-local-system/src/client/Streaming/WriteFile/index.tsx +39 -0
- package/packages/builtin-tool-local-system/src/client/Streaming/index.ts +2 -0
- package/packages/builtin-tool-local-system/src/executor/index.ts +94 -60
- package/packages/database/src/repositories/agentGroup/index.ts +23 -0
- package/packages/model-bank/src/aiModels/qiniu.ts +24 -0
- package/packages/prompts/src/prompts/fileSystem/formatCommandOutput.test.ts +61 -0
- package/packages/prompts/src/prompts/fileSystem/formatCommandOutput.ts +21 -0
- package/packages/prompts/src/prompts/fileSystem/formatCommandResult.test.ts +87 -0
- package/packages/prompts/src/prompts/fileSystem/formatCommandResult.ts +35 -0
- package/packages/prompts/src/prompts/fileSystem/formatEditResult.test.ts +57 -0
- package/packages/prompts/src/prompts/fileSystem/formatEditResult.ts +17 -0
- package/packages/prompts/src/prompts/fileSystem/formatFileContent.test.ts +59 -0
- package/packages/prompts/src/prompts/fileSystem/formatFileContent.ts +14 -0
- package/packages/prompts/src/prompts/fileSystem/formatFileList.test.ts +62 -0
- package/packages/prompts/src/prompts/fileSystem/formatFileList.ts +13 -0
- package/packages/prompts/src/prompts/fileSystem/formatFileSearchResults.test.ts +34 -0
- package/packages/prompts/src/prompts/fileSystem/formatFileSearchResults.ts +12 -0
- package/packages/prompts/src/prompts/fileSystem/formatGlobResults.test.ts +64 -0
- package/packages/prompts/src/prompts/fileSystem/formatGlobResults.ts +23 -0
- package/packages/prompts/src/prompts/fileSystem/formatGrepResults.test.ts +85 -0
- package/packages/prompts/src/prompts/fileSystem/formatGrepResults.ts +24 -0
- package/packages/prompts/src/prompts/fileSystem/formatKillResult.test.ts +30 -0
- package/packages/prompts/src/prompts/fileSystem/formatKillResult.ts +9 -0
- package/packages/prompts/src/prompts/fileSystem/formatMoveResults.test.ts +37 -0
- package/packages/prompts/src/prompts/fileSystem/formatMoveResults.ts +20 -0
- package/packages/prompts/src/prompts/fileSystem/formatMultipleFiles.test.ts +54 -0
- package/packages/prompts/src/prompts/fileSystem/formatMultipleFiles.ts +9 -0
- package/packages/prompts/src/prompts/fileSystem/formatRenameResult.test.ts +35 -0
- package/packages/prompts/src/prompts/fileSystem/formatRenameResult.ts +17 -0
- package/packages/prompts/src/prompts/fileSystem/formatWriteResult.test.ts +30 -0
- package/packages/prompts/src/prompts/fileSystem/formatWriteResult.ts +11 -0
- package/packages/prompts/src/prompts/fileSystem/index.ts +13 -0
- package/packages/prompts/src/prompts/index.ts +1 -0
- package/src/app/[variants]/(auth)/_layout/index.tsx +0 -2
- package/src/app/[variants]/(auth)/layout.tsx +0 -2
- package/src/app/[variants]/(auth)/login/[[...login]]/page.tsx +1 -3
- package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -3
- package/src/app/[variants]/(desktop)/desktop-onboarding/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/Actions.tsx +4 -3
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/useDropdownMenu.tsx +12 -2
- package/src/app/[variants]/(main)/agent/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/agent/features/Portal/index.tsx +0 -2
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/AddGroupAgent.tsx +69 -17
- package/src/app/[variants]/(main)/community/(list)/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/community/(list)/assistant/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/community/(list)/mcp/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/community/(list)/model/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/community/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/Actions.tsx +4 -3
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/useDropdownMenu.tsx +12 -2
- package/src/app/[variants]/(main)/group/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/group/features/Conversation/Header/index.tsx +4 -2
- package/src/app/[variants]/(main)/group/features/Portal/index.tsx +0 -2
- package/src/app/[variants]/(main)/home/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/home/index.tsx +0 -2
- package/src/app/[variants]/(main)/image/_layout/Topics/TopicUrlSync.tsx +0 -2
- package/src/app/[variants]/(main)/image/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/memory/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/page/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/resource/(home)/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/resource/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/resource/library/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/resource/library/features/Container.tsx +0 -2
- package/src/app/[variants]/(main)/settings/_layout/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/about/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/agent/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/apikey/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/chat-appearance/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/common/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/hotkey/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/image/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/memory/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/provider/(list)/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/proxy/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/security/index.tsx +1 -3
- package/src/app/[variants]/(main)/settings/storage/index.tsx +0 -2
- package/src/app/[variants]/(main)/settings/tts/index.tsx +0 -2
- package/src/app/[variants]/(mobile)/(home)/_layout/index.tsx +0 -2
- package/src/app/[variants]/(mobile)/_layout/index.tsx +1 -3
- package/src/app/[variants]/(mobile)/chat/_layout/index.tsx +0 -2
- package/src/app/[variants]/(mobile)/chat/settings/_layout/index.tsx +0 -2
- package/src/app/[variants]/(mobile)/community/(detail)/_layout/index.tsx +0 -2
- package/src/app/[variants]/(mobile)/community/(list)/_layout/index.tsx +0 -2
- package/src/app/[variants]/(mobile)/community/_layout/index.tsx +0 -2
- package/src/app/[variants]/(mobile)/router/MobileClientRouter.tsx +0 -2
- package/src/app/[variants]/(mobile)/settings/index.tsx +0 -2
- package/src/app/[variants]/onboarding/_layout/index.tsx +0 -2
- package/src/app/[variants]/router/DesktopClientRouter.tsx +0 -2
- package/src/components/ModelSelect/index.tsx +6 -56
- package/src/components/server/MobileNavLayout.tsx +0 -2
- package/src/components/server/ServerLayout.tsx +0 -2
- package/src/features/ChatInput/ActionBar/Upload/ServerMode.tsx +13 -3
- package/src/features/ChatInput/ActionBar/components/ActionDropdown.tsx +26 -3
- package/src/features/ModelSwitchPanel/components/Footer.tsx +0 -2
- package/src/features/ModelSwitchPanel/components/List/MultipleProvidersModelItem.tsx +0 -1
- package/src/features/ModelSwitchPanel/components/List/SingleProviderModelItem.tsx +0 -1
- package/src/features/ModelSwitchPanel/components/List/VirtualItemRenderer.tsx +0 -1
- package/src/features/ModelSwitchPanel/components/List/index.tsx +15 -13
- package/src/features/ModelSwitchPanel/components/PanelContent.tsx +0 -2
- package/src/features/ModelSwitchPanel/index.tsx +21 -23
- package/src/features/ResourceManager/components/Explorer/MasonryView/index.tsx +0 -2
- package/src/features/ResourceManager/components/Header/AddButton.tsx +20 -3
- package/src/features/User/UserAvatar.tsx +0 -2
- package/src/locales/default/plugin.ts +2 -1
- package/src/server/routers/lambda/__tests__/agentGroup.test.ts +1 -0
- package/src/server/routers/lambda/agentGroup.ts +22 -0
- package/src/services/chat/index.ts +1 -0
- package/src/services/chat/mecha/agentConfigResolver.test.ts +62 -45
- package/src/services/chat/mecha/agentConfigResolver.ts +29 -27
- package/src/services/chatGroup/index.ts +14 -0
- package/src/store/chat/agents/GroupOrchestration/__tests__/call-supervisor.test.ts +305 -0
- package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +2 -1
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +6 -2
- package/src/store/chat/slices/plugin/actions/exector.ts +92 -0
- package/src/store/chat/slices/plugin/actions/pluginTypes.ts +82 -177
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import type { AgentState } from '@lobechat/agent-runtime';
|
|
2
|
+
import type { UIChatMessage } from '@lobechat/types';
|
|
3
|
+
import { nanoid } from '@lobechat/utils';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
|
|
6
|
+
import type { ChatStore } from '@/store/chat/store';
|
|
7
|
+
|
|
8
|
+
import { createGroupOrchestrationExecutors } from '../createGroupOrchestrationExecutors';
|
|
9
|
+
|
|
10
|
+
const TEST_IDS = {
|
|
11
|
+
GROUP_ID: 'test-group-id',
|
|
12
|
+
OPERATION_ID: 'test-operation-id',
|
|
13
|
+
ORCHESTRATION_OPERATION_ID: 'test-orchestration-operation-id',
|
|
14
|
+
SUPERVISOR_AGENT_ID: 'test-supervisor-agent-id',
|
|
15
|
+
TOPIC_ID: 'test-topic-id',
|
|
16
|
+
USER_MESSAGE_ID: 'test-user-message-id',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Create a minimal mock store for group orchestration executor tests
|
|
21
|
+
*/
|
|
22
|
+
const createMockStore = (overrides: Partial<ChatStore> = {}): ChatStore => {
|
|
23
|
+
const operations: Record<string, any> = {};
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
dbMessagesMap: {},
|
|
27
|
+
internal_execAgentRuntime: vi.fn().mockResolvedValue(undefined),
|
|
28
|
+
messagesMap: {},
|
|
29
|
+
operations,
|
|
30
|
+
startOperation: vi.fn().mockImplementation((config) => {
|
|
31
|
+
const operationId = `op_${nanoid()}`;
|
|
32
|
+
const abortController = new AbortController();
|
|
33
|
+
operations[operationId] = {
|
|
34
|
+
abortController,
|
|
35
|
+
context: config.context || {},
|
|
36
|
+
id: operationId,
|
|
37
|
+
status: 'running',
|
|
38
|
+
type: config.type,
|
|
39
|
+
};
|
|
40
|
+
return { abortController, operationId };
|
|
41
|
+
}),
|
|
42
|
+
...overrides,
|
|
43
|
+
} as unknown as ChatStore;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Create initial agent state for testing
|
|
48
|
+
*/
|
|
49
|
+
const createInitialState = (overrides: Partial<AgentState> = {}): AgentState => {
|
|
50
|
+
return {
|
|
51
|
+
cost: {
|
|
52
|
+
calculatedAt: new Date().toISOString(),
|
|
53
|
+
currency: 'USD',
|
|
54
|
+
llm: { byModel: [], currency: 'USD', total: 0 },
|
|
55
|
+
tools: { byTool: [], currency: 'USD', total: 0 },
|
|
56
|
+
total: 0,
|
|
57
|
+
},
|
|
58
|
+
createdAt: new Date().toISOString(),
|
|
59
|
+
lastModified: new Date().toISOString(),
|
|
60
|
+
maxSteps: 10,
|
|
61
|
+
messages: [],
|
|
62
|
+
operationId: TEST_IDS.OPERATION_ID,
|
|
63
|
+
status: 'running',
|
|
64
|
+
stepCount: 0,
|
|
65
|
+
toolManifestMap: {},
|
|
66
|
+
usage: {
|
|
67
|
+
humanInteraction: {
|
|
68
|
+
approvalRequests: 0,
|
|
69
|
+
promptRequests: 0,
|
|
70
|
+
selectRequests: 0,
|
|
71
|
+
totalWaitingTimeMs: 0,
|
|
72
|
+
},
|
|
73
|
+
llm: { apiCalls: 0, processingTimeMs: 0, tokens: { input: 0, output: 0, total: 0 } },
|
|
74
|
+
tools: { byTool: [], totalCalls: 0, totalTimeMs: 0 },
|
|
75
|
+
},
|
|
76
|
+
userInterventionConfig: { allowList: [], approvalMode: 'auto' },
|
|
77
|
+
...overrides,
|
|
78
|
+
} as AgentState;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
describe('createGroupOrchestrationExecutors', () => {
|
|
82
|
+
describe('call_supervisor executor', () => {
|
|
83
|
+
it('should NOT pass operationId to internal_execAgentRuntime (creates new child operation)', async () => {
|
|
84
|
+
const mockStore = createMockStore({
|
|
85
|
+
dbMessagesMap: {
|
|
86
|
+
[`group_${TEST_IDS.GROUP_ID}_${TEST_IDS.TOPIC_ID}`]: [
|
|
87
|
+
{
|
|
88
|
+
content: 'Hello',
|
|
89
|
+
createdAt: Date.now(),
|
|
90
|
+
id: TEST_IDS.USER_MESSAGE_ID,
|
|
91
|
+
role: 'user',
|
|
92
|
+
updatedAt: Date.now(),
|
|
93
|
+
} as UIChatMessage,
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const executors = createGroupOrchestrationExecutors({
|
|
99
|
+
get: () => mockStore,
|
|
100
|
+
messageContext: {
|
|
101
|
+
agentId: TEST_IDS.GROUP_ID,
|
|
102
|
+
scope: 'group',
|
|
103
|
+
topicId: TEST_IDS.TOPIC_ID,
|
|
104
|
+
},
|
|
105
|
+
orchestrationOperationId: TEST_IDS.ORCHESTRATION_OPERATION_ID,
|
|
106
|
+
supervisorAgentId: TEST_IDS.SUPERVISOR_AGENT_ID,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const callSupervisorExecutor = executors.call_supervisor!;
|
|
110
|
+
|
|
111
|
+
await callSupervisorExecutor(
|
|
112
|
+
{
|
|
113
|
+
payload: { round: 1, supervisorAgentId: TEST_IDS.SUPERVISOR_AGENT_ID },
|
|
114
|
+
type: 'call_supervisor',
|
|
115
|
+
},
|
|
116
|
+
createInitialState(),
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// Verify internal_execAgentRuntime was called
|
|
120
|
+
expect(mockStore.internal_execAgentRuntime).toHaveBeenCalledTimes(1);
|
|
121
|
+
|
|
122
|
+
// Verify operationId is NOT passed (should be undefined)
|
|
123
|
+
// This ensures a new child operation is created
|
|
124
|
+
const callArgs = (mockStore.internal_execAgentRuntime as any).mock.calls[0][0];
|
|
125
|
+
expect(callArgs.operationId).toBeUndefined();
|
|
126
|
+
|
|
127
|
+
// Verify parentOperationId is passed correctly
|
|
128
|
+
expect(callArgs.parentOperationId).toBe(TEST_IDS.ORCHESTRATION_OPERATION_ID);
|
|
129
|
+
|
|
130
|
+
// Verify isSupervisor is passed in context
|
|
131
|
+
expect(callArgs.context.isSupervisor).toBe(true);
|
|
132
|
+
|
|
133
|
+
// Verify agentId is the supervisor agent id
|
|
134
|
+
expect(callArgs.context.agentId).toBe(TEST_IDS.SUPERVISOR_AGENT_ID);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should pass isSupervisor: true in context for supervisor messages metadata', async () => {
|
|
138
|
+
const mockStore = createMockStore({
|
|
139
|
+
dbMessagesMap: {
|
|
140
|
+
[`group_${TEST_IDS.GROUP_ID}_${TEST_IDS.TOPIC_ID}`]: [
|
|
141
|
+
{
|
|
142
|
+
content: 'Hello',
|
|
143
|
+
createdAt: Date.now(),
|
|
144
|
+
id: TEST_IDS.USER_MESSAGE_ID,
|
|
145
|
+
role: 'user',
|
|
146
|
+
updatedAt: Date.now(),
|
|
147
|
+
} as UIChatMessage,
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const executors = createGroupOrchestrationExecutors({
|
|
153
|
+
get: () => mockStore,
|
|
154
|
+
messageContext: {
|
|
155
|
+
agentId: TEST_IDS.GROUP_ID,
|
|
156
|
+
scope: 'group',
|
|
157
|
+
topicId: TEST_IDS.TOPIC_ID,
|
|
158
|
+
},
|
|
159
|
+
orchestrationOperationId: TEST_IDS.ORCHESTRATION_OPERATION_ID,
|
|
160
|
+
supervisorAgentId: TEST_IDS.SUPERVISOR_AGENT_ID,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const callSupervisorExecutor = executors.call_supervisor!;
|
|
164
|
+
|
|
165
|
+
await callSupervisorExecutor(
|
|
166
|
+
{
|
|
167
|
+
payload: { round: 1, supervisorAgentId: TEST_IDS.SUPERVISOR_AGENT_ID },
|
|
168
|
+
type: 'call_supervisor',
|
|
169
|
+
},
|
|
170
|
+
createInitialState(),
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const callArgs = (mockStore.internal_execAgentRuntime as any).mock.calls[0][0];
|
|
174
|
+
|
|
175
|
+
// The key assertion: isSupervisor must be true
|
|
176
|
+
// This is used by createAgentExecutors to set metadata.isSupervisor on assistant messages
|
|
177
|
+
expect(callArgs.context).toMatchObject({
|
|
178
|
+
agentId: TEST_IDS.SUPERVISOR_AGENT_ID,
|
|
179
|
+
isSupervisor: true,
|
|
180
|
+
scope: 'group',
|
|
181
|
+
topicId: TEST_IDS.TOPIC_ID,
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('call_agent executor', () => {
|
|
187
|
+
it('should NOT pass operationId to internal_execAgentRuntime (creates new child operation)', async () => {
|
|
188
|
+
const mockStore = createMockStore({
|
|
189
|
+
dbMessagesMap: {
|
|
190
|
+
[`group_${TEST_IDS.GROUP_ID}_${TEST_IDS.TOPIC_ID}`]: [
|
|
191
|
+
{
|
|
192
|
+
content: 'Hello',
|
|
193
|
+
createdAt: Date.now(),
|
|
194
|
+
id: TEST_IDS.USER_MESSAGE_ID,
|
|
195
|
+
role: 'user',
|
|
196
|
+
updatedAt: Date.now(),
|
|
197
|
+
} as UIChatMessage,
|
|
198
|
+
],
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const executors = createGroupOrchestrationExecutors({
|
|
203
|
+
get: () => mockStore,
|
|
204
|
+
messageContext: {
|
|
205
|
+
agentId: TEST_IDS.GROUP_ID,
|
|
206
|
+
scope: 'group',
|
|
207
|
+
topicId: TEST_IDS.TOPIC_ID,
|
|
208
|
+
},
|
|
209
|
+
orchestrationOperationId: TEST_IDS.ORCHESTRATION_OPERATION_ID,
|
|
210
|
+
supervisorAgentId: TEST_IDS.SUPERVISOR_AGENT_ID,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
const callAgentExecutor = executors.call_agent!;
|
|
214
|
+
const targetAgentId = 'target-agent-id';
|
|
215
|
+
|
|
216
|
+
await callAgentExecutor(
|
|
217
|
+
{
|
|
218
|
+
payload: { agentId: targetAgentId, instruction: 'Please respond' },
|
|
219
|
+
type: 'call_agent',
|
|
220
|
+
},
|
|
221
|
+
createInitialState(),
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
// Verify internal_execAgentRuntime was called
|
|
225
|
+
expect(mockStore.internal_execAgentRuntime).toHaveBeenCalledTimes(1);
|
|
226
|
+
|
|
227
|
+
// Verify operationId is NOT passed (should be undefined)
|
|
228
|
+
const callArgs = (mockStore.internal_execAgentRuntime as any).mock.calls[0][0];
|
|
229
|
+
expect(callArgs.operationId).toBeUndefined();
|
|
230
|
+
|
|
231
|
+
// Verify parentOperationId is passed correctly
|
|
232
|
+
expect(callArgs.parentOperationId).toBe(TEST_IDS.ORCHESTRATION_OPERATION_ID);
|
|
233
|
+
|
|
234
|
+
// Verify subAgentId is passed (NOT isSupervisor)
|
|
235
|
+
expect(callArgs.context.subAgentId).toBe(targetAgentId);
|
|
236
|
+
expect(callArgs.context.isSupervisor).toBeUndefined();
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
describe('operation structure comparison', () => {
|
|
241
|
+
it('call_supervisor and call_agent should both create independent child operations', async () => {
|
|
242
|
+
const mockStore = createMockStore({
|
|
243
|
+
dbMessagesMap: {
|
|
244
|
+
[`group_${TEST_IDS.GROUP_ID}_${TEST_IDS.TOPIC_ID}`]: [
|
|
245
|
+
{
|
|
246
|
+
content: 'Hello',
|
|
247
|
+
createdAt: Date.now(),
|
|
248
|
+
id: TEST_IDS.USER_MESSAGE_ID,
|
|
249
|
+
role: 'user',
|
|
250
|
+
updatedAt: Date.now(),
|
|
251
|
+
} as UIChatMessage,
|
|
252
|
+
],
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const executors = createGroupOrchestrationExecutors({
|
|
257
|
+
get: () => mockStore,
|
|
258
|
+
messageContext: {
|
|
259
|
+
agentId: TEST_IDS.GROUP_ID,
|
|
260
|
+
scope: 'group',
|
|
261
|
+
topicId: TEST_IDS.TOPIC_ID,
|
|
262
|
+
},
|
|
263
|
+
orchestrationOperationId: TEST_IDS.ORCHESTRATION_OPERATION_ID,
|
|
264
|
+
supervisorAgentId: TEST_IDS.SUPERVISOR_AGENT_ID,
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Execute call_supervisor
|
|
268
|
+
await executors.call_supervisor!(
|
|
269
|
+
{
|
|
270
|
+
payload: { round: 1, supervisorAgentId: TEST_IDS.SUPERVISOR_AGENT_ID },
|
|
271
|
+
type: 'call_supervisor',
|
|
272
|
+
},
|
|
273
|
+
createInitialState(),
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
// Execute call_agent
|
|
277
|
+
await executors.call_agent!(
|
|
278
|
+
{
|
|
279
|
+
payload: { agentId: 'agent-1', instruction: 'test' },
|
|
280
|
+
type: 'call_agent',
|
|
281
|
+
},
|
|
282
|
+
createInitialState(),
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
// Verify both were called
|
|
286
|
+
expect(mockStore.internal_execAgentRuntime).toHaveBeenCalledTimes(2);
|
|
287
|
+
|
|
288
|
+
// Get both call arguments
|
|
289
|
+
const supervisorCallArgs = (mockStore.internal_execAgentRuntime as any).mock.calls[0][0];
|
|
290
|
+
const agentCallArgs = (mockStore.internal_execAgentRuntime as any).mock.calls[1][0];
|
|
291
|
+
|
|
292
|
+
// Both should NOT have operationId (create new child operations)
|
|
293
|
+
expect(supervisorCallArgs.operationId).toBeUndefined();
|
|
294
|
+
expect(agentCallArgs.operationId).toBeUndefined();
|
|
295
|
+
|
|
296
|
+
// Both should have same parentOperationId (orchestration operation)
|
|
297
|
+
expect(supervisorCallArgs.parentOperationId).toBe(TEST_IDS.ORCHESTRATION_OPERATION_ID);
|
|
298
|
+
expect(agentCallArgs.parentOperationId).toBe(TEST_IDS.ORCHESTRATION_OPERATION_ID);
|
|
299
|
+
|
|
300
|
+
// Supervisor should have isSupervisor: true
|
|
301
|
+
expect(supervisorCallArgs.context.isSupervisor).toBe(true);
|
|
302
|
+
expect(agentCallArgs.context.isSupervisor).toBeUndefined();
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
});
|
|
@@ -126,10 +126,11 @@ export const createGroupOrchestrationExecutors = (
|
|
|
126
126
|
|
|
127
127
|
// Execute Supervisor agent with the supervisor's agentId in context
|
|
128
128
|
// Mark isSupervisor=true so assistant messages get metadata.isSupervisor for UI rendering
|
|
129
|
+
// Note: Don't pass operationId - let it create a new child operation (same as call_agent)
|
|
130
|
+
// This ensures each call has its own immutable context with isSupervisor properly set
|
|
129
131
|
await get().internal_execAgentRuntime({
|
|
130
132
|
context: { ...messageContext, agentId: supervisorAgentId, isSupervisor: true },
|
|
131
133
|
messages,
|
|
132
|
-
operationId: state.operationId,
|
|
133
134
|
parentMessageId: lastMessage.id,
|
|
134
135
|
parentMessageType: lastMessage.role as 'user' | 'assistant' | 'tool',
|
|
135
136
|
parentOperationId: orchestrationOperationId,
|
|
@@ -160,14 +160,16 @@ export const streamingExecutor: StateCreator<
|
|
|
160
160
|
// - agentId is used for session ID (message storage location)
|
|
161
161
|
const effectiveAgentId = paramSubAgentId || agentId;
|
|
162
162
|
|
|
163
|
-
// Get scope from operation context if available
|
|
163
|
+
// Get scope and groupId from operation context if available
|
|
164
164
|
const operation = operationId ? get().operations[operationId] : undefined;
|
|
165
165
|
const scope = operation?.context.scope;
|
|
166
|
+
const groupId = operation?.context.groupId;
|
|
166
167
|
|
|
167
168
|
// Resolve agent config with builtin agent runtime config merged
|
|
168
169
|
// This ensures runtime plugins (e.g., 'lobe-agent-builder' for Agent Builder) are included
|
|
169
170
|
const { agentConfig: agentConfigData, plugins: pluginIds } = resolveAgentConfig({
|
|
170
171
|
agentId: effectiveAgentId || '',
|
|
172
|
+
groupId, // Pass groupId for supervisor detection
|
|
171
173
|
scope, // Pass scope from operation context
|
|
172
174
|
});
|
|
173
175
|
|
|
@@ -341,6 +343,7 @@ export const streamingExecutor: StateCreator<
|
|
|
341
343
|
// - max_tokens/reasoning_effort based on chatConfig settings
|
|
342
344
|
const resolved = resolveAgentConfig({
|
|
343
345
|
agentId: effectiveAgentId,
|
|
346
|
+
groupId, // Pass groupId for supervisor detection
|
|
344
347
|
scope, // scope is already available from line 329
|
|
345
348
|
});
|
|
346
349
|
const finalAgentConfig = agentConfig || resolved.agentConfig;
|
|
@@ -594,7 +597,8 @@ export const streamingExecutor: StateCreator<
|
|
|
594
597
|
// - max_tokens/reasoning_effort based on chatConfig settings
|
|
595
598
|
const { agentConfig: agentConfigData } = resolveAgentConfig({
|
|
596
599
|
agentId: effectiveAgentId || '',
|
|
597
|
-
|
|
600
|
+
groupId, // Pass groupId for supervisor detection
|
|
601
|
+
scope: context.scope, // Pass scope from context parameter
|
|
598
602
|
});
|
|
599
603
|
|
|
600
604
|
// Use agent config from agentId
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { type MCPToolCallResult } from '@/libs/mcp';
|
|
2
|
+
import { useToolStore } from '@/store/tool';
|
|
3
|
+
import { type ChatToolPayload } from '@/types/message';
|
|
4
|
+
import { safeParseJSON } from '@/utils/safeParseJSON';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Executor function type for remote tool invocation
|
|
8
|
+
* @param payload - Tool call payload
|
|
9
|
+
* @returns Promise with MCPToolCallResult data
|
|
10
|
+
*/
|
|
11
|
+
export type RemoteToolExecutor = (payload: ChatToolPayload) => Promise<MCPToolCallResult>;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create a failed MCPToolCallResult
|
|
15
|
+
*/
|
|
16
|
+
const createFailedResult = (
|
|
17
|
+
errorMessage: string,
|
|
18
|
+
): { content: string; error: any; state: any; success: false } => ({
|
|
19
|
+
content: errorMessage,
|
|
20
|
+
error: { message: errorMessage },
|
|
21
|
+
state: {},
|
|
22
|
+
success: false,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const klavisExecutor: RemoteToolExecutor = async (p) => {
|
|
26
|
+
// payload.identifier 现在是存储用的 identifier(如 'google-calendar')
|
|
27
|
+
const identifier = p.identifier;
|
|
28
|
+
const klavisServers = useToolStore.getState().servers || [];
|
|
29
|
+
const server = klavisServers.find((s) => s.identifier === identifier);
|
|
30
|
+
|
|
31
|
+
if (!server) {
|
|
32
|
+
return createFailedResult(`Klavis server not found: ${identifier}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Parse arguments
|
|
36
|
+
const args = safeParseJSON(p.arguments) || {};
|
|
37
|
+
|
|
38
|
+
// Call Klavis tool via store action
|
|
39
|
+
const result = await useToolStore.getState().callKlavisTool({
|
|
40
|
+
serverUrl: server.serverUrl,
|
|
41
|
+
toolArgs: args,
|
|
42
|
+
toolName: p.apiName,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (!result.success) {
|
|
46
|
+
return createFailedResult(result.error || 'Klavis tool execution failed');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// result.data is MCPToolCallProcessedResult from server
|
|
50
|
+
// Convert to MCPToolCallResult format
|
|
51
|
+
const toolResult = result.data;
|
|
52
|
+
if (toolResult) {
|
|
53
|
+
return {
|
|
54
|
+
content: toolResult.content,
|
|
55
|
+
error: toolResult.state?.isError ? toolResult.state : undefined,
|
|
56
|
+
state: toolResult.state,
|
|
57
|
+
success: toolResult.success,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return createFailedResult('Klavis tool returned empty result');
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const lobehubSkillExecutor: RemoteToolExecutor = async (p) => {
|
|
65
|
+
// payload.identifier is the provider id (e.g., 'linear', 'microsoft')
|
|
66
|
+
const provider = p.identifier;
|
|
67
|
+
|
|
68
|
+
// Parse arguments
|
|
69
|
+
const args = safeParseJSON(p.arguments) || {};
|
|
70
|
+
|
|
71
|
+
// Call LobeHub Skill tool via store action
|
|
72
|
+
const result = await useToolStore.getState().callLobehubSkillTool({
|
|
73
|
+
args,
|
|
74
|
+
provider,
|
|
75
|
+
toolName: p.apiName,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (!result.success) {
|
|
79
|
+
return createFailedResult(
|
|
80
|
+
result.error || `LobeHub Skill tool ${provider} ${p.apiName} execution failed`,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Convert to MCPToolCallResult format
|
|
85
|
+
const content = typeof result.data === 'string' ? result.data : JSON.stringify(result.data);
|
|
86
|
+
return {
|
|
87
|
+
content,
|
|
88
|
+
error: undefined,
|
|
89
|
+
state: { content: [{ text: content, type: 'text' }] },
|
|
90
|
+
success: true,
|
|
91
|
+
};
|
|
92
|
+
};
|