@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
|
@@ -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,
|
|
@@ -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();
|
|
@@ -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,
|
|
@@ -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'}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type DropdownMenuProps,
|
|
9
9
|
DropdownMenuRoot,
|
|
10
10
|
DropdownMenuTrigger,
|
|
11
|
+
type MenuItemType,
|
|
11
12
|
type MenuProps,
|
|
12
13
|
type PopoverTrigger,
|
|
13
14
|
renderDropdownMenuItems,
|
|
@@ -16,6 +17,7 @@ import { createStaticStyles, cx } from 'antd-style';
|
|
|
16
17
|
import {
|
|
17
18
|
type CSSProperties,
|
|
18
19
|
type ReactNode,
|
|
20
|
+
isValidElement,
|
|
19
21
|
memo,
|
|
20
22
|
useCallback,
|
|
21
23
|
useEffect,
|
|
@@ -34,8 +36,15 @@ const styles = createStaticStyles(({ css }) => ({
|
|
|
34
36
|
`,
|
|
35
37
|
}));
|
|
36
38
|
|
|
37
|
-
type
|
|
38
|
-
|
|
39
|
+
export type ActionDropdownMenuItem = MenuItemType;
|
|
40
|
+
|
|
41
|
+
export type ActionDropdownMenuItems = MenuProps<ActionDropdownMenuItem>['items'];
|
|
42
|
+
|
|
43
|
+
type ActionDropdownMenu = Omit<
|
|
44
|
+
Pick<MenuProps<ActionDropdownMenuItem>, 'className' | 'onClick' | 'style'>,
|
|
45
|
+
'items'
|
|
46
|
+
> & {
|
|
47
|
+
items: ActionDropdownMenuItems | (() => ActionDropdownMenuItems);
|
|
39
48
|
};
|
|
40
49
|
|
|
41
50
|
export interface ActionDropdownProps extends Omit<DropdownMenuProps, 'items'> {
|
|
@@ -116,7 +125,7 @@ const ActionDropdown = memo<ActionDropdownProps>(
|
|
|
116
125
|
}, [openOnHover, triggerProps]);
|
|
117
126
|
|
|
118
127
|
const decorateMenuItems = useCallback(
|
|
119
|
-
(items:
|
|
128
|
+
(items: ActionDropdownMenuItems): ActionDropdownMenuItems => {
|
|
120
129
|
if (!items) return items;
|
|
121
130
|
|
|
122
131
|
return items.map((item) => {
|
|
@@ -136,10 +145,24 @@ const ActionDropdown = memo<ActionDropdownProps>(
|
|
|
136
145
|
};
|
|
137
146
|
}
|
|
138
147
|
const itemOnClick = 'onClick' in item ? item.onClick : undefined;
|
|
148
|
+
const closeOnClick = 'closeOnClick' in item ? item.closeOnClick : undefined;
|
|
149
|
+
const keepOpenOnClick = closeOnClick === false;
|
|
150
|
+
const itemLabel = 'label' in item ? item.label : undefined;
|
|
151
|
+
const shouldKeepOpen = isValidElement(itemLabel);
|
|
152
|
+
|
|
153
|
+
const resolvedCloseOnClick = closeOnClick ?? (shouldKeepOpen ? false : undefined);
|
|
139
154
|
|
|
140
155
|
return {
|
|
141
156
|
...item,
|
|
157
|
+
...(resolvedCloseOnClick !== undefined ? { closeOnClick: resolvedCloseOnClick } : null),
|
|
142
158
|
onClick: (info) => {
|
|
159
|
+
if (keepOpenOnClick) {
|
|
160
|
+
info.domEvent.stopPropagation();
|
|
161
|
+
menu.onClick?.(info);
|
|
162
|
+
itemOnClick?.(info);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
143
166
|
info.domEvent.preventDefault();
|
|
144
167
|
menu.onClick?.(info);
|
|
145
168
|
itemOnClick?.(info);
|
|
@@ -5,7 +5,7 @@ import { Notion } from '@lobehub/icons';
|
|
|
5
5
|
import { Button, DropdownMenu, Icon, type MenuProps } from '@lobehub/ui';
|
|
6
6
|
import { Upload } from 'antd';
|
|
7
7
|
import { FilePenLine, FileUp, FolderIcon, FolderUp, Link, Plus } from 'lucide-react';
|
|
8
|
-
import { useCallback, useMemo } from 'react';
|
|
8
|
+
import { type ChangeEvent, useCallback, useMemo, useState } from 'react';
|
|
9
9
|
import { useTranslation } from 'react-i18next';
|
|
10
10
|
|
|
11
11
|
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
|
@@ -23,6 +23,7 @@ const AddButton = () => {
|
|
|
23
23
|
const pushDockFileList = useFileStore((s) => s.pushDockFileList);
|
|
24
24
|
const uploadFolderWithStructure = useFileStore((s) => s.uploadFolderWithStructure);
|
|
25
25
|
const createResourceAndSync = useFileStore((s) => s.createResourceAndSync);
|
|
26
|
+
const [menuOpen, setMenuOpen] = useState(false);
|
|
26
27
|
|
|
27
28
|
// TODO: Migrate Notion import to use createResource
|
|
28
29
|
// Keep old functions temporarily for components not yet migrated
|
|
@@ -121,6 +122,13 @@ const AddButton = () => {
|
|
|
121
122
|
t,
|
|
122
123
|
uploadFolderWithStructure,
|
|
123
124
|
});
|
|
125
|
+
const handleFolderUploadWithClose = useCallback(
|
|
126
|
+
(event: ChangeEvent<HTMLInputElement>) => {
|
|
127
|
+
setMenuOpen(false);
|
|
128
|
+
return handleFolderUpload(event);
|
|
129
|
+
},
|
|
130
|
+
[handleFolderUpload],
|
|
131
|
+
);
|
|
124
132
|
|
|
125
133
|
const items = useMemo<MenuProps['items']>(
|
|
126
134
|
() => [
|
|
@@ -144,11 +152,13 @@ const AddButton = () => {
|
|
|
144
152
|
type: 'divider',
|
|
145
153
|
},
|
|
146
154
|
{
|
|
155
|
+
closeOnClick: false,
|
|
147
156
|
icon: <Icon icon={FileUp} />,
|
|
148
157
|
key: 'upload-file',
|
|
149
158
|
label: (
|
|
150
159
|
<Upload
|
|
151
160
|
beforeUpload={async (file) => {
|
|
161
|
+
setMenuOpen(false);
|
|
152
162
|
await pushDockFileList([file], libraryId, currentFolderId ?? undefined);
|
|
153
163
|
|
|
154
164
|
return false;
|
|
@@ -161,6 +171,7 @@ const AddButton = () => {
|
|
|
161
171
|
),
|
|
162
172
|
},
|
|
163
173
|
{
|
|
174
|
+
closeOnClick: false,
|
|
164
175
|
icon: <Icon icon={FolderUp} />,
|
|
165
176
|
key: 'upload-folder',
|
|
166
177
|
label: <label htmlFor="folder-upload-input">{t('header.actions.uploadFolder')}</label>,
|
|
@@ -211,7 +222,13 @@ const AddButton = () => {
|
|
|
211
222
|
|
|
212
223
|
return (
|
|
213
224
|
<>
|
|
214
|
-
<DropdownMenu
|
|
225
|
+
<DropdownMenu
|
|
226
|
+
items={items}
|
|
227
|
+
onOpenChange={setMenuOpen}
|
|
228
|
+
open={menuOpen}
|
|
229
|
+
placement="bottomRight"
|
|
230
|
+
trigger="both"
|
|
231
|
+
>
|
|
215
232
|
<Button data-no-highlight icon={Plus} type="primary">
|
|
216
233
|
{t('addLibrary')}
|
|
217
234
|
</Button>
|
|
@@ -233,7 +250,7 @@ const AddButton = () => {
|
|
|
233
250
|
<input
|
|
234
251
|
id="folder-upload-input"
|
|
235
252
|
multiple
|
|
236
|
-
onChange={
|
|
253
|
+
onChange={handleFolderUploadWithClose}
|
|
237
254
|
style={{ display: 'none' }}
|
|
238
255
|
type="file"
|
|
239
256
|
// @ts-expect-error - webkitdirectory is not in the React types
|
|
@@ -129,6 +129,19 @@ export const agentGroupRouter = router({
|
|
|
129
129
|
})
|
|
130
130
|
.partial(),
|
|
131
131
|
),
|
|
132
|
+
supervisorConfig: z
|
|
133
|
+
.object({
|
|
134
|
+
avatar: z.string().nullish(),
|
|
135
|
+
backgroundColor: z.string().nullish(),
|
|
136
|
+
description: z.string().nullish(),
|
|
137
|
+
model: z.string().nullish(),
|
|
138
|
+
params: z.any().nullish(),
|
|
139
|
+
provider: z.string().nullish(),
|
|
140
|
+
systemRole: z.string().nullish(),
|
|
141
|
+
tags: z.array(z.string()).nullish(),
|
|
142
|
+
title: z.string().nullish(),
|
|
143
|
+
})
|
|
144
|
+
.optional(),
|
|
132
145
|
}),
|
|
133
146
|
)
|
|
134
147
|
.mutation(async ({ input, ctx }) => {
|
|
@@ -144,6 +157,14 @@ export const agentGroupRouter = router({
|
|
|
144
157
|
const memberAgentIds = createdAgents.map((agent) => agent.id);
|
|
145
158
|
|
|
146
159
|
// 2. Create group with supervisor and member agents
|
|
160
|
+
// Filter out null/undefined values from supervisorConfig
|
|
161
|
+
const supervisorConfig = input.supervisorConfig
|
|
162
|
+
? Object.fromEntries(
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, eqeqeq
|
|
164
|
+
Object.entries(input.supervisorConfig).filter(([_, v]) => v != null),
|
|
165
|
+
)
|
|
166
|
+
: undefined;
|
|
167
|
+
|
|
147
168
|
const { group, supervisorAgentId } = await ctx.agentGroupRepo.createGroupWithSupervisor(
|
|
148
169
|
{
|
|
149
170
|
...input.groupConfig,
|
|
@@ -152,6 +173,7 @@ export const agentGroupRouter = router({
|
|
|
152
173
|
),
|
|
153
174
|
},
|
|
154
175
|
memberAgentIds,
|
|
176
|
+
supervisorConfig as any,
|
|
155
177
|
);
|
|
156
178
|
|
|
157
179
|
return { agentIds: memberAgentIds, groupId: group.id, supervisorAgentId };
|