@lobehub/lobehub 2.0.0-next.306 → 2.0.0-next.307
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 +28 -0
- package/changelog/v1.json +9 -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/executor.test.ts +0 -12
- package/packages/builtin-tool-group-management/src/executor.ts +8 -47
- package/packages/builtin-tool-group-management/src/manifest.ts +0 -17
- package/packages/builtin-tool-group-management/src/systemRole.ts +1 -8
- package/packages/builtin-tool-group-management/src/types.ts +0 -10
- package/packages/builtin-tool-local-system/src/ExecutionRuntime/index.ts +70 -31
- package/packages/builtin-tool-local-system/src/executor/index.ts +94 -60
- package/packages/database/src/repositories/agentGroup/index.ts +23 -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]/(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)/community/(detail)/group_agent/features/Sidebar/ActionButton/AddGroupAgent.tsx +69 -17
- 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/features/ChatInput/ActionBar/Upload/ServerMode.tsx +13 -3
- package/src/features/ChatInput/ActionBar/components/ActionDropdown.tsx +26 -3
- package/src/features/ResourceManager/components/Header/AddButton.tsx +20 -3
- 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/slices/aiChat/actions/streamingExecutor.ts +6 -2
|
@@ -627,7 +627,7 @@ describe('resolveAgentConfig', () => {
|
|
|
627
627
|
});
|
|
628
628
|
});
|
|
629
629
|
|
|
630
|
-
describe('supervisor agent (
|
|
630
|
+
describe('supervisor agent (detected via groupId)', () => {
|
|
631
631
|
const mockGroupStoreState = { groupMap: {} };
|
|
632
632
|
const mockGroupWithSupervisor = {
|
|
633
633
|
agents: [
|
|
@@ -651,18 +651,11 @@ describe('resolveAgentConfig', () => {
|
|
|
651
651
|
);
|
|
652
652
|
});
|
|
653
653
|
|
|
654
|
-
it('should detect supervisor agent
|
|
655
|
-
// Mock:
|
|
656
|
-
vi.spyOn(
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
).mockReturnValue(() => mockGroupWithSupervisor as any);
|
|
660
|
-
|
|
661
|
-
// Mock: getGroupBySupervisorAgentId for building groupSupervisorContext
|
|
662
|
-
vi.spyOn(
|
|
663
|
-
agentGroupSelectors.agentGroupSelectors,
|
|
664
|
-
'getGroupBySupervisorAgentId',
|
|
665
|
-
).mockReturnValue(() => mockGroupWithSupervisor as any);
|
|
654
|
+
it('should detect supervisor agent using groupId for direct lookup', () => {
|
|
655
|
+
// Mock: groupById returns the group
|
|
656
|
+
vi.spyOn(agentGroupSelectors.agentGroupByIdSelectors, 'groupById').mockReturnValue(
|
|
657
|
+
() => mockGroupWithSupervisor as any,
|
|
658
|
+
);
|
|
666
659
|
|
|
667
660
|
// Mock: getGroupMembers returns non-supervisor agents
|
|
668
661
|
vi.spyOn(agentGroupSelectors.agentGroupSelectors, 'getGroupMembers').mockReturnValue(
|
|
@@ -680,7 +673,10 @@ describe('resolveAgentConfig', () => {
|
|
|
680
673
|
systemRole: 'You are a group supervisor...',
|
|
681
674
|
});
|
|
682
675
|
|
|
683
|
-
const result = resolveAgentConfig({
|
|
676
|
+
const result = resolveAgentConfig({
|
|
677
|
+
agentId: 'supervisor-agent-id',
|
|
678
|
+
groupId: 'group-123',
|
|
679
|
+
});
|
|
684
680
|
|
|
685
681
|
expect(result.isBuiltinAgent).toBe(true);
|
|
686
682
|
expect(result.slug).toBe('group-supervisor');
|
|
@@ -689,17 +685,10 @@ describe('resolveAgentConfig', () => {
|
|
|
689
685
|
});
|
|
690
686
|
|
|
691
687
|
it('should pass groupSupervisorContext to getAgentRuntimeConfig', () => {
|
|
692
|
-
// Mock:
|
|
693
|
-
vi.spyOn(
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
).mockReturnValue(() => mockGroupWithSupervisor as any);
|
|
697
|
-
|
|
698
|
-
// Mock: getGroupBySupervisorAgentId for building groupSupervisorContext
|
|
699
|
-
vi.spyOn(
|
|
700
|
-
agentGroupSelectors.agentGroupSelectors,
|
|
701
|
-
'getGroupBySupervisorAgentId',
|
|
702
|
-
).mockReturnValue(() => mockGroupWithSupervisor as any);
|
|
688
|
+
// Mock: groupById returns the group
|
|
689
|
+
vi.spyOn(agentGroupSelectors.agentGroupByIdSelectors, 'groupById').mockReturnValue(
|
|
690
|
+
() => mockGroupWithSupervisor as any,
|
|
691
|
+
);
|
|
703
692
|
|
|
704
693
|
// Mock: getGroupMembers returns non-supervisor agents
|
|
705
694
|
vi.spyOn(agentGroupSelectors.agentGroupSelectors, 'getGroupMembers').mockReturnValue(
|
|
@@ -718,7 +707,10 @@ describe('resolveAgentConfig', () => {
|
|
|
718
707
|
systemRole: 'You are a group supervisor...',
|
|
719
708
|
});
|
|
720
709
|
|
|
721
|
-
resolveAgentConfig({
|
|
710
|
+
resolveAgentConfig({
|
|
711
|
+
agentId: 'supervisor-agent-id',
|
|
712
|
+
groupId: 'group-123',
|
|
713
|
+
});
|
|
722
714
|
|
|
723
715
|
expect(getAgentRuntimeConfigSpy).toHaveBeenCalledWith(
|
|
724
716
|
'group-supervisor',
|
|
@@ -736,31 +728,53 @@ describe('resolveAgentConfig', () => {
|
|
|
736
728
|
);
|
|
737
729
|
});
|
|
738
730
|
|
|
739
|
-
it('should treat as regular agent when
|
|
740
|
-
//
|
|
741
|
-
|
|
742
|
-
agentGroupSelectors.agentGroupByIdSelectors,
|
|
743
|
-
'groupBySupervisorAgentId',
|
|
744
|
-
).mockReturnValue(() => undefined);
|
|
745
|
-
|
|
746
|
-
const result = resolveAgentConfig({ agentId: 'some-other-agent' });
|
|
731
|
+
it('should treat as regular agent when groupId is not provided', () => {
|
|
732
|
+
// Without groupId, cannot detect supervisor
|
|
733
|
+
const result = resolveAgentConfig({ agentId: 'supervisor-agent-id' });
|
|
747
734
|
|
|
748
735
|
expect(result.isBuiltinAgent).toBe(false);
|
|
749
736
|
expect(result.slug).toBeUndefined();
|
|
750
737
|
expect(result.plugins).toEqual(['plugin-a', 'plugin-b']); // Falls back to agent config plugins
|
|
751
738
|
});
|
|
752
739
|
|
|
753
|
-
it('should
|
|
754
|
-
//
|
|
755
|
-
vi.spyOn(
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
).mockReturnValue(() => mockGroupWithSupervisor as any);
|
|
740
|
+
it('should treat as regular agent when agentId does not match group supervisorAgentId', () => {
|
|
741
|
+
// Mock: groupById returns the group
|
|
742
|
+
vi.spyOn(agentGroupSelectors.agentGroupByIdSelectors, 'groupById').mockReturnValue(
|
|
743
|
+
() => mockGroupWithSupervisor as any,
|
|
744
|
+
);
|
|
759
745
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
'
|
|
763
|
-
|
|
746
|
+
// Pass a different agentId that is not the supervisor
|
|
747
|
+
const result = resolveAgentConfig({
|
|
748
|
+
agentId: 'some-other-agent',
|
|
749
|
+
groupId: 'group-123',
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
expect(result.isBuiltinAgent).toBe(false);
|
|
753
|
+
expect(result.slug).toBeUndefined();
|
|
754
|
+
expect(result.plugins).toEqual(['plugin-a', 'plugin-b']);
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
it('should treat as regular agent when group is not found', () => {
|
|
758
|
+
// Mock: groupById returns undefined
|
|
759
|
+
vi.spyOn(agentGroupSelectors.agentGroupByIdSelectors, 'groupById').mockReturnValue(
|
|
760
|
+
() => undefined,
|
|
761
|
+
);
|
|
762
|
+
|
|
763
|
+
const result = resolveAgentConfig({
|
|
764
|
+
agentId: 'supervisor-agent-id',
|
|
765
|
+
groupId: 'non-existent-group',
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
expect(result.isBuiltinAgent).toBe(false);
|
|
769
|
+
expect(result.slug).toBeUndefined();
|
|
770
|
+
expect(result.plugins).toEqual(['plugin-a', 'plugin-b']);
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
it('should work correctly when regenerating supervisor message with groupId', () => {
|
|
774
|
+
// This simulates the regenerate flow where both agentId and groupId are provided
|
|
775
|
+
vi.spyOn(agentGroupSelectors.agentGroupByIdSelectors, 'groupById').mockReturnValue(
|
|
776
|
+
() => mockGroupWithSupervisor as any,
|
|
777
|
+
);
|
|
764
778
|
|
|
765
779
|
vi.spyOn(agentGroupSelectors.agentGroupSelectors, 'getGroupMembers').mockReturnValue(
|
|
766
780
|
() => [{ id: 'member-agent-1', title: 'Agent 1' }] as any,
|
|
@@ -772,7 +786,10 @@ describe('resolveAgentConfig', () => {
|
|
|
772
786
|
systemRole: 'Supervisor system role',
|
|
773
787
|
});
|
|
774
788
|
|
|
775
|
-
const result = resolveAgentConfig({
|
|
789
|
+
const result = resolveAgentConfig({
|
|
790
|
+
agentId: 'supervisor-agent-id',
|
|
791
|
+
groupId: 'group-123',
|
|
792
|
+
});
|
|
776
793
|
|
|
777
794
|
// Should correctly identify as builtin supervisor agent
|
|
778
795
|
expect(result.isBuiltinAgent).toBe(true);
|
|
@@ -55,6 +55,12 @@ export interface AgentConfigResolverContext {
|
|
|
55
55
|
/** Document content for page-agent */
|
|
56
56
|
documentContent?: string;
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Group ID for supervisor detection.
|
|
60
|
+
* When provided, used for direct lookup instead of iterating all groups.
|
|
61
|
+
*/
|
|
62
|
+
groupId?: string;
|
|
63
|
+
|
|
58
64
|
/** Current model being used (for template variables) */
|
|
59
65
|
model?: string;
|
|
60
66
|
/** Plugins enabled for the agent */
|
|
@@ -114,30 +120,19 @@ export const resolveAgentConfig = (ctx: AgentConfigResolverContext): ResolvedAge
|
|
|
114
120
|
const basePlugins = agentConfig.plugins ?? [];
|
|
115
121
|
|
|
116
122
|
// Check if this is a builtin agent
|
|
117
|
-
// First check agent store, then check if this is a supervisor agent
|
|
123
|
+
// First check agent store, then check if this is a supervisor agent via groupId
|
|
118
124
|
let slug = agentSelectors.getAgentSlugById(agentId)(agentStoreState);
|
|
119
125
|
log('slug from agentStore: %s (agentId: %s)', slug, agentId);
|
|
120
126
|
|
|
121
|
-
// If not found in agent store, check if this is a supervisor agent
|
|
122
|
-
//
|
|
123
|
-
if (!slug) {
|
|
127
|
+
// If not found in agent store, check if this is a supervisor agent using groupId
|
|
128
|
+
// This is more reliable than iterating all groups to find a match
|
|
129
|
+
if (!slug && ctx.groupId) {
|
|
124
130
|
const groupStoreState = getChatGroupStoreState();
|
|
125
|
-
const
|
|
126
|
-
const groupMapKeys = Object.keys(groupMap);
|
|
127
|
-
log(
|
|
128
|
-
'checking groupStore for supervisor - groupMap has %d groups: %o',
|
|
129
|
-
groupMapKeys.length,
|
|
130
|
-
groupMapKeys.map((key) => ({
|
|
131
|
-
groupId: key,
|
|
132
|
-
supervisorAgentId: groupMap[key]?.supervisorAgentId,
|
|
133
|
-
title: groupMap[key]?.title,
|
|
134
|
-
})),
|
|
135
|
-
);
|
|
131
|
+
const group = agentGroupByIdSelectors.groupById(ctx.groupId)(groupStoreState);
|
|
136
132
|
|
|
137
|
-
const group = agentGroupByIdSelectors.groupBySupervisorAgentId(agentId)(groupStoreState);
|
|
138
133
|
log(
|
|
139
|
-
'
|
|
140
|
-
|
|
134
|
+
'checking supervisor via groupId %s: group=%o',
|
|
135
|
+
ctx.groupId,
|
|
141
136
|
group
|
|
142
137
|
? {
|
|
143
138
|
groupId: group.id,
|
|
@@ -147,10 +142,15 @@ export const resolveAgentConfig = (ctx: AgentConfigResolverContext): ResolvedAge
|
|
|
147
142
|
: null,
|
|
148
143
|
);
|
|
149
144
|
|
|
150
|
-
if
|
|
151
|
-
|
|
145
|
+
// Check if this agent is the supervisor of the specified group
|
|
146
|
+
if (group?.supervisorAgentId === agentId) {
|
|
152
147
|
slug = BUILTIN_AGENT_SLUGS.groupSupervisor;
|
|
153
|
-
log(
|
|
148
|
+
log(
|
|
149
|
+
'agentId %s identified as group supervisor for group %s, assigned slug: %s',
|
|
150
|
+
agentId,
|
|
151
|
+
ctx.groupId,
|
|
152
|
+
slug,
|
|
153
|
+
);
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
|
|
@@ -213,15 +213,17 @@ export const resolveAgentConfig = (ctx: AgentConfigResolverContext): ResolvedAge
|
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
// Build groupSupervisorContext if this is a group-supervisor agent
|
|
216
|
+
// Use groupId for direct lookup instead of reverse lookup by supervisorAgentId
|
|
216
217
|
let groupSupervisorContext;
|
|
217
|
-
if (slug === BUILTIN_AGENT_SLUGS.groupSupervisor) {
|
|
218
|
-
log('building groupSupervisorContext for agentId: %s', agentId);
|
|
218
|
+
if (slug === BUILTIN_AGENT_SLUGS.groupSupervisor && ctx.groupId) {
|
|
219
|
+
log('building groupSupervisorContext for agentId: %s, groupId: %s', agentId, ctx.groupId);
|
|
219
220
|
const groupStoreState = getChatGroupStoreState();
|
|
220
|
-
//
|
|
221
|
-
const group =
|
|
221
|
+
// Direct lookup using groupId
|
|
222
|
+
const group = agentGroupByIdSelectors.groupById(ctx.groupId)(groupStoreState);
|
|
222
223
|
|
|
223
224
|
log(
|
|
224
|
-
'
|
|
225
|
+
'groupById result for %s: %o',
|
|
226
|
+
ctx.groupId,
|
|
225
227
|
group
|
|
226
228
|
? {
|
|
227
229
|
agentsCount: group.agents?.length,
|
|
@@ -253,7 +255,7 @@ export const resolveAgentConfig = (ctx: AgentConfigResolverContext): ResolvedAge
|
|
|
253
255
|
hasSystemPrompt: !!groupSupervisorContext.systemPrompt,
|
|
254
256
|
});
|
|
255
257
|
} else {
|
|
256
|
-
log('WARNING: group not found for
|
|
258
|
+
log('WARNING: group not found for groupId: %s', ctx.groupId);
|
|
257
259
|
}
|
|
258
260
|
}
|
|
259
261
|
|
|
@@ -20,6 +20,18 @@ export interface GroupMemberConfig {
|
|
|
20
20
|
title?: string;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
export interface SupervisorConfig {
|
|
24
|
+
avatar?: string;
|
|
25
|
+
backgroundColor?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
model?: string;
|
|
28
|
+
params?: any;
|
|
29
|
+
provider?: string;
|
|
30
|
+
systemRole?: string;
|
|
31
|
+
tags?: string[];
|
|
32
|
+
title?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
23
35
|
class ChatGroupService {
|
|
24
36
|
/**
|
|
25
37
|
* Create a group with a supervisor agent.
|
|
@@ -42,6 +54,7 @@ class ChatGroupService {
|
|
|
42
54
|
createGroupWithMembers = (
|
|
43
55
|
groupConfig: Omit<NewChatGroup, 'userId'>,
|
|
44
56
|
members: GroupMemberConfig[],
|
|
57
|
+
supervisorConfig?: SupervisorConfig,
|
|
45
58
|
): Promise<{ agentIds: string[]; groupId: string; supervisorAgentId: string }> => {
|
|
46
59
|
return lambdaClient.group.createGroupWithMembers.mutate({
|
|
47
60
|
groupConfig: {
|
|
@@ -49,6 +62,7 @@ class ChatGroupService {
|
|
|
49
62
|
config: groupConfig.config as any,
|
|
50
63
|
},
|
|
51
64
|
members: members as Partial<AgentItem>[],
|
|
65
|
+
supervisorConfig,
|
|
52
66
|
});
|
|
53
67
|
};
|
|
54
68
|
|
|
@@ -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
|