@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
@@ -23,26 +23,13 @@ interface AgentModalContextValue {
23
23
 
24
24
  interface GroupWizardCallbacks {
25
25
  onCancel?: () => void;
26
- onCreateCustom?: (
27
- selectedAgents: string[],
28
- hostConfig?: { model?: string; provider?: string },
29
- enableSupervisor?: boolean,
30
- ) => Promise<void>;
31
- onCreateFromTemplate?: (
32
- templateId: string,
33
- hostConfig?: { model?: string; provider?: string },
34
- enableSupervisor?: boolean,
35
- selectedMemberTitles?: string[],
36
- ) => Promise<void>;
26
+ onCreateCustom?: (selectedAgents: string[]) => Promise<void>;
27
+ onCreateFromTemplate?: (templateId: string, selectedMemberTitles?: string[]) => Promise<void>;
37
28
  }
38
29
 
39
30
  interface MemberSelectionCallbacks {
40
31
  onCancel?: () => void;
41
- onConfirm?: (
42
- selectedAgents: string[],
43
- hostConfig?: { model?: string; provider?: string },
44
- enableSupervisor?: boolean,
45
- ) => Promise<void>;
32
+ onConfirm?: (selectedAgents: string[]) => Promise<void>;
46
33
  }
47
34
 
48
35
  const AgentModalContext = createContext<AgentModalContextValue | null>(null);
@@ -131,21 +118,11 @@ export const AgentModalProvider = memo<AgentModalProviderProps>(({ children }) =
131
118
  groupWizardCallbacks.onCancel?.();
132
119
  setGroupWizardOpen(false);
133
120
  }}
134
- onCreateCustom={async (selectedAgents, hostConfig, enableSupervisor) => {
135
- await groupWizardCallbacks.onCreateCustom?.(selectedAgents, hostConfig, enableSupervisor);
121
+ onCreateCustom={async (selectedAgents: string[]) => {
122
+ await groupWizardCallbacks.onCreateCustom?.(selectedAgents);
136
123
  }}
137
- onCreateFromTemplate={async (
138
- templateId,
139
- hostConfig,
140
- enableSupervisor,
141
- selectedMemberTitles,
142
- ) => {
143
- await groupWizardCallbacks.onCreateFromTemplate?.(
144
- templateId,
145
- hostConfig,
146
- enableSupervisor,
147
- selectedMemberTitles,
148
- );
124
+ onCreateFromTemplate={async (templateId: string, selectedMemberTitles?: string[]) => {
125
+ await groupWizardCallbacks.onCreateFromTemplate?.(templateId, selectedMemberTitles);
149
126
  }}
150
127
  open={groupWizardOpen}
151
128
  />
@@ -156,8 +133,8 @@ export const AgentModalProvider = memo<AgentModalProviderProps>(({ children }) =
156
133
  memberSelectionCallbacks.onCancel?.();
157
134
  setMemberSelectionOpen(false);
158
135
  }}
159
- onConfirm={async (selectedAgents, hostConfig, enableSupervisor) => {
160
- await memberSelectionCallbacks.onConfirm?.(selectedAgents, hostConfig, enableSupervisor);
136
+ onConfirm={async (selectedAgents: string[]) => {
137
+ await memberSelectionCallbacks.onConfirm?.(selectedAgents);
161
138
  }}
162
139
  open={memberSelectionOpen}
163
140
  />
@@ -16,11 +16,6 @@ import { useAgentGroupStore } from '@/store/agentGroup';
16
16
  import { useHomeStore } from '@/store/home';
17
17
  import { usePageStore } from '@/store/page';
18
18
 
19
- interface HostConfig {
20
- model?: string;
21
- provider?: string;
22
- }
23
-
24
19
  interface CreateAgentOptions {
25
20
  groupId?: string;
26
21
  isPinned?: boolean;
@@ -104,12 +99,7 @@ export const useCreateMenuItems = () => {
104
99
  * Uses backend batch creation for better performance and consistency
105
100
  */
106
101
  const createGroupFromTemplate = useCallback(
107
- async (
108
- templateId: string,
109
- hostConfig?: HostConfig,
110
- enableSupervisor?: boolean,
111
- selectedMemberTitles?: string[],
112
- ) => {
102
+ async (templateId: string, selectedMemberTitles?: string[]) => {
113
103
  setIsCreatingGroup(true);
114
104
  try {
115
105
  const template = groupTemplates.find((t) => t.id === templateId);
@@ -134,16 +124,6 @@ export const useCreateMenuItems = () => {
134
124
  // Use batch creation endpoint - creates all agents and group in one request
135
125
  const { groupId } = await chatGroupService.createGroupWithMembers(
136
126
  {
137
- config: {
138
- ...(hostConfig
139
- ? {
140
- orchestratorModel: hostConfig.model,
141
- orchestratorProvider: hostConfig.provider,
142
- }
143
- : {}),
144
- enableSupervisor: enableSupervisor ?? true,
145
- scene: DEFAULT_CHAT_GROUP_CHAT_CONFIG.scene,
146
- },
147
127
  title: template.title,
148
128
  },
149
129
  memberConfigs,
@@ -172,28 +152,14 @@ export const useCreateMenuItems = () => {
172
152
  * Create group with members
173
153
  */
174
154
  const createGroupWithMembers = useCallback(
175
- async (
176
- selectedAgents: string[],
177
- groupTitle?: string,
178
- hostConfig?: HostConfig,
179
- enableSupervisor?: boolean,
180
- ) => {
155
+ async (selectedAgents: string[], groupTitle?: string) => {
181
156
  setIsCreatingGroup(true);
182
157
  try {
183
158
  const title = groupTitle || t('defaultGroupChat');
184
159
 
185
160
  await createGroup(
186
161
  {
187
- config: {
188
- ...DEFAULT_CHAT_GROUP_CHAT_CONFIG,
189
- ...(hostConfig
190
- ? {
191
- orchestratorModel: hostConfig.model,
192
- orchestratorProvider: hostConfig.provider,
193
- }
194
- : {}),
195
- enableSupervisor: enableSupervisor ?? true,
196
- },
162
+ config: DEFAULT_CHAT_GROUP_CHAT_CONFIG,
197
163
  title,
198
164
  },
199
165
  selectedAgents,
@@ -18,11 +18,6 @@ const styles = createStaticStyles(({ css }) => ({
18
18
  `,
19
19
  }));
20
20
 
21
- interface HostConfig {
22
- model?: string;
23
- provider?: string;
24
- }
25
-
26
21
  /**
27
22
  * Hook for generating menu items for session group containers
28
23
  * Used in List/Group/Actions.tsx
@@ -153,11 +148,7 @@ export const useSessionGroupMenuItems = () => {
153
148
  _groupId: string,
154
149
  onOpenMemberSelection: (callbacks: {
155
150
  onCancel: () => void;
156
- onConfirm: (
157
- selectedAgents: string[],
158
- hostConfig?: HostConfig,
159
- enableSupervisor?: boolean,
160
- ) => Promise<void>;
151
+ onConfirm: (selectedAgents: string[]) => Promise<void>;
161
152
  }) => void,
162
153
  ): ItemType => {
163
154
  const iconElement = <Icon icon={FolderPenIcon} />;
@@ -170,21 +161,12 @@ export const useSessionGroupMenuItems = () => {
170
161
 
171
162
  onOpenMemberSelection({
172
163
  onCancel: () => {},
173
- onConfirm: async (selectedAgents, hostConfig, enableSupervisor) => {
164
+ onConfirm: async (selectedAgents) => {
174
165
  setIsCreatingGroup(true);
175
166
  try {
176
167
  await createGroup(
177
168
  {
178
- config: {
179
- ...DEFAULT_CHAT_GROUP_CHAT_CONFIG,
180
- ...(hostConfig
181
- ? {
182
- orchestratorModel: hostConfig.model,
183
- orchestratorProvider: hostConfig.provider,
184
- }
185
- : {}),
186
- enableSupervisor: enableSupervisor ?? true,
187
- },
169
+ config: DEFAULT_CHAT_GROUP_CHAT_CONFIG,
188
170
  title: 'New Group Chat',
189
171
  },
190
172
  selectedAgents,
@@ -208,12 +190,7 @@ export const useSessionGroupMenuItems = () => {
208
190
  * Internal helper function used by create menu items
209
191
  */
210
192
  const createGroupFromTemplate = useCallback(
211
- async (
212
- templateId: string,
213
- hostConfig?: HostConfig,
214
- enableSupervisor?: boolean,
215
- selectedMemberTitles?: string[],
216
- ) => {
193
+ async (templateId: string, selectedMemberTitles?: string[]) => {
217
194
  setIsCreatingGroup(true);
218
195
  try {
219
196
  const template = groupTemplates.find((t) => t.id === templateId);
@@ -258,16 +235,7 @@ export const useSessionGroupMenuItems = () => {
258
235
 
259
236
  await createGroup(
260
237
  {
261
- config: {
262
- ...DEFAULT_CHAT_GROUP_CHAT_CONFIG,
263
- ...(hostConfig
264
- ? {
265
- orchestratorModel: hostConfig.model,
266
- orchestratorProvider: hostConfig.provider,
267
- }
268
- : {}),
269
- enableSupervisor: enableSupervisor ?? true,
270
- },
238
+ config: DEFAULT_CHAT_GROUP_CHAT_CONFIG,
271
239
  title: template.title,
272
240
  },
273
241
  memberAgentIds,
@@ -290,28 +258,14 @@ export const useSessionGroupMenuItems = () => {
290
258
  * Internal helper function used by create menu items
291
259
  */
292
260
  const createGroupWithMembers = useCallback(
293
- async (
294
- selectedAgents: string[],
295
- groupTitle?: string,
296
- hostConfig?: HostConfig,
297
- enableSupervisor?: boolean,
298
- ) => {
261
+ async (selectedAgents: string[], groupTitle?: string) => {
299
262
  setIsCreatingGroup(true);
300
263
  try {
301
264
  const title = groupTitle || t('defaultGroupChat');
302
265
 
303
266
  await createGroup(
304
267
  {
305
- config: {
306
- ...DEFAULT_CHAT_GROUP_CHAT_CONFIG,
307
- ...(hostConfig
308
- ? {
309
- orchestratorModel: hostConfig.model,
310
- orchestratorProvider: hostConfig.provider,
311
- }
312
- : {}),
313
- enableSupervisor: enableSupervisor ?? true,
314
- },
268
+ config: DEFAULT_CHAT_GROUP_CHAT_CONFIG,
315
269
  title,
316
270
  },
317
271
  selectedAgents,
@@ -7,6 +7,7 @@ import GroupSkeleton from '@/app/[variants]/(main)/home/features/components/Grou
7
7
  import { RECENT_BLOCK_SIZE } from '@/app/[variants]/(main)/home/features/const';
8
8
  import { useHomeStore } from '@/store/home';
9
9
  import { homeRecentSelectors } from '@/store/home/selectors';
10
+ import { standardizeIdentifier } from '@/utils/identifier';
10
11
 
11
12
  import RecentPageItem from './Item';
12
13
 
@@ -22,7 +23,7 @@ const RecentPageList = memo(() => {
22
23
  }
23
24
 
24
25
  return documents.map((document) => {
25
- const pageUrl = `/page/${document.id}`;
26
+ const pageUrl = `/page/${standardizeIdentifier(document.id)}`;
26
27
 
27
28
  return (
28
29
  <Link
@@ -17,7 +17,7 @@ import { createPortal } from 'react-dom';
17
17
  import { useTranslation } from 'react-i18next';
18
18
 
19
19
  import FileIcon from '@/components/FileIcon';
20
- import { clearTreeFolderCache } from '@/features/ResourceManager/components/Tree';
20
+ import { clearTreeFolderCache } from '@/features/ResourceManager/components/LibraryHierarchy';
21
21
  import { useFileStore } from '@/store/file';
22
22
 
23
23
  import { useResourceManagerStore } from './store';
@@ -4,14 +4,14 @@ import { memo } from 'react';
4
4
 
5
5
  import { NavPanelPortal } from '@/features/NavPanel';
6
6
  import SideBarLayout from '@/features/NavPanel/SideBarLayout';
7
- import FileTree from '@/features/ResourceManager/components/Tree';
7
+ import LibraryHierarchy from '@/features/ResourceManager/components/LibraryHierarchy';
8
8
 
9
9
  import Header from './Header';
10
10
 
11
11
  const Sidebar = memo(() => {
12
12
  return (
13
13
  <NavPanelPortal navKey="resourceLibrary">
14
- <SideBarLayout body={<FileTree />} header={<Header />} />
14
+ <SideBarLayout body={<LibraryHierarchy />} header={<Header />} />
15
15
  </NavPanelPortal>
16
16
  );
17
17
  });
@@ -3,7 +3,7 @@
3
3
  import { Flexbox } from '@lobehub/ui';
4
4
  import { memo } from 'react';
5
5
 
6
- import FileTree from '@/features/ResourceManager/components/Tree';
6
+ import LibraryHierarchy from '@/features/ResourceManager/components/LibraryHierarchy';
7
7
 
8
8
  import Head from '../_layout/Header/LibraryHead';
9
9
 
@@ -13,7 +13,7 @@ const Menu = memo<{ id: string }>(({ id }) => {
13
13
  <Flexbox paddingInline={12}>
14
14
  <Head id={id} />
15
15
  </Flexbox>
16
- <FileTree />
16
+ <LibraryHierarchy />
17
17
  </Flexbox>
18
18
  );
19
19
  });
@@ -8,9 +8,7 @@ import { useTranslation } from 'react-i18next';
8
8
 
9
9
  import { DESKTOP_HEADER_ICON_SIZE, MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
10
10
  import { useOpenChatSettings } from '@/hooks/useInterceptingRoutes';
11
- import { useAgentGroupStore } from '@/store/agentGroup';
12
11
  import { useSessionStore } from '@/store/session';
13
- import { sessionSelectors } from '@/store/session/selectors';
14
12
  import { useUserStore } from '@/store/user';
15
13
  import { settingsSelectors } from '@/store/user/selectors';
16
14
  import { HotkeyEnum } from '@/types/hotkey';
@@ -19,26 +17,18 @@ const AgentSettingsEditor = dynamic(() => import('@/app/[variants]/(main)/agent/
19
17
  ssr: false,
20
18
  });
21
19
 
22
- const AgentTeamSettings = dynamic(() => import('./AgentTeamSettings'), {
23
- ssr: false,
24
- });
25
-
26
20
  const SettingButton = memo<{ mobile?: boolean }>(({ mobile }) => {
27
21
  const hotkey = useUserStore(settingsSelectors.getHotkeyById(HotkeyEnum.OpenChatSettings));
28
22
  const { t } = useTranslation('common');
29
23
  const id = useSessionStore((s) => s.activeId);
30
- const isGroupSession = useSessionStore(sessionSelectors.isCurrentSessionGroupSession);
31
24
 
32
- // The chat settings need some compatibility so we use a hook but for
33
- // the group settings we use a store directly
34
25
  const openChatSettings = useOpenChatSettings();
35
- const openGroupSettings = useAgentGroupStore((s) => s.toggleGroupSetting);
36
26
 
37
27
  return (
38
28
  <>
39
29
  <ActionIcon
40
30
  icon={AlignJustify}
41
- onClick={() => (isGroupSession ? openGroupSettings(true) : openChatSettings())}
31
+ onClick={() => openChatSettings()}
42
32
  size={mobile ? MOBILE_HEADER_ICON_SIZE : DESKTOP_HEADER_ICON_SIZE}
43
33
  title={t('openChatSettings.title', { ns: 'hotkey' })}
44
34
  tooltipProps={{
@@ -47,7 +37,7 @@ const SettingButton = memo<{ mobile?: boolean }>(({ mobile }) => {
47
37
  }}
48
38
  />
49
39
 
50
- {isGroupSession ? <AgentTeamSettings key={id} /> : <AgentSettingsEditor key={id} />}
40
+ <AgentSettingsEditor key={id} />
51
41
  </>
52
42
  );
53
43
  });
@@ -191,15 +191,9 @@ export interface ChatGroupWizardProps {
191
191
  */
192
192
  isCreatingFromTemplate?: boolean;
193
193
  onCancel: () => void;
194
- onCreateCustom: (
195
- selectedAgents: string[],
196
- hostConfig?: { model?: string; provider?: string },
197
- enableSupervisor?: boolean,
198
- ) => void | Promise<void>;
194
+ onCreateCustom: (selectedAgents: string[]) => void | Promise<void>;
199
195
  onCreateFromTemplate: (
200
196
  templateId: string,
201
- hostConfig?: { model?: string; provider?: string },
202
- enableSupervisor?: boolean,
203
197
  selectedMemberTitles?: string[],
204
198
  ) => void | Promise<void>;
205
199
  open: boolean;
@@ -495,8 +489,6 @@ const ChatGroupWizard = memo<ChatGroupWizardProps>(
495
489
  const handleTemplateConfirm = useCallback(async () => {
496
490
  if (!selectedTemplate) return;
497
491
 
498
- const hostConfig = isHostRemoved ? undefined : normalizedHostModelConfig;
499
-
500
492
  try {
501
493
  // collect selected member titles (not removed)
502
494
  const template = groupTemplates.find((t) => t.id === selectedTemplate);
@@ -505,33 +497,19 @@ const ChatGroupWizard = memo<ChatGroupWizardProps>(
505
497
  .filter((m) => m !== null && m !== undefined && !removedForTemplate.has(m.title))
506
498
  .map((m) => m.title);
507
499
 
508
- await onCreateFromTemplate(
509
- selectedTemplate,
510
- hostConfig,
511
- !isHostRemoved,
512
- selectedMemberTitles,
513
- );
500
+ await onCreateFromTemplate(selectedTemplate, selectedMemberTitles);
514
501
  handleReset();
515
502
  } catch (error) {
516
503
  console.error('Failed to create group from template:', error);
517
504
  }
518
- }, [
519
- selectedTemplate,
520
- onCreateFromTemplate,
521
- normalizedHostModelConfig,
522
- isHostRemoved,
523
- groupTemplates,
524
- removedMembers,
525
- ]);
505
+ }, [selectedTemplate, onCreateFromTemplate, groupTemplates, removedMembers]);
526
506
 
527
507
  const handleCustomConfirm = useCallback(async () => {
528
508
  if (selectedAgents.length === 0) return;
529
509
 
530
- const hostConfig = isHostRemoved ? undefined : normalizedHostModelConfig;
531
-
532
510
  try {
533
511
  setIsCreatingCustom(true);
534
- await onCreateCustom(selectedAgents, hostConfig, !isHostRemoved);
512
+ await onCreateCustom(selectedAgents);
535
513
  handleReset();
536
514
  onCancel();
537
515
  } catch (error) {
@@ -539,7 +517,7 @@ const ChatGroupWizard = memo<ChatGroupWizardProps>(
539
517
  } finally {
540
518
  setIsCreatingCustom(false);
541
519
  }
542
- }, [selectedAgents, onCreateCustom, normalizedHostModelConfig, isHostRemoved, onCancel]);
520
+ }, [selectedAgents, onCreateCustom, onCancel]);
543
521
 
544
522
  const handleConfirm = useCallback(async () => {
545
523
  if (selectedTemplate) {
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable no-undef */
2
2
  import { Center, Flexbox, Icon } from '@lobehub/ui';
3
- import { createStaticStyles, cssVar } from 'antd-style';
3
+ import { createStyles } from 'antd-style';
4
4
  import { FileImage, FileText, FileUpIcon } from 'lucide-react';
5
5
  import { memo } from 'react';
6
6
  import { createPortal } from 'react-dom';
@@ -11,22 +11,22 @@ import { getContainer, useDragUpload } from './useDragUpload';
11
11
  const BLOCK_SIZE = 64;
12
12
  const ICON_SIZE = { size: 36, strokeWidth: 1.5 };
13
13
 
14
- const styles = createStaticStyles(({ css }) => {
14
+ const useStyles = createStyles(({ css, token }) => {
15
15
  return {
16
16
  container: css`
17
17
  width: 320px;
18
18
  height: 200px;
19
- padding: calc(${cssVar.borderRadiusLG} + 4px);
19
+ padding: calc(${token.borderRadiusLG}px + 4px);
20
20
  border-radius: 16px;
21
21
 
22
- background: ${cssVar.geekblue};
22
+ background: ${token.geekblue};
23
23
  `,
24
24
  content: css`
25
25
  width: 100%;
26
26
  height: 100%;
27
27
  padding: 16px;
28
28
  border: 1.5px dashed #fff;
29
- border-radius: ${cssVar.borderRadiusLG};
29
+ border-radius: ${token.borderRadiusLG}px;
30
30
  `,
31
31
  desc: css`
32
32
  font-size: 14px;
@@ -34,13 +34,25 @@ const styles = createStaticStyles(({ css }) => {
34
34
  color: #fff;
35
35
  `,
36
36
  icon: css`
37
- border-radius: ${cssVar.borderRadiusLG};
38
- color: color-mix(in srgb, ${cssVar.geekblue} 95%, black);
39
- background: color-mix(in srgb, ${cssVar.geekblue} 38%, white);
37
+ border-radius: ${token.borderRadiusLG}px;
38
+ color: color-mix(in srgb, ${token.geekblue} 95%, black);
39
+ background: color-mix(in srgb, ${token.geekblue} 38%, white);
40
40
  `,
41
41
  iconGroup: css`
42
42
  margin-block-start: -44px;
43
43
  `,
44
+ iconLeft: css`
45
+ transform: rotateZ(-20deg) translateX(10px);
46
+ border-radius: ${token.borderRadiusLG}px;
47
+ color: color-mix(in srgb, ${token.geekblue} 95%, black);
48
+ background: color-mix(in srgb, ${token.geekblue} 68%, white);
49
+ `,
50
+ iconRight: css`
51
+ transform: rotateZ(20deg) translateX(-10px);
52
+ border-radius: ${token.borderRadiusLG}px;
53
+ color: color-mix(in srgb, ${token.geekblue} 95%, black);
54
+ background: color-mix(in srgb, ${token.geekblue} 68%, white);
55
+ `,
44
56
  title: css`
45
57
  font-size: 20px;
46
58
  font-weight: bold;
@@ -54,7 +66,7 @@ const styles = createStaticStyles(({ css }) => {
54
66
  width: 100%;
55
67
  height: 100%;
56
68
 
57
- background: ${cssVar.colorBgMask};
69
+ background: ${token.colorBgMask};
58
70
 
59
71
  transition: all 0.3s ease-in-out;
60
72
  `,
@@ -68,6 +80,7 @@ interface DragUploadProps {
68
80
 
69
81
  const DragUpload = memo<DragUploadProps>(({ enabledFiles = true, onUploadFiles }) => {
70
82
  const { t } = useTranslation('components');
83
+ const { styles } = useStyles();
71
84
 
72
85
  const isDragging = useDragUpload(onUploadFiles);
73
86
 
@@ -78,15 +91,7 @@ const DragUpload = memo<DragUploadProps>(({ enabledFiles = true, onUploadFiles }
78
91
  <div className={styles.container}>
79
92
  <Center className={styles.content} gap={12}>
80
93
  <Flexbox className={styles.iconGroup} horizontal>
81
- <Center
82
- className={styles.icon}
83
- height={BLOCK_SIZE * 1.25}
84
- style={{
85
- background: `color-mix(in srgb, ${cssVar.geekblue} 68%, white)`,
86
- transform: 'rotateZ(-20deg) translateX(10px)',
87
- }}
88
- width={BLOCK_SIZE}
89
- >
94
+ <Center className={styles.iconLeft} height={BLOCK_SIZE * 1.25} width={BLOCK_SIZE}>
90
95
  <Icon icon={FileImage} size={ICON_SIZE} />
91
96
  </Center>
92
97
  <Center
@@ -100,15 +105,7 @@ const DragUpload = memo<DragUploadProps>(({ enabledFiles = true, onUploadFiles }
100
105
  >
101
106
  <Icon icon={FileUpIcon} size={ICON_SIZE} />
102
107
  </Center>
103
- <Center
104
- className={styles.icon}
105
- height={BLOCK_SIZE * 1.25}
106
- style={{
107
- background: `color-mix(in srgb, ${cssVar.geekblue} 68%, white)`,
108
- transform: 'rotateZ(20deg) translateX(-10px)',
109
- }}
110
- width={BLOCK_SIZE}
111
- >
108
+ <Center className={styles.iconRight} height={BLOCK_SIZE * 1.25} width={BLOCK_SIZE}>
112
109
  <Icon icon={FileText} size={ICON_SIZE} />
113
110
  </Center>
114
111
  </Flexbox>
@@ -162,11 +162,7 @@ export interface MemberSelectionModalProps {
162
162
  */
163
163
  mode: MemberSelectionMode;
164
164
  onCancel: () => void;
165
- onConfirm: (
166
- selectedAgents: string[],
167
- hostConfig?: { model?: string; provider?: string },
168
- enableSupervisor?: boolean,
169
- ) => void | Promise<void>;
165
+ onConfirm: (selectedAgents: string[]) => void | Promise<void>;
170
166
  open: boolean;
171
167
  /**
172
168
  * Pre-selected agent IDs (useful for editing existing groups)
@@ -338,12 +334,7 @@ const MemberSelectionModal = memo<MemberSelectionModalProps>(
338
334
  const handleConfirm = async () => {
339
335
  try {
340
336
  setIsAdding(true);
341
- // Only pass host config if the host card is visible (being managed in this modal)
342
- const shouldManageHost = !isHostCurrentlyEnabled;
343
- const hostConfig =
344
- shouldManageHost && !isHostRemoved ? normalizedHostModelConfig : undefined;
345
- const enableSupervisor = shouldManageHost ? !isHostRemoved : undefined;
346
- await onConfirm(selectedAgents, hostConfig, enableSupervisor);
337
+ await onConfirm(selectedAgents);
347
338
  handleReset();
348
339
  } catch (error) {
349
340
  console.error('Failed to confirm action:', error);
@@ -1,6 +1,6 @@
1
- import { Form, type FormItemProps, Tag } from '@lobehub/ui';
1
+ import { Form, type FormItemProps, SliderWithInput, Tag } from '@lobehub/ui';
2
2
  import { Checkbox, Flexbox } from '@lobehub/ui';
3
- import { Form as AntdForm } from 'antd';
3
+ import { Form as AntdForm, Switch } from 'antd';
4
4
  import { createStaticStyles } from 'antd-style';
5
5
  import { debounce } from 'es-toolkit/compat';
6
6
  import isEqual from 'fast-deep-equal';
@@ -151,6 +151,7 @@ const Controls = memo<ControlsProps>(({ setUpdating }) => {
151
151
  const config = useAgentStore((s) => agentByIdSelectors.getAgentConfigById(agentId)(s), isEqual);
152
152
  const [form] = Form.useForm();
153
153
 
154
+ const enableMaxTokens = AntdForm.useWatch(['chatConfig', 'enableMaxTokens'], form);
154
155
  const { frequency_penalty, presence_penalty, temperature, top_p } = config.params ?? {};
155
156
 
156
157
  const lastValuesRef = useRef<Record<ParamKey, number | undefined>>({
@@ -289,6 +290,40 @@ const Controls = memo<ControlsProps>(({ setUpdating }) => {
289
290
  } satisfies FormItemProps;
290
291
  });
291
292
 
293
+ // MaxTokens items
294
+ const maxTokensItems: FormItemProps[] = [
295
+ {
296
+ children: <Switch />,
297
+ label: (
298
+ <Flexbox align={'center'} className={styles.label} gap={8} horizontal>
299
+ {t('settingModel.enableMaxTokens.title')}
300
+ </Flexbox>
301
+ ),
302
+ name: ['chatConfig', 'enableMaxTokens'],
303
+ tag: 'max_tokens',
304
+ valuePropName: 'checked',
305
+ },
306
+ ...(enableMaxTokens
307
+ ? [
308
+ {
309
+ children: (
310
+ <SliderWithInput max={32_000} min={0} step={100} unlimitedInput />
311
+ ),
312
+ label: (
313
+ <Flexbox align={'center'} className={styles.label} gap={8} horizontal>
314
+ {t('settingModel.maxTokens.title')}
315
+ <InfoTooltip title={t('settingModel.maxTokens.desc')} />
316
+ </Flexbox>
317
+ ),
318
+ name: ['params', 'max_tokens'],
319
+ tag: 'max_tokens',
320
+ } satisfies FormItemProps,
321
+ ]
322
+ : []),
323
+ ];
324
+
325
+ const allItems = [...baseItems, ...maxTokensItems];
326
+
292
327
  return (
293
328
  <Form
294
329
  form={form}
@@ -296,11 +331,11 @@ const Controls = memo<ControlsProps>(({ setUpdating }) => {
296
331
  itemMinWidth={220}
297
332
  items={
298
333
  mobile
299
- ? baseItems
300
- : baseItems.map(({ tag, ...item }) => ({
301
- ...item,
302
- desc: <Tag size={'small'}>{tag}</Tag>,
303
- }))
334
+ ? allItems
335
+ : allItems.map(({ tag, ...item }) => ({
336
+ ...item,
337
+ desc: <Tag size={'small'}>{tag}</Tag>,
338
+ }))
304
339
  }
305
340
  itemsType={'flat'}
306
341
  onValuesChange={handleValuesChange}
@@ -169,21 +169,11 @@ export const useCommandMenu = () => {
169
169
  const handleCreateAgentTeam = async () => {
170
170
  closeCommandMenu();
171
171
  openGroupWizard({
172
- onCreateCustom: async (selectedAgents, hostConfig, enableSupervisor) => {
173
- await createGroupWithMembers(selectedAgents, undefined, hostConfig, enableSupervisor);
172
+ onCreateCustom: async (selectedAgents) => {
173
+ await createGroupWithMembers(selectedAgents);
174
174
  },
175
- onCreateFromTemplate: async (
176
- templateId,
177
- hostConfig,
178
- enableSupervisor,
179
- selectedMemberTitles,
180
- ) => {
181
- await createGroupFromTemplate(
182
- templateId,
183
- hostConfig,
184
- enableSupervisor,
185
- selectedMemberTitles,
186
- );
175
+ onCreateFromTemplate: async (templateId, selectedMemberTitles) => {
176
+ await createGroupFromTemplate(templateId, selectedMemberTitles);
187
177
  },
188
178
  });
189
179
  };