@lobehub/lobehub 2.0.0-next.305 → 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 +53 -0
- package/changelog/v1.json +18 -0
- package/e2e/src/steps/community/detail-pages.steps.ts +3 -1
- package/e2e/src/steps/community/interactions.steps.ts +4 -4
- 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/context-engine/src/processors/GroupMessageFlatten.ts +9 -6
- package/packages/context-engine/src/processors/__tests__/GroupMessageFlatten.test.ts +103 -0
- package/packages/context-engine/src/providers/GroupAgentBuilderContextInjector.ts +18 -31
- package/packages/context-engine/src/providers/__tests__/GroupAgentBuilderContextInjector.test.ts +307 -0
- 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/packages/prompts/src/prompts/userMemory/__snapshots__/index.test.ts.snap +14 -38
- package/packages/prompts/src/prompts/userMemory/index.ts +5 -24
- 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)/assistant/index.tsx +1 -1
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/AddGroupAgent.tsx +69 -17
- package/src/app/[variants]/(main)/community/(detail)/mcp/index.tsx +1 -1
- 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/features/Conversation/MainChatInput/index.tsx +2 -2
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentItem/index.tsx +2 -2
- package/src/features/ChatInput/ActionBar/Upload/ServerMode.tsx +13 -3
- package/src/features/ChatInput/ActionBar/components/ActionDropdown.tsx +26 -3
- package/src/features/Conversation/Messages/Supervisor/index.tsx +2 -1
- package/src/features/Conversation/Messages/components/ContentLoading.tsx +8 -2
- 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 +77 -10
- package/src/services/chat/mecha/modelParamsResolver.test.ts +211 -0
- package/src/services/chatGroup/index.ts +14 -0
- package/src/store/agentGroup/action.ts +30 -0
- package/src/store/agentGroup/slices/lifecycle.test.ts +77 -18
- package/src/store/agentGroup/slices/lifecycle.ts +7 -9
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +6 -2
- package/src/store/chat/slices/operation/__tests__/selectors.test.ts +124 -0
- package/src/store/chat/slices/operation/selectors.ts +22 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface FormatRenameResultParams {
|
|
2
|
+
error?: string;
|
|
3
|
+
newName: string;
|
|
4
|
+
oldPath: string;
|
|
5
|
+
success: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const formatRenameResult = ({
|
|
9
|
+
success,
|
|
10
|
+
oldPath,
|
|
11
|
+
newName,
|
|
12
|
+
error,
|
|
13
|
+
}: FormatRenameResultParams): string => {
|
|
14
|
+
return success
|
|
15
|
+
? `Successfully renamed file ${oldPath} to ${newName}`
|
|
16
|
+
: `Failed to rename file: ${error}`;
|
|
17
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { formatWriteResult } from './formatWriteResult';
|
|
4
|
+
|
|
5
|
+
describe('formatWriteResult', () => {
|
|
6
|
+
it('should format successful write', () => {
|
|
7
|
+
const result = formatWriteResult({
|
|
8
|
+
path: '/src/newFile.ts',
|
|
9
|
+
success: true,
|
|
10
|
+
});
|
|
11
|
+
expect(result).toMatchInlineSnapshot(`"Successfully wrote to /src/newFile.ts"`);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should format failed write with error', () => {
|
|
15
|
+
const result = formatWriteResult({
|
|
16
|
+
error: 'Permission denied',
|
|
17
|
+
path: '/protected/file.ts',
|
|
18
|
+
success: false,
|
|
19
|
+
});
|
|
20
|
+
expect(result).toMatchInlineSnapshot(`"Failed to write file: Permission denied"`);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should format failed write without error message', () => {
|
|
24
|
+
const result = formatWriteResult({
|
|
25
|
+
path: '/some/path.ts',
|
|
26
|
+
success: false,
|
|
27
|
+
});
|
|
28
|
+
expect(result).toMatchInlineSnapshot(`"Failed to write file: Unknown error"`);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface FormatWriteResultParams {
|
|
2
|
+
error?: string;
|
|
3
|
+
path: string;
|
|
4
|
+
success: boolean;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const formatWriteResult = ({ success, path, error }: FormatWriteResultParams): string => {
|
|
8
|
+
return success
|
|
9
|
+
? `Successfully wrote to ${path}`
|
|
10
|
+
: `Failed to write file: ${error || 'Unknown error'}`;
|
|
11
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from './formatCommandOutput';
|
|
2
|
+
export * from './formatCommandResult';
|
|
3
|
+
export * from './formatEditResult';
|
|
4
|
+
export * from './formatFileContent';
|
|
5
|
+
export * from './formatFileList';
|
|
6
|
+
export * from './formatFileSearchResults';
|
|
7
|
+
export * from './formatGlobResults';
|
|
8
|
+
export * from './formatGrepResults';
|
|
9
|
+
export * from './formatKillResult';
|
|
10
|
+
export * from './formatMoveResults';
|
|
11
|
+
export * from './formatMultipleFiles';
|
|
12
|
+
export * from './formatRenameResult';
|
|
13
|
+
export * from './formatWriteResult';
|
|
@@ -120,15 +120,9 @@ exports[`promptUserMemory > identities only > should format identities grouped b
|
|
|
120
120
|
"<user_memory>
|
|
121
121
|
<instruction>The following are memories about this user retrieved from previous conversations. Use this information to personalize your responses and maintain continuity.</instruction>
|
|
122
122
|
<identities count="3">
|
|
123
|
-
<personal
|
|
124
|
-
|
|
125
|
-
</
|
|
126
|
-
<professional count="1">
|
|
127
|
-
<identity role="Software Engineer">User is a senior software engineer</identity>
|
|
128
|
-
</professional>
|
|
129
|
-
<demographic count="1">
|
|
130
|
-
<identity>User is based in Shanghai</identity>
|
|
131
|
-
</demographic>
|
|
123
|
+
<identity type="personal" role="Father" id="id-1">User is a father of two children</identity>
|
|
124
|
+
<identity type="professional" role="Software Engineer" id="id-2">User is a senior software engineer</identity>
|
|
125
|
+
<identity type="demographic" id="id-3">User is based in Shanghai</identity>
|
|
132
126
|
</identities>
|
|
133
127
|
</user_memory>"
|
|
134
128
|
`;
|
|
@@ -137,10 +131,8 @@ exports[`promptUserMemory > identities only > should format single type identiti
|
|
|
137
131
|
"<user_memory>
|
|
138
132
|
<instruction>The following are memories about this user retrieved from previous conversations. Use this information to personalize your responses and maintain continuity.</instruction>
|
|
139
133
|
<identities count="2">
|
|
140
|
-
<demographic
|
|
141
|
-
|
|
142
|
-
<identity>User speaks Mandarin and English</identity>
|
|
143
|
-
</demographic>
|
|
134
|
+
<identity type="demographic" id="id-1">User is 35 years old</identity>
|
|
135
|
+
<identity type="demographic" id="id-2">User speaks Mandarin and English</identity>
|
|
144
136
|
</identities>
|
|
145
137
|
</user_memory>"
|
|
146
138
|
`;
|
|
@@ -149,10 +141,8 @@ exports[`promptUserMemory > identities only > should format single type identiti
|
|
|
149
141
|
"<user_memory>
|
|
150
142
|
<instruction>The following are memories about this user retrieved from previous conversations. Use this information to personalize your responses and maintain continuity.</instruction>
|
|
151
143
|
<identities count="2">
|
|
152
|
-
<personal
|
|
153
|
-
|
|
154
|
-
<identity>User has a pet dog</identity>
|
|
155
|
-
</personal>
|
|
144
|
+
<identity type="personal" id="id-1">User is married</identity>
|
|
145
|
+
<identity type="personal" id="id-2">User has a pet dog</identity>
|
|
156
146
|
</identities>
|
|
157
147
|
</user_memory>"
|
|
158
148
|
`;
|
|
@@ -161,9 +151,7 @@ exports[`promptUserMemory > identities only > should format single type identiti
|
|
|
161
151
|
"<user_memory>
|
|
162
152
|
<instruction>The following are memories about this user retrieved from previous conversations. Use this information to personalize your responses and maintain continuity.</instruction>
|
|
163
153
|
<identities count="1">
|
|
164
|
-
<professional
|
|
165
|
-
<identity role="CTO">User works at a tech startup</identity>
|
|
166
|
-
</professional>
|
|
154
|
+
<identity type="professional" role="CTO" id="id-1">User works at a tech startup</identity>
|
|
167
155
|
</identities>
|
|
168
156
|
</user_memory>"
|
|
169
157
|
`;
|
|
@@ -172,9 +160,7 @@ exports[`promptUserMemory > identities only > should handle identity with null v
|
|
|
172
160
|
"<user_memory>
|
|
173
161
|
<instruction>The following are memories about this user retrieved from previous conversations. Use this information to personalize your responses and maintain continuity.</instruction>
|
|
174
162
|
<identities count="1">
|
|
175
|
-
<personal
|
|
176
|
-
<identity></identity>
|
|
177
|
-
</personal>
|
|
163
|
+
<identity type="personal" id="id-1"></identity>
|
|
178
164
|
</identities>
|
|
179
165
|
</user_memory>"
|
|
180
166
|
`;
|
|
@@ -183,9 +169,7 @@ exports[`promptUserMemory > identities only > should handle identity without rol
|
|
|
183
169
|
"<user_memory>
|
|
184
170
|
<instruction>The following are memories about this user retrieved from previous conversations. Use this information to personalize your responses and maintain continuity.</instruction>
|
|
185
171
|
<identities count="1">
|
|
186
|
-
<personal
|
|
187
|
-
<identity>User enjoys hiking</identity>
|
|
188
|
-
</personal>
|
|
172
|
+
<identity type="personal" id="id-1">User enjoys hiking</identity>
|
|
189
173
|
</identities>
|
|
190
174
|
</user_memory>"
|
|
191
175
|
`;
|
|
@@ -194,9 +178,7 @@ exports[`promptUserMemory > mixed memory types > should format all memory types
|
|
|
194
178
|
"<user_memory>
|
|
195
179
|
<instruction>The following are memories about this user retrieved from previous conversations. Use this information to personalize your responses and maintain continuity.</instruction>
|
|
196
180
|
<identities count="1">
|
|
197
|
-
<professional
|
|
198
|
-
<identity role="Tech Lead">User is a tech lead at a startup</identity>
|
|
199
|
-
</professional>
|
|
181
|
+
<identity type="professional" role="Tech Lead" id="id-1">User is a tech lead at a startup</identity>
|
|
200
182
|
</identities>
|
|
201
183
|
<contexts count="1">
|
|
202
184
|
<context id="ctx-1" title="Experience Level">Senior developer with 10 years experience</context>
|
|
@@ -217,15 +199,9 @@ exports[`promptUserMemory > mixed memory types > should format all memory types
|
|
|
217
199
|
"<user_memory>
|
|
218
200
|
<instruction>The following are memories about this user retrieved from previous conversations. Use this information to personalize your responses and maintain continuity.</instruction>
|
|
219
201
|
<identities count="3">
|
|
220
|
-
<personal
|
|
221
|
-
|
|
222
|
-
</
|
|
223
|
-
<professional count="1">
|
|
224
|
-
<identity role="Senior Engineer">User is a senior engineer</identity>
|
|
225
|
-
</professional>
|
|
226
|
-
<demographic count="1">
|
|
227
|
-
<identity>User lives in Beijing</identity>
|
|
228
|
-
</demographic>
|
|
202
|
+
<identity type="personal" role="Father" id="id-1">User is a father</identity>
|
|
203
|
+
<identity type="professional" role="Senior Engineer" id="id-2">User is a senior engineer</identity>
|
|
204
|
+
<identity type="demographic" id="id-3">User lives in Beijing</identity>
|
|
229
205
|
</identities>
|
|
230
206
|
<contexts count="1">
|
|
231
207
|
<context id="ctx-1" title="Current Work">Working on AI products</context>
|
|
@@ -98,29 +98,10 @@ const isValidIdentityItem = (item: UserMemoryIdentityItem): boolean => {
|
|
|
98
98
|
* Formats a single identity memory item
|
|
99
99
|
*/
|
|
100
100
|
const formatIdentityItem = (item: UserMemoryIdentityItem): string => {
|
|
101
|
+
const typeAttr = item.type ? ` type="${item.type}"` : '';
|
|
101
102
|
const roleAttr = item.role ? ` role="${item.role}"` : '';
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Format identities grouped by type as XML
|
|
107
|
-
* Types: personal (角色), professional (职业), demographic (属性)
|
|
108
|
-
*/
|
|
109
|
-
const formatIdentitiesSection = (identities: UserMemoryIdentityItem[]): string => {
|
|
110
|
-
const personal = identities.filter((i) => i.type === 'personal');
|
|
111
|
-
const professional = identities.filter((i) => i.type === 'professional');
|
|
112
|
-
const demographic = identities.filter((i) => i.type === 'demographic');
|
|
113
|
-
|
|
114
|
-
return [
|
|
115
|
-
personal.length > 0 &&
|
|
116
|
-
` <personal count="${personal.length}">\n${personal.map(formatIdentityItem).join('\n')}\n </personal>`,
|
|
117
|
-
professional.length > 0 &&
|
|
118
|
-
` <professional count="${professional.length}">\n${professional.map(formatIdentityItem).join('\n')}\n </professional>`,
|
|
119
|
-
demographic.length > 0 &&
|
|
120
|
-
` <demographic count="${demographic.length}">\n${demographic.map(formatIdentityItem).join('\n')}\n </demographic>`,
|
|
121
|
-
]
|
|
122
|
-
.filter(Boolean)
|
|
123
|
-
.join('\n');
|
|
103
|
+
const idAttr = item.id ? ` id="${item.id}"` : '';
|
|
104
|
+
return ` <identity${typeAttr}${roleAttr}${idAttr}>${item.description || ''}</identity>`;
|
|
124
105
|
};
|
|
125
106
|
|
|
126
107
|
/**
|
|
@@ -156,9 +137,9 @@ export const promptUserMemory = ({ memories }: PromptUserMemoryOptions): string
|
|
|
156
137
|
'<instruction>The following are memories about this user retrieved from previous conversations. Use this information to personalize your responses and maintain continuity.</instruction>',
|
|
157
138
|
);
|
|
158
139
|
|
|
159
|
-
// Add identities section (user's identity information
|
|
140
|
+
// Add identities section (user's identity information)
|
|
160
141
|
if (hasIdentities) {
|
|
161
|
-
const identitiesXml =
|
|
142
|
+
const identitiesXml = identities.map((item) => formatIdentityItem(item)).join('\n');
|
|
162
143
|
contentParts.push(`<identities count="${identities.length}">
|
|
163
144
|
${identitiesXml}
|
|
164
145
|
</identities>`);
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { ActionIcon, DropdownMenu } from '@lobehub/ui';
|
|
2
2
|
import { MoreHorizontal } from 'lucide-react';
|
|
3
|
-
import { memo } from 'react';
|
|
3
|
+
import { memo, useState } from 'react';
|
|
4
4
|
|
|
5
5
|
import { useTopicActionsDropdownMenu } from './useDropdownMenu';
|
|
6
6
|
|
|
7
7
|
const Actions = memo(() => {
|
|
8
|
-
const
|
|
8
|
+
const [open, setOpen] = useState(false);
|
|
9
|
+
const menuItems = useTopicActionsDropdownMenu({ onUploadClose: () => setOpen(false) });
|
|
9
10
|
|
|
10
11
|
return (
|
|
11
|
-
<DropdownMenu items={menuItems}>
|
|
12
|
+
<DropdownMenu items={menuItems} onOpenChange={setOpen} open={open}>
|
|
12
13
|
<ActionIcon icon={MoreHorizontal} size={'small'} />
|
|
13
14
|
</DropdownMenu>
|
|
14
15
|
);
|
|
@@ -21,9 +21,16 @@ const hotArea = css`
|
|
|
21
21
|
}
|
|
22
22
|
`;
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
interface UseTopicActionsDropdownMenuOptions {
|
|
25
|
+
onUploadClose?: () => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const useTopicActionsDropdownMenu = (
|
|
29
|
+
options: UseTopicActionsDropdownMenuOptions = {},
|
|
30
|
+
): MenuProps['items'] => {
|
|
25
31
|
const { t } = useTranslation(['topic', 'common']);
|
|
26
32
|
const { modal } = App.useApp();
|
|
33
|
+
const { onUploadClose } = options;
|
|
27
34
|
|
|
28
35
|
const [removeUnstarredTopic, removeAllTopic, importTopic] = useChatStore((s) => [
|
|
29
36
|
s.removeUnstarredTopic,
|
|
@@ -33,6 +40,7 @@ export const useTopicActionsDropdownMenu = (): MenuProps['items'] => {
|
|
|
33
40
|
|
|
34
41
|
const handleImport = useCallback(
|
|
35
42
|
async (file: File) => {
|
|
43
|
+
onUploadClose?.();
|
|
36
44
|
try {
|
|
37
45
|
const text = await file.text();
|
|
38
46
|
// Validate JSON format
|
|
@@ -46,7 +54,7 @@ export const useTopicActionsDropdownMenu = (): MenuProps['items'] => {
|
|
|
46
54
|
}
|
|
47
55
|
return false; // Prevent default upload behavior
|
|
48
56
|
},
|
|
49
|
-
[importTopic, modal, t],
|
|
57
|
+
[importTopic, modal, onUploadClose, t],
|
|
50
58
|
);
|
|
51
59
|
|
|
52
60
|
const [topicDisplayMode, updatePreference] = useUserStore((s) => [
|
|
@@ -101,6 +109,7 @@ export const useTopicActionsDropdownMenu = (): MenuProps['items'] => {
|
|
|
101
109
|
<div className={cx(hotArea)}>{t('actions.import')}</div>
|
|
102
110
|
</Upload>
|
|
103
111
|
),
|
|
112
|
+
...(onUploadClose ? { closeOnClick: false } : null),
|
|
104
113
|
},
|
|
105
114
|
{
|
|
106
115
|
type: 'divider' as const,
|
|
@@ -143,6 +152,7 @@ export const useTopicActionsDropdownMenu = (): MenuProps['items'] => {
|
|
|
143
152
|
updatePreference,
|
|
144
153
|
updateSystemStatus,
|
|
145
154
|
handleImport,
|
|
155
|
+
onUploadClose,
|
|
146
156
|
removeUnstarredTopic,
|
|
147
157
|
removeAllTopic,
|
|
148
158
|
t,
|
|
@@ -40,7 +40,7 @@ const AssistantDetailPage = memo<AssistantDetailPageProps>(({ mobile }) => {
|
|
|
40
40
|
return (
|
|
41
41
|
<TocProvider>
|
|
42
42
|
<DetailProvider config={data}>
|
|
43
|
-
<Flexbox gap={16}>
|
|
43
|
+
<Flexbox data-testid="assistant-detail-content" gap={16}>
|
|
44
44
|
<Header mobile={mobile} />
|
|
45
45
|
<Details mobile={mobile} />
|
|
46
46
|
</Flexbox>
|
|
@@ -87,6 +87,42 @@ const AddGroupAgent = memo<{ mobile?: boolean }>(() => {
|
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
// Find supervisor from memberAgents
|
|
91
|
+
const supervisorMember = memberAgents.find((member: any) => {
|
|
92
|
+
const agent = member.agent || member;
|
|
93
|
+
const role = member.role || agent.role;
|
|
94
|
+
return role === 'supervisor';
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Prepare supervisor config
|
|
98
|
+
let supervisorConfig;
|
|
99
|
+
if (supervisorMember) {
|
|
100
|
+
// Type assertion needed because actual API data structure differs from type definition
|
|
101
|
+
const member = supervisorMember as any;
|
|
102
|
+
const agent = member.agent || member;
|
|
103
|
+
const currentVersion = member.currentVersion || member;
|
|
104
|
+
const rawConfig = {
|
|
105
|
+
avatar: currentVersion.avatar,
|
|
106
|
+
backgroundColor: currentVersion.backgroundColor,
|
|
107
|
+
description: currentVersion.description,
|
|
108
|
+
model: currentVersion.config?.model || currentVersion.model,
|
|
109
|
+
params: currentVersion.config?.params || currentVersion.params,
|
|
110
|
+
provider: currentVersion.config?.provider || currentVersion.provider,
|
|
111
|
+
systemRole:
|
|
112
|
+
currentVersion.config?.systemRole ||
|
|
113
|
+
currentVersion.config?.systemPrompt ||
|
|
114
|
+
currentVersion.systemRole ||
|
|
115
|
+
currentVersion.content,
|
|
116
|
+
tags: currentVersion.tags,
|
|
117
|
+
title: currentVersion.name || agent.name || 'Supervisor',
|
|
118
|
+
};
|
|
119
|
+
// Filter out null/undefined values
|
|
120
|
+
supervisorConfig = Object.fromEntries(
|
|
121
|
+
// eslint-disable-next-line eqeqeq, @typescript-eslint/no-unused-vars
|
|
122
|
+
Object.entries(rawConfig).filter(([_, v]) => v != null),
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
90
126
|
// Prepare group config
|
|
91
127
|
const groupConfig = {
|
|
92
128
|
config: {
|
|
@@ -95,30 +131,46 @@ const AddGroupAgent = memo<{ mobile?: boolean }>(() => {
|
|
|
95
131
|
openingQuestions: config.openingQuestions,
|
|
96
132
|
revealDM: config.revealDM,
|
|
97
133
|
},
|
|
98
|
-
content
|
|
134
|
+
// Group content is the supervisor's systemRole (for backward compatibility)
|
|
135
|
+
content: supervisorConfig?.systemRole || config.systemRole,
|
|
99
136
|
...meta,
|
|
100
137
|
};
|
|
101
138
|
|
|
102
139
|
// Prepare member agents from market data
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
140
|
+
// Filter out supervisor role as it will be created separately using supervisorConfig
|
|
141
|
+
const members = memberAgents
|
|
142
|
+
.filter((member: any) => {
|
|
143
|
+
const agent = member.agent || member;
|
|
144
|
+
const role = member.role || agent.role;
|
|
145
|
+
return role !== 'supervisor';
|
|
146
|
+
})
|
|
147
|
+
.map((member: any) => {
|
|
148
|
+
const agent = member.agent || member;
|
|
149
|
+
const currentVersion = member.currentVersion || member;
|
|
150
|
+
return {
|
|
151
|
+
avatar: currentVersion.avatar,
|
|
152
|
+
backgroundColor: currentVersion.backgroundColor,
|
|
153
|
+
description: currentVersion.description,
|
|
154
|
+
model: currentVersion.config?.model || currentVersion.model,
|
|
155
|
+
plugins: currentVersion.plugins,
|
|
156
|
+
provider: currentVersion.config?.provider || currentVersion.provider,
|
|
157
|
+
systemRole:
|
|
158
|
+
currentVersion.config?.systemRole ||
|
|
159
|
+
currentVersion.config?.systemPrompt ||
|
|
160
|
+
currentVersion.systemRole ||
|
|
161
|
+
currentVersion.content,
|
|
162
|
+
tags: currentVersion.tags,
|
|
163
|
+
title: currentVersion.name || agent.name,
|
|
164
|
+
};
|
|
165
|
+
});
|
|
118
166
|
|
|
119
167
|
try {
|
|
120
168
|
// Create group with all members in one request
|
|
121
|
-
const result = await chatGroupService.createGroupWithMembers(
|
|
169
|
+
const result = await chatGroupService.createGroupWithMembers(
|
|
170
|
+
groupConfig,
|
|
171
|
+
members,
|
|
172
|
+
supervisorConfig,
|
|
173
|
+
);
|
|
122
174
|
|
|
123
175
|
// Refresh group list
|
|
124
176
|
await loadGroups();
|
|
@@ -35,7 +35,7 @@ const McpDetailPage = memo<McpDetailPageProps>(({ mobile }) => {
|
|
|
35
35
|
return (
|
|
36
36
|
<TocProvider>
|
|
37
37
|
<DetailProvider config={data}>
|
|
38
|
-
<Flexbox gap={16}>
|
|
38
|
+
<Flexbox data-testid="mcp-detail-content" gap={16}>
|
|
39
39
|
<Header mobile={mobile} />
|
|
40
40
|
<Details mobile={mobile} />
|
|
41
41
|
</Flexbox>
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { ActionIcon, DropdownMenu } from '@lobehub/ui';
|
|
2
2
|
import { MoreHorizontal } from 'lucide-react';
|
|
3
|
-
import { memo } from 'react';
|
|
3
|
+
import { memo, useState } from 'react';
|
|
4
4
|
|
|
5
5
|
import { useTopicActionsDropdownMenu } from './useDropdownMenu';
|
|
6
6
|
|
|
7
7
|
const Actions = memo(() => {
|
|
8
|
-
const
|
|
8
|
+
const [open, setOpen] = useState(false);
|
|
9
|
+
const menuItems = useTopicActionsDropdownMenu({ onUploadClose: () => setOpen(false) });
|
|
9
10
|
|
|
10
11
|
return (
|
|
11
|
-
<DropdownMenu items={menuItems}>
|
|
12
|
+
<DropdownMenu items={menuItems} onOpenChange={setOpen} open={open}>
|
|
12
13
|
<ActionIcon icon={MoreHorizontal} size={'small'} />
|
|
13
14
|
</DropdownMenu>
|
|
14
15
|
);
|
|
@@ -21,9 +21,16 @@ const hotArea = css`
|
|
|
21
21
|
}
|
|
22
22
|
`;
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
interface UseTopicActionsDropdownMenuOptions {
|
|
25
|
+
onUploadClose?: () => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const useTopicActionsDropdownMenu = (
|
|
29
|
+
options: UseTopicActionsDropdownMenuOptions = {},
|
|
30
|
+
): MenuProps['items'] => {
|
|
25
31
|
const { t } = useTranslation(['topic', 'common']);
|
|
26
32
|
const { modal } = App.useApp();
|
|
33
|
+
const { onUploadClose } = options;
|
|
27
34
|
|
|
28
35
|
const [removeUnstarredTopic, removeAllTopic, importTopic] = useChatStore((s) => [
|
|
29
36
|
s.removeUnstarredTopic,
|
|
@@ -33,6 +40,7 @@ export const useTopicActionsDropdownMenu = (): MenuProps['items'] => {
|
|
|
33
40
|
|
|
34
41
|
const handleImport = useCallback(
|
|
35
42
|
async (file: File) => {
|
|
43
|
+
onUploadClose?.();
|
|
36
44
|
try {
|
|
37
45
|
const text = await file.text();
|
|
38
46
|
// Validate JSON format
|
|
@@ -46,7 +54,7 @@ export const useTopicActionsDropdownMenu = (): MenuProps['items'] => {
|
|
|
46
54
|
}
|
|
47
55
|
return false; // Prevent default upload behavior
|
|
48
56
|
},
|
|
49
|
-
[importTopic, modal, t],
|
|
57
|
+
[importTopic, modal, onUploadClose, t],
|
|
50
58
|
);
|
|
51
59
|
|
|
52
60
|
const [topicDisplayMode, updatePreference] = useUserStore((s) => [
|
|
@@ -101,6 +109,7 @@ export const useTopicActionsDropdownMenu = (): MenuProps['items'] => {
|
|
|
101
109
|
<div className={cx(hotArea)}>{t('actions.import')}</div>
|
|
102
110
|
</Upload>
|
|
103
111
|
),
|
|
112
|
+
...(onUploadClose ? { closeOnClick: false } : null),
|
|
104
113
|
},
|
|
105
114
|
{
|
|
106
115
|
type: 'divider' as const,
|
|
@@ -143,6 +152,7 @@ export const useTopicActionsDropdownMenu = (): MenuProps['items'] => {
|
|
|
143
152
|
updatePreference,
|
|
144
153
|
updateSystemStatus,
|
|
145
154
|
handleImport,
|
|
155
|
+
onUploadClose,
|
|
146
156
|
removeUnstarredTopic,
|
|
147
157
|
removeAllTopic,
|
|
148
158
|
t,
|
|
@@ -11,10 +11,10 @@ import { useSendMenuItems } from './useSendMenuItems';
|
|
|
11
11
|
const leftActions: ActionKeys[] = [
|
|
12
12
|
'model',
|
|
13
13
|
'search',
|
|
14
|
-
'typo',
|
|
15
14
|
'fileUpload',
|
|
15
|
+
'tools',
|
|
16
16
|
'---',
|
|
17
|
-
['
|
|
17
|
+
['typo', 'params', 'clear'],
|
|
18
18
|
'mainToken',
|
|
19
19
|
];
|
|
20
20
|
|
|
@@ -37,8 +37,8 @@ const AgentItem = memo<AgentItemProps>(({ item, style, className }) => {
|
|
|
37
37
|
s.agentUpdatingId === id,
|
|
38
38
|
]);
|
|
39
39
|
|
|
40
|
-
// Separate loading state from chat store - only
|
|
41
|
-
const isLoading = useChatStore(operationSelectors.
|
|
40
|
+
// Separate loading state from chat store - only show loading for this specific agent
|
|
41
|
+
const isLoading = useChatStore(operationSelectors.isAgentRunning(id));
|
|
42
42
|
|
|
43
43
|
// Get display title with fallback
|
|
44
44
|
const displayTitle = title || t('untitledAgent');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { validateVideoFileSize } from '@lobechat/utils/client';
|
|
2
|
-
import { Icon, type ItemType,
|
|
2
|
+
import { Icon, type ItemType, Tooltip } from '@lobehub/ui';
|
|
3
3
|
import { Upload } from 'antd';
|
|
4
4
|
import { css, cx } from 'antd-style';
|
|
5
5
|
import isEqual from 'fast-deep-equal';
|
|
@@ -21,6 +21,7 @@ import { preferenceSelectors } from '@/store/user/selectors';
|
|
|
21
21
|
|
|
22
22
|
import { useAgentId } from '../../hooks/useAgentId';
|
|
23
23
|
import Action from '../components/Action';
|
|
24
|
+
import type { ActionDropdownMenuItems } from '../components/ActionDropdown';
|
|
24
25
|
import CheckboxItem from '../components/CheckboxWithLoading';
|
|
25
26
|
|
|
26
27
|
const hotArea = css`
|
|
@@ -48,6 +49,7 @@ const FileUpload = memo(() => {
|
|
|
48
49
|
s.updateGuideState,
|
|
49
50
|
]);
|
|
50
51
|
const [modalOpen, setModalOpen] = useState(false);
|
|
52
|
+
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
51
53
|
const [updating, setUpdating] = useState(false);
|
|
52
54
|
|
|
53
55
|
const files = useAgentStore((s) => agentByIdSelectors.getAgentFilesById(agentId)(s), isEqual);
|
|
@@ -61,8 +63,9 @@ const FileUpload = memo(() => {
|
|
|
61
63
|
s.toggleKnowledgeBase,
|
|
62
64
|
]);
|
|
63
65
|
|
|
64
|
-
const uploadItems:
|
|
66
|
+
const uploadItems: ActionDropdownMenuItems = [
|
|
65
67
|
{
|
|
68
|
+
closeOnClick: false,
|
|
66
69
|
disabled: !canUploadImage,
|
|
67
70
|
icon: ImageUp,
|
|
68
71
|
key: 'upload-image',
|
|
@@ -70,6 +73,7 @@ const FileUpload = memo(() => {
|
|
|
70
73
|
<Upload
|
|
71
74
|
accept={'image/*'}
|
|
72
75
|
beforeUpload={async (file) => {
|
|
76
|
+
setDropdownOpen(false);
|
|
73
77
|
await upload([file]);
|
|
74
78
|
|
|
75
79
|
return false;
|
|
@@ -86,6 +90,7 @@ const FileUpload = memo(() => {
|
|
|
86
90
|
),
|
|
87
91
|
},
|
|
88
92
|
{
|
|
93
|
+
closeOnClick: false,
|
|
89
94
|
icon: FileUp,
|
|
90
95
|
key: 'upload-file',
|
|
91
96
|
label: (
|
|
@@ -105,6 +110,7 @@ const FileUpload = memo(() => {
|
|
|
105
110
|
return false;
|
|
106
111
|
}
|
|
107
112
|
|
|
113
|
+
setDropdownOpen(false);
|
|
108
114
|
await upload([file]);
|
|
109
115
|
|
|
110
116
|
return false;
|
|
@@ -117,6 +123,7 @@ const FileUpload = memo(() => {
|
|
|
117
123
|
),
|
|
118
124
|
},
|
|
119
125
|
{
|
|
126
|
+
closeOnClick: false,
|
|
120
127
|
icon: FolderUp,
|
|
121
128
|
key: 'upload-folder',
|
|
122
129
|
label: (
|
|
@@ -136,6 +143,7 @@ const FileUpload = memo(() => {
|
|
|
136
143
|
return false;
|
|
137
144
|
}
|
|
138
145
|
|
|
146
|
+
setDropdownOpen(false);
|
|
139
147
|
await upload([file]);
|
|
140
148
|
|
|
141
149
|
return false;
|
|
@@ -214,7 +222,7 @@ const FileUpload = memo(() => {
|
|
|
214
222
|
},
|
|
215
223
|
);
|
|
216
224
|
|
|
217
|
-
const items:
|
|
225
|
+
const items: ActionDropdownMenuItems = [
|
|
218
226
|
...uploadItems,
|
|
219
227
|
...(knowledgeItems.length > 0 ? knowledgeItems : []),
|
|
220
228
|
];
|
|
@@ -229,6 +237,8 @@ const FileUpload = memo(() => {
|
|
|
229
237
|
}}
|
|
230
238
|
icon={Paperclip}
|
|
231
239
|
loading={updating}
|
|
240
|
+
onOpenChange={setDropdownOpen}
|
|
241
|
+
open={dropdownOpen}
|
|
232
242
|
showTooltip={false}
|
|
233
243
|
title={t('upload.action.tooltip')}
|
|
234
244
|
trigger={'both'}
|