@lobehub/chat 1.141.7 → 1.141.9

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 (128) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/apps/desktop/package.json +1 -0
  3. package/apps/desktop/src/main/controllers/LocalFileCtr.ts +279 -52
  4. package/apps/desktop/src/main/controllers/__tests__/LocalFileCtr.test.ts +392 -0
  5. package/changelog/v1.json +18 -0
  6. package/docs/usage/features/{group-chat.mdx → agent-team.mdx} +14 -14
  7. package/docs/usage/features/agent-team.zh-CN.mdx +52 -0
  8. package/locales/ar/chat.json +17 -17
  9. package/locales/ar/setting.json +15 -19
  10. package/locales/ar/welcome.json +1 -1
  11. package/locales/bg-BG/chat.json +17 -17
  12. package/locales/bg-BG/setting.json +15 -19
  13. package/locales/de-DE/chat.json +17 -17
  14. package/locales/de-DE/setting.json +15 -19
  15. package/locales/de-DE/welcome.json +1 -1
  16. package/locales/en-US/chat.json +17 -17
  17. package/locales/en-US/setting.json +15 -19
  18. package/locales/en-US/welcome.json +1 -1
  19. package/locales/es-ES/chat.json +17 -17
  20. package/locales/es-ES/setting.json +15 -19
  21. package/locales/es-ES/welcome.json +1 -1
  22. package/locales/fa-IR/chat.json +17 -17
  23. package/locales/fa-IR/setting.json +15 -19
  24. package/locales/fa-IR/welcome.json +1 -1
  25. package/locales/fr-FR/chat.json +16 -16
  26. package/locales/fr-FR/setting.json +15 -19
  27. package/locales/fr-FR/welcome.json +1 -1
  28. package/locales/it-IT/chat.json +17 -17
  29. package/locales/it-IT/setting.json +15 -19
  30. package/locales/it-IT/welcome.json +1 -1
  31. package/locales/ja-JP/chat.json +17 -17
  32. package/locales/ja-JP/setting.json +15 -19
  33. package/locales/ja-JP/welcome.json +1 -1
  34. package/locales/ko-KR/chat.json +17 -17
  35. package/locales/ko-KR/setting.json +15 -19
  36. package/locales/ko-KR/welcome.json +1 -1
  37. package/locales/nl-NL/chat.json +17 -17
  38. package/locales/nl-NL/setting.json +15 -19
  39. package/locales/nl-NL/welcome.json +1 -1
  40. package/locales/pl-PL/chat.json +17 -17
  41. package/locales/pl-PL/setting.json +15 -19
  42. package/locales/pt-BR/chat.json +17 -17
  43. package/locales/pt-BR/setting.json +15 -19
  44. package/locales/pt-BR/welcome.json +1 -1
  45. package/locales/ru-RU/chat.json +17 -17
  46. package/locales/ru-RU/setting.json +15 -19
  47. package/locales/ru-RU/welcome.json +1 -1
  48. package/locales/tr-TR/chat.json +17 -17
  49. package/locales/tr-TR/setting.json +15 -19
  50. package/locales/vi-VN/chat.json +15 -15
  51. package/locales/vi-VN/setting.json +15 -19
  52. package/locales/zh-CN/chat.json +17 -17
  53. package/locales/zh-CN/setting.json +15 -19
  54. package/locales/zh-CN/welcome.json +1 -1
  55. package/locales/zh-TW/chat.json +17 -17
  56. package/locales/zh-TW/setting.json +15 -19
  57. package/locales/zh-TW/welcome.json +1 -1
  58. package/package.json +1 -1
  59. package/packages/agent-runtime/src/core/InterventionChecker.ts +173 -0
  60. package/packages/agent-runtime/src/core/UsageCounter.ts +248 -0
  61. package/packages/agent-runtime/src/core/__tests__/InterventionChecker.test.ts +334 -0
  62. package/packages/agent-runtime/src/core/__tests__/UsageCounter.test.ts +873 -0
  63. package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +32 -26
  64. package/packages/agent-runtime/src/core/index.ts +2 -0
  65. package/packages/agent-runtime/src/core/runtime.ts +31 -18
  66. package/packages/agent-runtime/src/types/instruction.ts +1 -1
  67. package/packages/agent-runtime/src/types/state.ts +3 -3
  68. package/packages/agent-runtime/src/types/usage.ts +34 -25
  69. package/packages/const/src/settings/systemAgent.ts +0 -1
  70. package/packages/context-engine/src/index.ts +1 -0
  71. package/packages/context-engine/src/tools/ToolNameResolver.ts +2 -2
  72. package/packages/context-engine/src/tools/ToolsEngine.ts +37 -8
  73. package/packages/context-engine/src/tools/__tests__/ToolsEngine.test.ts +149 -5
  74. package/packages/context-engine/src/tools/__tests__/utils.test.ts +2 -2
  75. package/packages/context-engine/src/tools/index.ts +1 -0
  76. package/packages/context-engine/src/tools/types.ts +18 -3
  77. package/packages/context-engine/src/tools/utils.ts +4 -4
  78. package/packages/types/src/tool/builtin.ts +54 -1
  79. package/packages/types/src/tool/index.ts +1 -0
  80. package/packages/types/src/tool/intervention.ts +114 -0
  81. package/packages/types/src/user/settings/systemAgent.ts +0 -1
  82. package/packages/types/src/user/settings/tool.ts +37 -0
  83. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/OrchestratorThinking.tsx +2 -3
  84. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/index.tsx +2 -2
  85. package/src/app/[variants]/(main)/chat/(workspace)/@topic/features/GroupConfig/GroupMember.tsx +34 -2
  86. package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/Main.tsx +1 -1
  87. package/src/app/[variants]/(main)/chat/(workspace)/features/{GroupChatSettings → AgentTeamSettings}/index.tsx +4 -5
  88. package/src/app/[variants]/(main)/chat/(workspace)/features/SettingButton.tsx +2 -2
  89. package/src/app/[variants]/(main)/chat/@session/_layout/Desktop/SessionHeader.tsx +2 -0
  90. package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/CollapseGroup/Actions.tsx +18 -1
  91. package/src/components/ChatGroupWizard/ChatGroupWizard.tsx +33 -5
  92. package/src/components/MemberSelectionModal/MemberSelectionModal.tsx +170 -26
  93. package/src/features/Conversation/Messages/Assistant/Actions/index.tsx +7 -2
  94. package/src/features/Conversation/Messages/Assistant/Tool/Render/index.tsx +4 -2
  95. package/src/features/Conversation/Messages/User/Actions.tsx +8 -2
  96. package/src/features/GroupChatSettings/{ChatGroupSettings.tsx → AgentTeamChatSettings.tsx} +6 -5
  97. package/src/features/GroupChatSettings/{GroupMembers.tsx → AgentTeamMembersSettings.tsx} +64 -19
  98. package/src/features/GroupChatSettings/{ChatGroupMeta.tsx → AgentTeamMetaSettings.tsx} +2 -2
  99. package/src/features/GroupChatSettings/AgentTeamSettings.tsx +54 -0
  100. package/src/features/GroupChatSettings/index.ts +4 -5
  101. package/src/locales/default/chat.ts +17 -17
  102. package/src/locales/default/setting.ts +15 -19
  103. package/src/locales/default/welcome.ts +1 -1
  104. package/src/store/chat/slices/aiChat/actions/generateAIGroupChat.ts +2 -1
  105. package/src/store/chat/slices/builtinTool/actions/{dalle.test.ts → __tests__/dalle.test.ts} +2 -5
  106. package/src/store/chat/slices/builtinTool/actions/__tests__/{localFile.test.ts → localSystem.test.ts} +4 -4
  107. package/src/store/chat/slices/builtinTool/actions/index.ts +2 -2
  108. package/src/store/chat/slices/builtinTool/actions/{localFile.ts → localSystem.ts} +183 -69
  109. package/src/store/chatGroup/action.ts +36 -1
  110. package/src/store/electron/selectors/__tests__/desktopState.test.ts +3 -3
  111. package/src/store/electron/selectors/desktopState.ts +11 -2
  112. package/src/store/user/slices/settings/selectors/__snapshots__/settings.test.ts.snap +0 -4
  113. package/src/store/user/slices/settings/selectors/systemAgent.ts +0 -2
  114. package/src/tools/local-system/Placeholder/ListFiles.tsx +10 -8
  115. package/src/tools/local-system/Placeholder/SearchFiles.tsx +12 -10
  116. package/src/tools/local-system/Placeholder/index.tsx +1 -1
  117. package/src/tools/local-system/Render/ReadLocalFile/ReadFileSkeleton.tsx +8 -18
  118. package/src/tools/local-system/Render/ReadLocalFile/ReadFileView.tsx +21 -6
  119. package/src/tools/local-system/Render/SearchFiles/Result.tsx +5 -4
  120. package/src/tools/local-system/Render/SearchFiles/SearchQuery/SearchView.tsx +4 -15
  121. package/src/tools/local-system/Render/SearchFiles/index.tsx +3 -2
  122. package/src/tools/local-system/type.ts +39 -0
  123. package/docs/usage/features/group-chat.zh-CN.mdx +0 -52
  124. package/src/features/GroupChatSettings/GroupSettings.tsx +0 -30
  125. package/src/features/GroupChatSettings/GroupSettingsContent.tsx +0 -24
  126. package/src/tools/local-system/Placeholder/ReadLocalFile.tsx +0 -9
  127. package/src/tools/local-system/Render/ReadLocalFile/style.ts +0 -37
  128. /package/src/store/chat/slices/builtinTool/actions/{search.test.ts → __tests__/search.test.ts} +0 -0
@@ -46,6 +46,8 @@ const Header = memo(() => {
46
46
  const { showCreateSession, enableGroupChat } = useServerConfigStore(featureFlagsSelectors);
47
47
  const [isGroupWizardOpen, setIsGroupWizardOpen] = useState(false);
48
48
 
49
+ // const enableGroupChatInLabs = useUserStore(preferenceSelectors.enableGroupChat);
50
+
49
51
  // We need pass inital member list so we cannot use mutate
50
52
  const [isCreatingGroup, setIsCreatingGroup] = useState(false);
51
53
 
@@ -82,11 +82,28 @@ const Actions = memo<ActionsProps>(
82
82
  },
83
83
  };
84
84
 
85
- const handleCreateGroupWithMembers = async (selectedAgents: string[]) => {
85
+ const handleCreateGroupWithMembers = async (
86
+ selectedAgents: string[],
87
+ hostConfig?: { model?: string; provider?: string },
88
+ enableSupervisor?: boolean,
89
+ ) => {
86
90
  try {
87
91
  setIsCreatingGroup(true);
92
+
93
+ const config: any = {};
94
+
95
+ if (enableSupervisor !== undefined) {
96
+ config.enableSupervisor = enableSupervisor;
97
+ }
98
+
99
+ if (hostConfig) {
100
+ config.orchestratorModel = hostConfig.model;
101
+ config.orchestratorProvider = hostConfig.provider;
102
+ }
103
+
88
104
  await createGroup(
89
105
  {
106
+ config: Object.keys(config).length > 0 ? config : undefined,
90
107
  title: 'New Group Chat',
91
108
  },
92
109
  selectedAgents,
@@ -5,11 +5,11 @@ import { Button, Checkbox, Empty, Switch } from 'antd';
5
5
  import { createStyles, useTheme } from 'antd-style';
6
6
  import { omit } from 'lodash-es';
7
7
  import { Users } from 'lucide-react';
8
- import { ChangeEvent, memo, useCallback, useEffect, useMemo, useState } from 'react';
8
+ import { ChangeEvent, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
9
9
  import { useTranslation } from 'react-i18next';
10
10
  import { Flexbox } from 'react-layout-kit';
11
11
 
12
- import { DEFAULT_AVATAR, DEFAULT_SUPERVISOR_AVATAR } from '@/const/meta';
12
+ import { DEFAULT_AVATAR } from '@/const/meta';
13
13
  import ModelSelect from '@/features/ModelSelect';
14
14
  import { useEnabledChatModels } from '@/hooks/useEnabledChatModels';
15
15
  import { useSessionStore } from '@/store/session';
@@ -233,6 +233,7 @@ const ChatGroupWizard = memo<ChatGroupWizardProps>(
233
233
  return { model: undefined, provider: undefined };
234
234
  }, [enabledModels]);
235
235
 
236
+ const [inputValue, setInputValue] = useState('');
236
237
  const [searchTerm, setSearchTerm] = useState('');
237
238
  const [selectedTemplate, setSelectedTemplate] = useState<string>('');
238
239
  const [selectedAgents, setSelectedAgents] = useState<string[]>([]);
@@ -244,6 +245,8 @@ const ChatGroupWizard = memo<ChatGroupWizardProps>(
244
245
  const [isCreatingCustom, setIsCreatingCustom] = useState(false);
245
246
  const [activePanel, setActivePanel] = useState<'templates' | 'agents'>('templates');
246
247
 
248
+ const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
249
+
247
250
  const isCreatingFromTemplate = externalLoading ?? false;
248
251
 
249
252
  const handleTemplateToggle = useCallback((templateId: string) => {
@@ -278,10 +281,16 @@ const ChatGroupWizard = memo<ChatGroupWizardProps>(
278
281
  const handleReset = () => {
279
282
  setSelectedTemplate('');
280
283
  setSelectedAgents([]);
284
+ setInputValue('');
281
285
  setSearchTerm('');
282
286
  setRemovedMembers({});
283
287
  setIsHostRemoved(false);
284
288
  setHostModelConfig(defaultModel.model && defaultModel.provider ? defaultModel : {});
289
+
290
+ // Clear any pending debounce timer
291
+ if (debounceTimerRef.current) {
292
+ clearTimeout(debounceTimerRef.current);
293
+ }
285
294
  };
286
295
 
287
296
  const handleHostModelChange = useCallback((config: { model?: string; provider?: string }) => {
@@ -319,11 +328,31 @@ const ChatGroupWizard = memo<ChatGroupWizardProps>(
319
328
  }, []);
320
329
 
321
330
  const handleSearchChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
322
- setSearchTerm(event.target.value);
331
+ const value = event.target.value;
332
+ setInputValue(value);
333
+
334
+ // Clear previous timer
335
+ if (debounceTimerRef.current) {
336
+ clearTimeout(debounceTimerRef.current);
337
+ }
338
+
339
+ // Set new timer to update searchTerm after 300ms
340
+ debounceTimerRef.current = setTimeout(() => {
341
+ setSearchTerm(value);
342
+ }, 300);
323
343
  }, []);
324
344
 
325
345
  const agentCount = visibleAgentSessions.length;
326
346
 
347
+ // Cleanup debounce timer on unmount
348
+ useEffect(() => {
349
+ return () => {
350
+ if (debounceTimerRef.current) {
351
+ clearTimeout(debounceTimerRef.current);
352
+ }
353
+ };
354
+ }, []);
355
+
327
356
  useEffect(() => {
328
357
  if (!open) return;
329
358
 
@@ -551,7 +580,7 @@ const ChatGroupWizard = memo<ChatGroupWizardProps>(
551
580
  onChange={handleSearchChange}
552
581
  placeholder={t('memberSelection.searchAgents')}
553
582
  style={{ margin: `${theme.paddingSM}px ${theme.paddingSM}px 0 ${theme.paddingSM}px` }}
554
- value={searchTerm}
583
+ value={inputValue}
555
584
  variant="filled"
556
585
  />
557
586
  <Flexbox flex={1} style={{ overflowY: 'auto', padding: `0 ${theme.paddingSM}px` }}>
@@ -636,7 +665,6 @@ const ChatGroupWizard = memo<ChatGroupWizardProps>(
636
665
  <Flexbox className={styles.rightColumn} flex={1}>
637
666
  <Flexbox flex={1} gap={16} style={{ overflowY: 'auto' }}>
638
667
  <Flexbox align="center" className={styles.hostCard} gap={12} horizontal>
639
- <Avatar avatar={DEFAULT_SUPERVISOR_AVATAR} shape="circle" size={40} />
640
668
  <Flexbox flex={1} gap={2}>
641
669
  <Text
642
670
  style={{ fontSize: 14, fontWeight: 500 }}
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
- import { ActionIcon, Avatar, List, Modal, SearchBar } from '@lobehub/ui';
3
+ import { ActionIcon, Avatar, List, Modal, SearchBar, Text, Tooltip } from '@lobehub/ui';
4
4
  import { useHover } from 'ahooks';
5
- import { List as AntdList, Button, Checkbox, Empty, Typography } from 'antd';
5
+ import { List as AntdList, Button, Checkbox, Empty, Switch, Typography } from 'antd';
6
6
  import { createStyles } from 'antd-style';
7
7
  import { X } from 'lucide-react';
8
8
  import { type ChangeEvent, memo, useCallback, useMemo, useRef, useState } from 'react';
@@ -10,10 +10,12 @@ import { useTranslation } from 'react-i18next';
10
10
  import { Flexbox } from 'react-layout-kit';
11
11
 
12
12
  import { DEFAULT_AVATAR } from '@/const/meta';
13
+ import ModelSelect from '@/features/ModelSelect';
14
+ import { useEnabledChatModels } from '@/hooks/useEnabledChatModels';
13
15
  import { useSessionStore } from '@/store/session';
14
16
  import { LobeAgentSession, LobeSessionType } from '@/types/session';
15
17
 
16
- const { Text } = Typography;
18
+ const { Text: AntText } = Typography;
17
19
 
18
20
  const AvailableAgentItem = memo<{
19
21
  agent: LobeAgentSession;
@@ -56,11 +58,11 @@ const AvailableAgentItem = memo<{
56
58
  />
57
59
  </Flexbox>
58
60
  <Flexbox flex={1} gap={2} style={{ minWidth: 0 }}>
59
- <Text className={styles.title}>{title}</Text>
61
+ <AntText className={styles.title}>{title}</AntText>
60
62
  {description && (
61
- <Text className={styles.description} ellipsis>
63
+ <AntText className={styles.description} ellipsis>
62
64
  {description}
63
- </Text>
65
+ </AntText>
64
66
  )}
65
67
  </Flexbox>
66
68
  </Flexbox>
@@ -82,6 +84,14 @@ const useStyles = createStyles(({ css, token }) => ({
82
84
  line-height: 1.2;
83
85
  color: ${token.colorTextSecondary};
84
86
  `,
87
+ hostCard: css`
88
+ margin-block-end: ${token.paddingSM}px;
89
+ padding: ${token.padding}px;
90
+ border: 1px solid ${token.colorBorderSecondary};
91
+ border-radius: ${token.borderRadiusLG}px;
92
+
93
+ background: ${token.colorFillTertiary};
94
+ `,
85
95
  leftColumn: css`
86
96
  user-select: none;
87
97
 
@@ -107,6 +117,9 @@ const useStyles = createStyles(({ css, token }) => ({
107
117
  background: ${token.colorFillTertiary};
108
118
  }
109
119
  `,
120
+ modelSelectDisabled: css`
121
+ pointer-events: none;
122
+ `,
110
123
  rightColumn: css`
111
124
  overflow-y: auto;
112
125
  flex: 1;
@@ -121,6 +134,14 @@ const useStyles = createStyles(({ css, token }) => ({
121
134
  export type MemberSelectionMode = 'create' | 'add';
122
135
 
123
136
  export interface MemberSelectionModalProps {
137
+ /**
138
+ * Current host configuration (for add mode)
139
+ */
140
+ currentHostConfig?: {
141
+ enableSupervisor?: boolean;
142
+ orchestratorModel?: string;
143
+ orchestratorProvider?: string;
144
+ };
124
145
  /**
125
146
  * Existing group members to exclude from available agents (for add mode)
126
147
  */
@@ -136,7 +157,11 @@ export interface MemberSelectionModalProps {
136
157
  */
137
158
  mode: MemberSelectionMode;
138
159
  onCancel: () => void;
139
- onConfirm: (selectedAgents: string[]) => void | Promise<void>;
160
+ onConfirm: (
161
+ selectedAgents: string[],
162
+ hostConfig?: { model?: string; provider?: string },
163
+ enableSupervisor?: boolean,
164
+ ) => void | Promise<void>;
140
165
  open: boolean;
141
166
  /**
142
167
  * Pre-selected agent IDs (useful for editing existing groups)
@@ -145,15 +170,56 @@ export interface MemberSelectionModalProps {
145
170
  }
146
171
 
147
172
  const MemberSelectionModal = memo<MemberSelectionModalProps>(
148
- ({ existingMembers = [], mode, onCancel, onConfirm, open, preSelectedAgents = [] }) => {
173
+ ({
174
+ currentHostConfig,
175
+ existingMembers = [],
176
+ mode,
177
+ onCancel,
178
+ onConfirm,
179
+ open,
180
+ preSelectedAgents = [],
181
+ }) => {
149
182
  const { t } = useTranslation(['chat', 'common']);
150
183
  const { styles, cx } = useStyles();
184
+ const enabledModels = useEnabledChatModels();
151
185
  const [selectedAgents, setSelectedAgents] = useState<string[]>(preSelectedAgents);
152
186
  const [searchTerm, setSearchTerm] = useState('');
153
187
 
188
+ // Determine if host card should be shown
189
+ const isHostCurrentlyEnabled = mode === 'add' && currentHostConfig?.enableSupervisor === true;
190
+
191
+ // Initialize host state:
192
+ // - In create mode: default to enabled (isHostRemoved = false)
193
+ // - In add mode with host disabled: default to disabled (isHostRemoved = true)
194
+ const [isHostRemoved, setIsHostRemoved] = useState(mode === 'add' ? true : false);
195
+ const [hostModelConfig, setHostModelConfig] = useState<{ model?: string; provider?: string }>(
196
+ () => {
197
+ if (mode === 'add' && currentHostConfig) {
198
+ return {
199
+ model: currentHostConfig.orchestratorModel,
200
+ provider: currentHostConfig.orchestratorProvider,
201
+ };
202
+ }
203
+ // Set default for create mode
204
+ if (enabledModels.length > 0 && enabledModels[0].children.length > 0) {
205
+ const firstProvider = enabledModels[0];
206
+ const firstModel = firstProvider.children[0];
207
+
208
+ return {
209
+ model: firstModel.id,
210
+ provider: firstProvider.id,
211
+ };
212
+ }
213
+ return {};
214
+ },
215
+ );
216
+
154
217
  const agentSessions = useSessionStore((s) => {
155
218
  const allSessions = s.sessions || [];
156
- return allSessions.filter((session) => session.type === LobeSessionType.Agent);
219
+ return allSessions.filter(
220
+ (session): session is LobeAgentSession =>
221
+ session.type === LobeSessionType.Agent && !session.config?.virtual,
222
+ );
157
223
  });
158
224
 
159
225
  const currentSessionId = useSessionStore((s) => s.activeId);
@@ -172,6 +238,14 @@ const MemberSelectionModal = memo<MemberSelectionModalProps>(
172
238
  setSearchTerm(e.target.value);
173
239
  }, []);
174
240
 
241
+ const handleHostToggle = useCallback((enabled: boolean) => {
242
+ setIsHostRemoved(!enabled);
243
+ }, []);
244
+
245
+ const handleHostModelChange = useCallback((config: { model?: string; provider?: string }) => {
246
+ setHostModelConfig(config);
247
+ }, []);
248
+
175
249
  // Filter logic based on mode
176
250
  const availableAgents = useMemo(() => {
177
251
  if (mode === 'create') {
@@ -237,14 +311,35 @@ const MemberSelectionModal = memo<MemberSelectionModalProps>(
237
311
  const handleReset = () => {
238
312
  setSelectedAgents(preSelectedAgents);
239
313
  setSearchTerm('');
314
+ setIsHostRemoved(mode === 'add' ? true : false);
315
+ if (mode === 'add' && currentHostConfig) {
316
+ setHostModelConfig({
317
+ model: currentHostConfig.orchestratorModel,
318
+ provider: currentHostConfig.orchestratorProvider,
319
+ });
320
+ }
240
321
  };
241
322
 
242
323
  const [isAdding, setIsAdding] = useState(false);
243
324
 
325
+ const normalizedHostModelConfig = useMemo(() => {
326
+ const model = hostModelConfig.model;
327
+ const provider = hostModelConfig.provider;
328
+
329
+ if (!model || !provider) return undefined;
330
+
331
+ return { model, provider };
332
+ }, [hostModelConfig]);
333
+
244
334
  const handleConfirm = async () => {
245
335
  try {
246
336
  setIsAdding(true);
247
- await onConfirm(selectedAgents);
337
+ // Only pass host config if the host card is visible (being managed in this modal)
338
+ const shouldManageHost = !isHostCurrentlyEnabled;
339
+ const hostConfig =
340
+ shouldManageHost && !isHostRemoved ? normalizedHostModelConfig : undefined;
341
+ const enableSupervisor = shouldManageHost ? !isHostRemoved : undefined;
342
+ await onConfirm(selectedAgents, hostConfig, enableSupervisor);
248
343
  handleReset();
249
344
  } catch (error) {
250
345
  console.error('Failed to confirm action:', error);
@@ -265,8 +360,13 @@ const MemberSelectionModal = memo<MemberSelectionModalProps>(
265
360
  const confirmButtonText =
266
361
  mode === 'create' ? t('memberSelection.createGroup') : t('memberSelection.addMember');
267
362
 
363
+ // Calculate total member count including host if enabled
364
+ // Only count the host when the host card is visible (create mode or add mode with host disabled)
365
+ const shouldShowHostCard = !isHostCurrentlyEnabled;
366
+ const totalMemberCount = selectedAgents.length + (shouldShowHostCard && !isHostRemoved ? 1 : 0);
367
+
268
368
  const minMembersRequired = mode === 'create' ? 1 : 0; // At least 1 member for group creation
269
- const isConfirmDisabled = selectedAgents.length < minMembersRequired || isAdding;
369
+ const isConfirmDisabled = totalMemberCount < minMembersRequired || isAdding;
270
370
 
271
371
  return (
272
372
  <Modal
@@ -280,7 +380,7 @@ const MemberSelectionModal = memo<MemberSelectionModalProps>(
280
380
  onClick={handleConfirm}
281
381
  type="primary"
282
382
  >
283
- {confirmButtonText} ({selectedAgents.length})
383
+ {confirmButtonText} ({totalMemberCount})
284
384
  </Button>
285
385
  </Flexbox>
286
386
  }
@@ -337,22 +437,66 @@ const MemberSelectionModal = memo<MemberSelectionModalProps>(
337
437
  </Flexbox>
338
438
  </Flexbox>
339
439
 
340
- {/* Right Column - Selected Agents */}
440
+ {/* Right Column - Host and Selected Agents */}
341
441
  <Flexbox className={styles.rightColumn} flex={1}>
342
- {selectedAgentListItems.length === 0 ? (
343
- <Flexbox align="center" flex={1} justify="center">
344
- <Empty
345
- description={
346
- mode === 'create'
347
- ? t('memberSelection.noSelectedAgents')
348
- : t('memberSelection.noSelectedAgents')
349
- }
350
- image={Empty.PRESENTED_IMAGE_SIMPLE}
351
- />
442
+ <Flexbox gap={16}>
443
+ {/* Host Card - Only show in create mode or when host is disabled in add mode */}
444
+ {!isHostCurrentlyEnabled && (
445
+ <Flexbox align="center" className={styles.hostCard} gap={12} horizontal>
446
+ <Flexbox flex={1} gap={2}>
447
+ <Text
448
+ style={{ fontSize: 14, fontWeight: 500 }}
449
+ type={isHostRemoved ? 'secondary' : undefined}
450
+ >
451
+ {t('groupWizard.host.title')}
452
+ </Text>
453
+ <Text
454
+ style={{ color: '#999', fontSize: 12 }}
455
+ type={isHostRemoved ? 'secondary' : undefined}
456
+ >
457
+ {t('groupWizard.host.description')}
458
+ </Text>
459
+ </Flexbox>
460
+ <Flexbox align="center" gap={12} horizontal>
461
+ <div
462
+ className={cx(isHostRemoved && styles.modelSelectDisabled)}
463
+ style={{ opacity: isHostRemoved ? 0.6 : 1 }}
464
+ >
465
+ <ModelSelect
466
+ onChange={handleHostModelChange}
467
+ requiredAbilities={['functionCall']}
468
+ value={normalizedHostModelConfig}
469
+ />
470
+ </div>
471
+ <Tooltip title={t('groupWizard.host.tooltip')}>
472
+ <Switch
473
+ checked={!isHostRemoved}
474
+ onChange={(checked) => handleHostToggle(checked)}
475
+ size="small"
476
+ />
477
+ </Tooltip>
478
+ </Flexbox>
479
+ </Flexbox>
480
+ )}
481
+
482
+ {/* Selected Agents List */}
483
+ <Flexbox flex={1}>
484
+ {selectedAgentListItems.length === 0 ? (
485
+ <Flexbox align="center" flex={1} justify="center">
486
+ <Empty
487
+ description={
488
+ mode === 'create'
489
+ ? t('memberSelection.noSelectedAgents')
490
+ : t('memberSelection.noSelectedAgents')
491
+ }
492
+ image={Empty.PRESENTED_IMAGE_SIMPLE}
493
+ />
494
+ </Flexbox>
495
+ ) : (
496
+ <List items={selectedAgentListItems} />
497
+ )}
352
498
  </Flexbox>
353
- ) : (
354
- <List items={selectedAgentListItems} />
355
- )}
499
+ </Flexbox>
356
500
  </Flexbox>
357
501
  </Flexbox>
358
502
  </Modal>
@@ -8,6 +8,8 @@ import ShareMessageModal from '@/features/Conversation/components/ShareMessageMo
8
8
  import { VirtuosoContext } from '@/features/Conversation/components/VirtualizedList/VirtuosoContext';
9
9
  import { useChatStore } from '@/store/chat';
10
10
  import { threadSelectors } from '@/store/chat/selectors';
11
+ import { useSessionStore } from '@/store/session';
12
+ import { sessionSelectors } from '@/store/session/selectors';
11
13
  import { ChatMessage } from '@/types/message';
12
14
 
13
15
  import { InPortalThreadContext } from '../../../context/InPortalThreadContext';
@@ -25,6 +27,7 @@ export const AssistantActionsBar = memo<AssistantActionsProps>(({ id, data, inde
25
27
  !!s.activeThreadId,
26
28
  threadSelectors.hasThreadBySourceMsgId(id)(s),
27
29
  ]);
30
+ const isGroupSession = useSessionStore(sessionSelectors.isCurrentSessionGroupSession);
28
31
  const [showShareModal, setShareModal] = useState(false);
29
32
 
30
33
  const {
@@ -49,8 +52,10 @@ export const AssistantActionsBar = memo<AssistantActionsProps>(({ id, data, inde
49
52
  const items = useMemo(() => {
50
53
  if (hasTools) return [delAndRegenerate, copy];
51
54
 
52
- return [edit, copy, inThread ? null : branching].filter(Boolean) as ActionIconGroupItemType[];
53
- }, [inThread, hasTools]);
55
+ return [edit, copy, inThread || isGroupSession ? null : branching].filter(
56
+ Boolean,
57
+ ) as ActionIconGroupItemType[];
58
+ }, [inThread, hasTools, isGroupSession]);
54
59
 
55
60
  const { t } = useTranslation('common');
56
61
  const searchParams = useSearchParams();
@@ -52,8 +52,10 @@ const Render = memo<RenderProps>(
52
52
 
53
53
  // 如果是 LOADING_FLAT 则说明还在加载中
54
54
  // 而 standalone 模式的插件 content 应该始终是 LOADING_FLAT
55
- if (toolMessage.content === LOADING_FLAT && toolMessage.plugin?.type !== 'standalone')
56
- return placeholder;
55
+ const inPlaceholder =
56
+ toolMessage.content === LOADING_FLAT && toolMessage.plugin?.type !== 'standalone';
57
+
58
+ if (inPlaceholder) return placeholder;
57
59
 
58
60
  return (
59
61
  <Suspense fallback={placeholder}>
@@ -9,6 +9,8 @@ import { useTranslation } from 'react-i18next';
9
9
 
10
10
  import { useChatStore } from '@/store/chat';
11
11
  import { threadSelectors } from '@/store/chat/selectors';
12
+ import { useSessionStore } from '@/store/session';
13
+ import { sessionSelectors } from '@/store/session/selectors';
12
14
 
13
15
  import { VirtuosoContext } from '../../components/VirtualizedList/VirtuosoContext';
14
16
  import { InPortalThreadContext } from '../../context/InPortalThreadContext';
@@ -54,6 +56,8 @@ export const UserActionsBar = memo<UserActionsProps>(({ id, data, index }) => {
54
56
  s.delAndResendThreadMessage,
55
57
  ]);
56
58
 
59
+ const isGroupSession = useSessionStore(sessionSelectors.isCurrentSessionGroupSession);
60
+
57
61
  const { regenerate, edit, copy, divider, del, branching, tts, translate } = useChatListActionsBar(
58
62
  { hasThread },
59
63
  );
@@ -63,8 +67,10 @@ export const UserActionsBar = memo<UserActionsProps>(({ id, data, index }) => {
63
67
 
64
68
  const items = useMemo(
65
69
  () =>
66
- [regenerate, edit, inThread ? null : branching].filter(Boolean) as ActionIconGroupItemType[],
67
- [inThread],
70
+ [regenerate, edit, inThread || isGroupSession ? null : branching].filter(
71
+ Boolean,
72
+ ) as ActionIconGroupItemType[],
73
+ [inThread, isGroupSession],
68
74
  );
69
75
 
70
76
  const { message } = App.useApp();
@@ -22,9 +22,9 @@ import { selectors, useStore } from './store';
22
22
  const { TextArea } = Input;
23
23
 
24
24
  /**
25
- * Chat Settings for Group Chat
25
+ * Chat Settings for Agent Team (Group Chat)
26
26
  */
27
- const ChatGroupSettings = memo(() => {
27
+ const AgentTeamChatSettings = memo(() => {
28
28
  const { t } = useTranslation(['setting', 'common']);
29
29
  const [form] = Form.useForm();
30
30
  const updateConfig = useStore((s) => s.updateGroupConfig);
@@ -171,8 +171,9 @@ const ChatGroupSettings = memo(() => {
171
171
  itemsType={'group'}
172
172
  onFinish={async ({ _modelConfig, ...rest }) => {
173
173
  await updateConfig({
174
- orchestratorModel: _modelConfig?.model,
175
- orchestratorProvider: _modelConfig?.provider,
174
+ // Preserve existing values when _modelConfig is undefined (enableSupervisor is false)
175
+ orchestratorModel: _modelConfig?.model ?? config?.orchestratorModel,
176
+ orchestratorProvider: _modelConfig?.provider ?? config?.orchestratorProvider,
176
177
  ...rest,
177
178
  });
178
179
 
@@ -184,4 +185,4 @@ const ChatGroupSettings = memo(() => {
184
185
  );
185
186
  });
186
187
 
187
- export default ChatGroupSettings;
188
+ export default AgentTeamChatSettings;