@lobehub/lobehub 2.0.0-next.266 → 2.0.0-next.268

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/.cursor/rules/microcopy-cn.mdc +75 -63
  2. package/.cursor/rules/microcopy-en.mdc +4 -8
  3. package/CHANGELOG.md +50 -0
  4. package/README.md +8 -8
  5. package/README.zh-CN.md +8 -8
  6. package/apps/desktop/src/main/locales/default/common.ts +2 -2
  7. package/changelog/v1.json +10 -0
  8. package/docs/development/database-schema.dbml +4 -0
  9. package/e2e/CLAUDE.md +43 -81
  10. package/e2e/cucumber.config.js +1 -0
  11. package/e2e/docs/local-setup.md +67 -219
  12. package/e2e/scripts/setup.ts +529 -0
  13. package/e2e/src/features/home/sidebarAgent.feature +62 -0
  14. package/e2e/src/features/home/sidebarGroup.feature +62 -0
  15. package/e2e/src/features/page/README.md +118 -0
  16. package/e2e/src/features/page/crud.feature +62 -0
  17. package/e2e/src/features/page/editor-content.feature +93 -0
  18. package/e2e/src/features/page/editor-meta.feature +60 -0
  19. package/e2e/src/steps/agent/conversation.steps.ts +4 -4
  20. package/e2e/src/steps/home/sidebarAgent.steps.ts +370 -0
  21. package/e2e/src/steps/home/sidebarGroup.steps.ts +168 -0
  22. package/e2e/src/steps/hooks.ts +4 -0
  23. package/e2e/src/steps/page/editor-content.steps.ts +344 -0
  24. package/e2e/src/steps/page/editor-meta.steps.ts +410 -0
  25. package/e2e/src/steps/page/page-crud.steps.ts +363 -0
  26. package/e2e/src/support/world.ts +12 -0
  27. package/locales/ar/file.json +2 -0
  28. package/locales/bg-BG/file.json +2 -0
  29. package/locales/de-DE/file.json +2 -0
  30. package/locales/en-US/auth.json +1 -1
  31. package/locales/en-US/file.json +2 -0
  32. package/locales/en-US/metadata.json +2 -2
  33. package/locales/es-ES/file.json +2 -0
  34. package/locales/fa-IR/file.json +2 -0
  35. package/locales/fr-FR/file.json +2 -0
  36. package/locales/it-IT/file.json +2 -0
  37. package/locales/ja-JP/file.json +2 -0
  38. package/locales/ko-KR/file.json +2 -0
  39. package/locales/nl-NL/file.json +2 -0
  40. package/locales/pl-PL/file.json +2 -0
  41. package/locales/pt-BR/file.json +2 -0
  42. package/locales/ru-RU/file.json +2 -0
  43. package/locales/tr-TR/file.json +2 -0
  44. package/locales/vi-VN/file.json +2 -0
  45. package/locales/zh-CN/file.json +2 -0
  46. package/locales/zh-TW/file.json +2 -0
  47. package/package.json +3 -3
  48. package/packages/builtin-agents/src/agents/agent-builder/index.ts +1 -1
  49. package/packages/builtin-agents/src/agents/group-agent-builder/index.ts +1 -1
  50. package/packages/builtin-agents/src/agents/page-agent/index.ts +1 -1
  51. package/packages/const/src/settings/group.ts +0 -10
  52. package/packages/database/migrations/0068_update_group_data.sql +4 -0
  53. package/packages/database/migrations/meta/0068_snapshot.json +9588 -0
  54. package/packages/database/migrations/meta/_journal.json +7 -0
  55. package/packages/database/src/models/__tests__/chatGroup.test.ts +5 -7
  56. package/packages/database/src/models/__tests__/knowledgeBase.test.ts +185 -0
  57. package/packages/database/src/models/knowledgeBase.ts +67 -3
  58. package/packages/database/src/repositories/agentGroup/index.test.ts +23 -29
  59. package/packages/database/src/repositories/agentGroup/index.ts +4 -9
  60. package/packages/database/src/repositories/knowledge/index.ts +3 -3
  61. package/packages/database/src/schemas/chatGroup.ts +4 -3
  62. package/packages/database/src/types/chatGroup.ts +0 -7
  63. package/packages/types/src/agentGroup/index.ts +30 -9
  64. package/packages/utils/src/multimodalContent.test.ts +302 -0
  65. package/packages/utils/src/server/__tests__/sse.test.ts +353 -0
  66. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentGroupItem/Editing.tsx +4 -11
  67. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentGroupItem/index.tsx +3 -3
  68. package/src/app/[variants]/(main)/home/_layout/Body/Agent/ModalProvider.tsx +9 -32
  69. package/src/app/[variants]/(main)/home/_layout/hooks/useCreateMenuItems.tsx +3 -37
  70. package/src/app/[variants]/(main)/home/_layout/hooks/useSessionGroupMenuItems.tsx +7 -53
  71. package/src/app/[variants]/(main)/home/features/RecentPage/List.tsx +2 -1
  72. package/src/app/[variants]/(main)/resource/features/DndContextWrapper.tsx +1 -1
  73. package/src/app/[variants]/(main)/resource/library/_layout/Sidebar.tsx +2 -2
  74. package/src/app/[variants]/(main)/resource/library/features/LibraryMenu.tsx +2 -2
  75. package/src/app/[variants]/(mobile)/chat/settings/features/SettingButton.tsx +2 -12
  76. package/src/components/ChatGroupWizard/ChatGroupWizard.tsx +5 -27
  77. package/src/components/DragUpload/index.tsx +24 -27
  78. package/src/components/MemberSelectionModal/MemberSelectionModal.tsx +2 -11
  79. package/src/features/ChatInput/ActionBar/Params/Controls.tsx +42 -7
  80. package/src/features/CommandMenu/useCommandMenu.ts +4 -14
  81. package/src/features/ResourceManager/components/Editor/index.tsx +2 -3
  82. package/src/features/ResourceManager/components/Explorer/Header/index.tsx +13 -17
  83. package/src/features/ResourceManager/components/Explorer/ItemDropdown/useFileItemDropdown.tsx +1 -1
  84. package/src/features/ResourceManager/components/Explorer/ListView/ListItem/TruncatedFileName.tsx +130 -0
  85. package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +36 -4
  86. package/src/features/ResourceManager/components/Explorer/ListView/Skeleton.tsx +4 -3
  87. package/src/features/ResourceManager/components/Explorer/ListView/index.tsx +58 -2
  88. package/src/features/ResourceManager/components/Explorer/MasonryView/index.tsx +58 -6
  89. package/src/features/ResourceManager/components/Explorer/MoveToFolderModal.tsx +2 -5
  90. package/src/features/ResourceManager/components/Explorer/ToolBar/BatchActionsDropdown.tsx +9 -5
  91. package/src/features/ResourceManager/components/Explorer/index.tsx +11 -56
  92. package/src/features/ResourceManager/components/Header/AddButton.tsx +5 -6
  93. package/src/features/ResourceManager/components/LibraryHierarchy/HierarchyNode.tsx +382 -0
  94. package/src/features/ResourceManager/components/LibraryHierarchy/index.tsx +396 -0
  95. package/src/features/ResourceManager/components/LibraryHierarchy/styles.ts +19 -0
  96. package/src/features/ResourceManager/components/LibraryHierarchy/treeState.ts +178 -0
  97. package/src/features/ResourceManager/components/LibraryHierarchy/types.ts +10 -0
  98. package/src/features/ResourceManager/index.tsx +3 -0
  99. package/src/layout/GlobalProvider/GroupWizardProvider.tsx +6 -29
  100. package/src/locales/default/auth.ts +1 -1
  101. package/src/locales/default/file.ts +2 -0
  102. package/src/locales/default/metadata.ts +2 -2
  103. package/src/server/modules/AgentRuntime/AgentRuntimeCoordinator.ts +30 -30
  104. package/src/server/modules/AgentRuntime/AgentStateManager.ts +23 -23
  105. package/src/server/modules/AgentRuntime/InMemoryAgentStateManager.ts +16 -16
  106. package/src/server/modules/AgentRuntime/InMemoryStreamEventManager.ts +13 -13
  107. package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +2 -2
  108. package/src/server/modules/AgentRuntime/StreamEventManager.ts +18 -18
  109. package/src/server/modules/AgentRuntime/types.ts +21 -21
  110. package/src/server/routers/lambda/__tests__/agentGroup.test.ts +8 -8
  111. package/src/server/routers/lambda/agentGroup.ts +10 -12
  112. package/src/server/services/document/index.ts +1 -0
  113. package/src/store/agentGroup/slices/curd.test.ts +4 -4
  114. package/src/store/file/slices/fileManager/action.ts +12 -4
  115. package/src/store/home/slices/homeInput/action.ts +0 -3
  116. package/src/store/home/slices/sidebarUI/action.ts +9 -0
  117. package/src/store/session/slices/session/action.ts +5 -9
  118. package/src/app/[variants]/(mobile)/chat/settings/features/AgentTeamSettings/index.tsx +0 -95
  119. package/src/features/GroupChatSettings/AgentCard.tsx +0 -154
  120. package/src/features/GroupChatSettings/AgentTeamChatSettings.tsx +0 -179
  121. package/src/features/GroupChatSettings/AgentTeamMembersSettings.tsx +0 -244
  122. package/src/features/GroupChatSettings/AgentTeamMetaSettings.tsx +0 -94
  123. package/src/features/GroupChatSettings/AgentTeamSettings.tsx +0 -54
  124. package/src/features/GroupChatSettings/GroupCategory/index.tsx +0 -30
  125. package/src/features/GroupChatSettings/GroupCategory/useGroupCategory.tsx +0 -42
  126. package/src/features/GroupChatSettings/GroupChatSettingsProvider.tsx +0 -19
  127. package/src/features/GroupChatSettings/HostMemberCard.tsx +0 -113
  128. package/src/features/GroupChatSettings/StoreUpdater.tsx +0 -34
  129. package/src/features/GroupChatSettings/hooks/useGroupChatSettings.ts +0 -25
  130. package/src/features/GroupChatSettings/index.ts +0 -16
  131. package/src/features/GroupChatSettings/store/action.ts +0 -105
  132. package/src/features/GroupChatSettings/store/index.ts +0 -18
  133. package/src/features/GroupChatSettings/store/initialState.ts +0 -23
  134. package/src/features/GroupChatSettings/store/selectors.ts +0 -13
  135. package/src/features/ResourceManager/components/Tree/index.tsx +0 -883
  136. /package/src/features/ResourceManager/components/{Tree → LibraryHierarchy}/TreeSkeleton.tsx +0 -0
@@ -1,154 +0,0 @@
1
- 'use client';
2
-
3
- import { Avatar, Flexbox, Icon, Skeleton, Text, Tooltip } from '@lobehub/ui';
4
- import { Switch } from 'antd';
5
- import { createStaticStyles, cssVar, cx } from 'antd-style';
6
- import { Bot, Loader2 } from 'lucide-react';
7
- import { memo } from 'react';
8
- import { useTranslation } from 'react-i18next';
9
-
10
- import { DEFAULT_AVATAR } from '@/const/meta';
11
- import { useIsDark } from '@/hooks/useIsDark';
12
- import { type LobeAgentSession } from '@/types/session';
13
-
14
- const styles = createStaticStyles(({ css }) => ({
15
- container: css`
16
- position: relative;
17
-
18
- overflow: hidden;
19
-
20
- height: 100%;
21
- border-radius: 12px;
22
-
23
- background: ${cssVar.colorBgContainer};
24
-
25
- transition: border-color 0.2s ${cssVar.motionEaseInOut};
26
-
27
- &:hover {
28
- border-color: ${cssVar.colorPrimary};
29
- }
30
- `,
31
- containerDark: css`
32
- border: 1px solid ${cssVar.colorBorder};
33
- `,
34
- containerLight: css`
35
- border: 1px solid ${cssVar.colorBorderSecondary};
36
- `,
37
- desc: css`
38
- overflow: hidden;
39
-
40
- height: 3em;
41
- margin-block-end: 0 !important;
42
-
43
- line-height: 1.5;
44
- color: ${cssVar.colorTextDescription};
45
- `,
46
- title: css`
47
- line-height: 1.3;
48
- `,
49
- }));
50
-
51
- interface AgentCardProps {
52
- agent: LobeAgentSession;
53
- inGroup: boolean;
54
- isHost?: boolean;
55
- loading?: boolean;
56
- onAction: (agentId: string, action: 'add' | 'remove') => void;
57
- operationLoading?: boolean;
58
- }
59
-
60
- const AgentCard = memo<AgentCardProps>(
61
- ({ agent, inGroup, isHost, loading, onAction, operationLoading }) => {
62
- const { t } = useTranslation('setting');
63
- const isDarkMode = useIsDark();
64
-
65
- if (loading) {
66
- return (
67
- <Flexbox
68
- className={cx(
69
- styles.container,
70
- isDarkMode ? styles.containerDark : styles.containerLight,
71
- )}
72
- gap={24}
73
- padding={16}
74
- >
75
- <Skeleton active />
76
- </Flexbox>
77
- );
78
- }
79
-
80
- const agentId = agent.config?.id;
81
- const title = agent.meta?.title || t('settingGroupMembers.defaultAgent');
82
- const description = agent.meta?.description || '';
83
- const avatar = agent.meta?.avatar || DEFAULT_AVATAR;
84
- const avatarBackground = agent.meta?.backgroundColor;
85
-
86
- if (!agentId) return null;
87
-
88
- const handleAction = (checked: boolean) => {
89
- onAction(agentId, checked ? 'add' : 'remove');
90
- };
91
-
92
- return (
93
- <Flexbox
94
- className={cx(styles.container, isDarkMode ? styles.containerDark : styles.containerLight)}
95
- gap={24}
96
- >
97
- <Flexbox gap={12} padding={16} width={'100%'}>
98
- <Flexbox gap={12} width={'100%'}>
99
- <Flexbox align={'center'} horizontal justify={'space-between'}>
100
- <Flexbox align={'center'} flex={1} gap={8} horizontal style={{ minWidth: 0 }}>
101
- <Avatar
102
- avatar={avatar}
103
- background={avatarBackground}
104
- shape={'square'}
105
- size={24}
106
- style={{ flexShrink: 0 }}
107
- />
108
- <Text
109
- className={styles.title}
110
- ellipsis
111
- style={{ fontSize: 16, fontWeight: 'bold', minWidth: 0 }}
112
- >
113
- {title}
114
- </Text>
115
- {isHost && (
116
- <Tooltip title={t('settingGroupMembers.groupHost')}>
117
- <Icon icon={Bot} size="small" style={{ color: '#1890ff' }} />
118
- </Tooltip>
119
- )}
120
- </Flexbox>
121
- </Flexbox>
122
- <Text
123
- className={styles.desc}
124
- ellipsis={{
125
- rows: 2,
126
- }}
127
- >
128
- {description || t('settingGroupMembers.noDescription')}
129
- </Text>
130
- </Flexbox>
131
- <Flexbox align="center" horizontal justify={'space-between'} width={'100%'}>
132
- <Icon icon={Loader2} size="small" spin style={{ opacity: operationLoading ? 1 : 0 }} />
133
- <Tooltip
134
- title={
135
- inGroup
136
- ? t('settingGroupMembers.removeFromGroup')
137
- : t('settingGroupMembers.addToGroup')
138
- }
139
- >
140
- <Switch
141
- checked={inGroup}
142
- disabled={operationLoading}
143
- onChange={handleAction}
144
- size="small"
145
- />
146
- </Tooltip>
147
- </Flexbox>
148
- </Flexbox>
149
- </Flexbox>
150
- );
151
- },
152
- );
153
-
154
- export default AgentCard;
@@ -1,179 +0,0 @@
1
- 'use client';
2
-
3
- import {
4
- Form,
5
- type FormGroupItemType,
6
- Icon,
7
- Segmented,
8
- Select,
9
- SliderWithInput,
10
- } from '@lobehub/ui';
11
- import { Form as AntdForm, App, Input, Switch } from 'antd';
12
- import { isEqual } from 'es-toolkit/compat';
13
- import { Coffee, Rabbit, Turtle } from 'lucide-react';
14
- import { memo } from 'react';
15
- import { useTranslation } from 'react-i18next';
16
-
17
- import { FORM_STYLE } from '@/const/layoutTokens';
18
-
19
- import ModelSelect from '../ModelSelect';
20
- import { selectors, useStore } from './store';
21
-
22
- const { TextArea } = Input;
23
-
24
- /**
25
- * Chat Settings for Agent Team (Group Chat)
26
- */
27
- const AgentTeamChatSettings = memo(() => {
28
- const { t } = useTranslation(['setting', 'common']);
29
- const [form] = Form.useForm();
30
- const updateConfig = useStore((s) => s.updateGroupConfig);
31
- const config = useStore(selectors.currentChatConfig, isEqual);
32
-
33
- const { message } = App.useApp();
34
-
35
- // Watch the allowDM value to conditionally show revealDM
36
- const allowDM = AntdForm.useWatch('allowDM', form);
37
- // Watch the enableSupervisor value to conditionally show host options
38
- const enableSupervisor = AntdForm.useWatch('enableSupervisor', form);
39
-
40
- const responseSpeedOptions = [
41
- {
42
- icon: <Icon icon={Turtle} size={16} />,
43
- label: t('settingGroupChat.responseSpeed.options.slow'),
44
- value: 'slow',
45
- },
46
- {
47
- icon: <Icon icon={Coffee} size={16} />,
48
- label: t('settingGroupChat.responseSpeed.options.medium'),
49
- value: 'medium',
50
- },
51
- {
52
- icon: <Icon icon={Rabbit} size={16} />,
53
- label: t('settingGroupChat.responseSpeed.options.fast'),
54
- value: 'fast',
55
- },
56
- ];
57
-
58
- const supervisorOptions: FormGroupItemType = {
59
- children: [
60
- {
61
- children: <Switch />,
62
- desc: t('settingGroupChat.enableSupervisor.desc'),
63
- divider: false,
64
- label: t('settingGroupChat.enableSupervisor.title'),
65
- name: 'enableSupervisor',
66
- },
67
- // Only show other options when enableSupervisor is true
68
- ...(enableSupervisor
69
- ? [
70
- {
71
- children: <ModelSelect requiredAbilities={['structuredOutput']} />,
72
- desc: t('settingGroupChat.model.desc'),
73
- label: t('settingGroupChat.model.title'),
74
- name: '_modelConfig',
75
- },
76
- {
77
- children: (
78
- <TextArea
79
- autoSize={{ maxRows: 8, minRows: 3 }}
80
- placeholder={t('settingGroupChat.systemPrompt.placeholder')}
81
- rows={4}
82
- />
83
- ),
84
- desc: t('settingGroupChat.systemPrompt.desc'),
85
- label: t('settingGroupChat.systemPrompt.title'),
86
- name: 'systemPrompt',
87
- },
88
- ]
89
- : []),
90
- ],
91
- title: t('settingGroupChat.orchestratorTitle'),
92
- };
93
-
94
- const chatOptions: FormGroupItemType = {
95
- children: [
96
- {
97
- children: <Segmented options={responseSpeedOptions} />,
98
- desc: t('settingGroupChat.responseSpeed.desc'),
99
- label: t('settingGroupChat.responseSpeed.title'),
100
- name: 'responseSpeed',
101
- },
102
- {
103
- children: (
104
- <Select
105
- options={[
106
- {
107
- label: t('settingGroupChat.responseOrder.options.sequential'),
108
- value: 'sequential',
109
- },
110
- { label: t('settingGroupChat.responseOrder.options.natural'), value: 'natural' },
111
- ]}
112
- placeholder={t('settingGroupChat.responseOrder.placeholder')}
113
- />
114
- ),
115
- desc: t('settingGroupChat.responseOrder.desc'),
116
- label: t('settingGroupChat.responseOrder.title'),
117
- name: 'responseOrder',
118
- },
119
- {
120
- children: <SliderWithInput max={32} min={0} step={1} unlimitedInput={true} />,
121
- desc: t('settingGroupChat.maxResponseInRow.desc'),
122
- divider: false,
123
- label: t('settingGroupChat.maxResponseInRow.title'),
124
- name: 'maxResponseInRow',
125
- },
126
- {
127
- children: <Switch />,
128
- desc: t('settingGroupChat.allowDM.desc'),
129
- divider: false,
130
- label: t('settingGroupChat.allowDM.title'),
131
- name: 'allowDM',
132
- },
133
- // Only show revealDM when allowDM is true
134
- ...(allowDM
135
- ? [
136
- {
137
- children: <Switch />,
138
- desc: t('settingGroupChat.revealDM.desc'),
139
- divider: false,
140
- label: t('settingGroupChat.revealDM.title'),
141
- name: 'revealDM',
142
- },
143
- ]
144
- : []),
145
- ],
146
- title: t('settingGroupChat.title'),
147
- };
148
-
149
- return (
150
- <Form
151
- footer={<Form.SubmitFooter />}
152
- form={form}
153
- initialValues={{
154
- ...config,
155
- _modelConfig: {
156
- model: config?.orchestratorModel,
157
- provider: config?.orchestratorProvider,
158
- },
159
- enableSupervisor: config?.enableSupervisor ?? true,
160
- }}
161
- items={[supervisorOptions, ...(enableSupervisor ? [chatOptions] : [])]}
162
- itemsType={'group'}
163
- onFinish={async ({ _modelConfig, ...rest }) => {
164
- await updateConfig({
165
- // Preserve existing values when _modelConfig is undefined (enableSupervisor is false)
166
- orchestratorModel: _modelConfig?.model ?? config?.orchestratorModel,
167
- orchestratorProvider: _modelConfig?.provider ?? config?.orchestratorProvider,
168
- ...rest,
169
- });
170
-
171
- message.success(t('message.success'));
172
- }}
173
- variant={'borderless'}
174
- {...FORM_STYLE}
175
- />
176
- );
177
- });
178
-
179
- export default AgentTeamChatSettings;
@@ -1,244 +0,0 @@
1
- 'use client';
2
-
3
- import { ActionIcon, Flexbox, Grid, Tag, Text } from '@lobehub/ui';
4
- import { createStaticStyles } from 'antd-style';
5
- import { Plus } from 'lucide-react';
6
- import { memo, useMemo, useState } from 'react';
7
- import { useTranslation } from 'react-i18next';
8
-
9
- import { DEFAULT_AVATAR } from '@/const/meta';
10
- import { useAgentGroupStore } from '@/store/agentGroup';
11
- import { agentGroupSelectors } from '@/store/agentGroup/selectors';
12
- import { useSessionStore } from '@/store/session';
13
- import { sessionSelectors } from '@/store/session/selectors';
14
- import { type LobeAgentSession, type LobeGroupSession, LobeSessionType } from '@/types/session';
15
-
16
- import AgentCard from './AgentCard';
17
- import HostMemberCard from './HostMemberCard';
18
-
19
- const styles = createStaticStyles(({ css }) => ({
20
- container: css`
21
- width: 100%;
22
- `,
23
- }));
24
-
25
- const HOST_MEMBER_ID = 'supervisor';
26
-
27
- const AgentTeamMembersSettings = memo(() => {
28
- const { t } = useTranslation('setting');
29
- const [loadingAgentId, setLoadingAgentId] = useState<string | null>(null);
30
- const [isCreatingMember, setIsCreatingMember] = useState(false);
31
-
32
- const activeGroupId = useSessionStore((s) => s.activeId);
33
- const currentSession = useSessionStore(sessionSelectors.currentSession) as LobeGroupSession;
34
- const groupConfig = useAgentGroupStore(agentGroupSelectors.currentGroupConfig);
35
-
36
- const addAgentsToGroup = useAgentGroupStore((s) => s.addAgentsToGroup);
37
- const removeAgentFromGroup = useAgentGroupStore((s) => s.removeAgentFromGroup);
38
- const updateGroupConfig = useAgentGroupStore((s) => s.updateGroupConfig);
39
- const refreshSessions = useSessionStore((s) => s.refreshSessions);
40
- const createSession = useSessionStore((s) => s.createSession);
41
-
42
- // Get all agent sessions
43
- const agentSessions = useSessionStore((s) => {
44
- const allSessions = s.sessions || [];
45
- return allSessions.filter(
46
- (session) => session.type === LobeSessionType.Agent,
47
- ) as LobeAgentSession[];
48
- });
49
-
50
- const currentSessionId = useSessionStore((s) => s.activeId);
51
-
52
- const isSupervisorEnabled = Boolean(groupConfig?.enableSupervisor);
53
-
54
- // Get member IDs from current session
55
- const memberIds = useMemo(() => {
56
- return currentSession?.members?.map((member: any) => member.id) || [];
57
- }, [currentSession?.members]);
58
-
59
- // Separate agents into two groups: in group and not in group
60
- const { agentsInGroup, agentsNotInGroup } = useMemo(() => {
61
- const inGroup: LobeAgentSession[] = [];
62
- const notInGroup: LobeAgentSession[] = [];
63
-
64
- agentSessions.forEach((agent) => {
65
- const agentId = agent.config?.id;
66
- if (!agentId || agent.id === currentSessionId) return; // Skip current session
67
-
68
- if (memberIds.includes(agentId)) {
69
- inGroup.push(agent);
70
- } else {
71
- notInGroup.push(agent);
72
- }
73
- });
74
-
75
- return { agentsInGroup: inGroup, agentsNotInGroup: notInGroup };
76
- }, [agentSessions, memberIds, currentSessionId]);
77
-
78
- const handleAgentAction = async (agentId: string, action: 'add' | 'remove') => {
79
- if (!activeGroupId) {
80
- console.error('No active group to perform action on');
81
- return;
82
- }
83
-
84
- // Check if this is the host member
85
- const isHostMember = agentId === HOST_MEMBER_ID;
86
-
87
- // Set loading state for this specific agent
88
- setLoadingAgentId(agentId);
89
-
90
- try {
91
- if (action === 'add') {
92
- if (isHostMember) {
93
- // Host toggle updates supervisor flag instead of modifying members
94
- await updateGroupConfig({ enableSupervisor: true });
95
- } else {
96
- await addAgentsToGroup(activeGroupId, [agentId]);
97
- }
98
- } else {
99
- if (isHostMember) {
100
- // Host toggle updates supervisor flag instead of modifying members
101
- await updateGroupConfig({ enableSupervisor: false });
102
- } else {
103
- await removeAgentFromGroup(activeGroupId, agentId);
104
- }
105
- }
106
-
107
- // Refresh session data to reflect the changes
108
- await refreshSessions();
109
- } catch (error) {
110
- console.error(`Failed to ${action} agent ${action === 'add' ? 'to' : 'from'} group:`, error);
111
- } finally {
112
- // Clear loading state
113
- setLoadingAgentId(null);
114
- }
115
- };
116
-
117
- const hostOperationLoading = loadingAgentId === HOST_MEMBER_ID;
118
-
119
- const handleHostToggle = (checked: boolean) => {
120
- handleAgentAction(HOST_MEMBER_ID, checked ? 'add' : 'remove');
121
- };
122
-
123
- const handleCreateMember = async () => {
124
- if (!activeGroupId || isCreatingMember) return;
125
-
126
- setIsCreatingMember(true);
127
-
128
- try {
129
- // Create a virtual assistant
130
- const sessionId = await createSession(
131
- {
132
- config: {
133
- virtual: true,
134
- },
135
- meta: {
136
- avatar: DEFAULT_AVATAR,
137
- description: '',
138
- title: t('settingGroupMembers.defaultAgent'),
139
- },
140
- },
141
- false, // Don't switch to the new session
142
- );
143
-
144
- // Refresh sessions to get the latest data
145
- await refreshSessions();
146
-
147
- // Get the agent ID from the created session
148
- const session = sessionSelectors.getSessionById(sessionId)(useSessionStore.getState());
149
- if (session && session.type === LobeSessionType.Agent) {
150
- const agentSession = session as LobeAgentSession;
151
- const agentId = agentSession.config?.id;
152
-
153
- if (agentId) {
154
- // Add the agent to the current group
155
- await addAgentsToGroup(activeGroupId, [agentId]);
156
- await refreshSessions();
157
- }
158
- }
159
- } catch (error) {
160
- console.error('Failed to create virtual member:', error);
161
- } finally {
162
- setIsCreatingMember(false);
163
- }
164
- };
165
-
166
- const groupMemberCount = agentsInGroup.length + (isSupervisorEnabled ? 1 : 0);
167
- const availableAgentCount = agentsNotInGroup.length + (isSupervisorEnabled ? 0 : 1);
168
-
169
- return (
170
- <Flexbox className={styles.container} gap={40}>
171
- {/* Agents in Group Section */}
172
- <Flexbox gap={24}>
173
- <Flexbox align={'center'} gap={8} horizontal justify="space-between">
174
- <Flexbox align={'center'} gap={8} horizontal>
175
- <Text strong style={{ fontSize: 18 }}>
176
- {t('settingGroupMembers.groupMembers')}
177
- </Text>
178
- <Tag>{groupMemberCount}</Tag>
179
- </Flexbox>
180
- <ActionIcon
181
- icon={Plus}
182
- loading={isCreatingMember}
183
- onClick={handleCreateMember}
184
- title={t('settingGroupMembers.createMember')}
185
- />
186
- </Flexbox>
187
- <Grid gap={16} rows={3}>
188
- {isSupervisorEnabled && (
189
- <HostMemberCard checked loading={hostOperationLoading} onToggle={handleHostToggle} />
190
- )}
191
- {agentsInGroup.map((agent) => (
192
- <AgentCard
193
- agent={agent}
194
- inGroup={true}
195
- key={agent.config?.id}
196
- onAction={handleAgentAction}
197
- operationLoading={loadingAgentId === agent.config?.id}
198
- />
199
- ))}
200
- {agentsInGroup.length === 0 && !isSupervisorEnabled && (
201
- <Text style={{ color: '#999', gridColumn: '1 / -1', padding: 40, textAlign: 'center' }}>
202
- {t('settingGroupMembers.noMembersInGroup')}
203
- </Text>
204
- )}
205
- </Grid>
206
- </Flexbox>
207
-
208
- {/* Agents not in Group Section */}
209
- <Flexbox gap={24}>
210
- <Flexbox align={'center'} gap={8} horizontal>
211
- <Text strong style={{ fontSize: 18 }}>
212
- {t('settingGroupMembers.availableAgents')}
213
- </Text>
214
- <Tag>{availableAgentCount}</Tag>
215
- </Flexbox>
216
- <Grid gap={16} rows={3}>
217
- {!isSupervisorEnabled && (
218
- <HostMemberCard
219
- checked={false}
220
- loading={hostOperationLoading}
221
- onToggle={handleHostToggle}
222
- />
223
- )}
224
- {agentsNotInGroup.map((agent) => (
225
- <AgentCard
226
- agent={agent}
227
- inGroup={false}
228
- key={agent.config?.id}
229
- onAction={handleAgentAction}
230
- operationLoading={loadingAgentId === agent.config?.id}
231
- />
232
- ))}
233
- {agentsNotInGroup.length === 0 && isSupervisorEnabled && (
234
- <Text style={{ color: '#999', gridColumn: '1 / -1', padding: 40, textAlign: 'center' }}>
235
- {t('settingGroupMembers.noAvailableAgents')}
236
- </Text>
237
- )}
238
- </Grid>
239
- </Flexbox>
240
- </Flexbox>
241
- );
242
- });
243
-
244
- export default AgentTeamMembersSettings;
@@ -1,94 +0,0 @@
1
- 'use client';
2
-
3
- import { Form, type FormGroupItemType, Icon, Segmented } from '@lobehub/ui';
4
- import { useUpdateEffect } from 'ahooks';
5
- import { Input } from 'antd';
6
- import isEqual from 'fast-deep-equal';
7
- import { Briefcase, Coffee } from 'lucide-react';
8
- import { memo } from 'react';
9
- import { useTranslation } from 'react-i18next';
10
-
11
- import { FORM_STYLE } from '@/const/layoutTokens';
12
-
13
- import { selectors, useStore } from './store';
14
-
15
- const { TextArea } = Input;
16
-
17
- const AgentTeamMetaSettings = memo(() => {
18
- const { t } = useTranslation(['setting', 'common']);
19
- const [form] = Form.useForm();
20
-
21
- const updateMeta = useStore((s) => s.updateGroupMeta);
22
- const meta = useStore(selectors.currentMetaConfig, isEqual) || {};
23
- const updateConfig = useStore((s) => s.updateGroupConfig);
24
- const config = useStore(selectors.currentChatConfig, isEqual) || {};
25
-
26
- useUpdateEffect(() => {
27
- form.setFieldsValue({ ...meta, scene: config.scene });
28
- }, [meta, config?.scene]);
29
-
30
- const groupSettings: FormGroupItemType = {
31
- children: [
32
- {
33
- children: <Input placeholder={t('settingGroup.name.placeholder')} />,
34
- label: t('settingGroup.name.title'),
35
- name: 'title',
36
- },
37
- {
38
- children: (
39
- <TextArea
40
- autoSize={{ maxRows: 10, minRows: 5 }}
41
- placeholder={t('settingGroup.description.placeholder')}
42
- rows={4}
43
- />
44
- ),
45
- label: t('settingGroup.description.title'),
46
- name: 'description',
47
- },
48
- {
49
- children: (
50
- <Segmented
51
- options={[
52
- {
53
- icon: <Icon icon={Coffee} size={16} />,
54
- label: t('settingGroup.scene.options.casual'),
55
- value: 'casual',
56
- },
57
- {
58
- icon: <Icon icon={Briefcase} size={16} />,
59
- label: t('settingGroup.scene.options.productive'),
60
- value: 'productive',
61
- },
62
- ]}
63
- />
64
- ),
65
- desc: t('settingGroup.scene.desc'),
66
- label: t('settingGroup.scene.title'),
67
- minWidth: undefined,
68
- name: 'scene',
69
- },
70
- ],
71
- title: t('settingGroup.title'),
72
- };
73
-
74
- return (
75
- <Form
76
- footer={<Form.SubmitFooter />}
77
- form={form}
78
- initialValues={{ ...meta, scene: config.scene }}
79
- items={[groupSettings]}
80
- itemsType={'group'}
81
- onFinish={async (values) => {
82
- const { scene, ...metaPayload } = values as any;
83
- await updateMeta(metaPayload);
84
- if (scene && scene !== config.scene) {
85
- await updateConfig({ scene });
86
- }
87
- }}
88
- variant={'borderless'}
89
- {...FORM_STYLE}
90
- />
91
- );
92
- });
93
-
94
- export default AgentTeamMetaSettings;