🐛 fix: add advace config back in agent/group profiles (#11727)

* fix: add the agents advace config modal back

* feat: add the group/profiles the advance settings
This commit is contained in:
Shinji-Li
2026-01-23 16:39:46 +08:00
committed by GitHub
parent c484d1aa1b
commit 403175f7fb
8 changed files with 381 additions and 10 deletions

View File

@@ -0,0 +1,133 @@
'use client';
import { Avatar, Block, Flexbox, Icon, Text } from '@lobehub/ui';
import { useTheme } from 'antd-style';
import type { ItemType } from 'antd/es/menu/interface';
import isEqual from 'fast-deep-equal';
import { BrainIcon, MessageSquareHeartIcon, Settings2Icon } from 'lucide-react';
import { memo, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Menu from '@/components/Menu';
import { DEFAULT_AVATAR, DEFAULT_INBOX_AVATAR } from '@/const/meta';
import { AgentSettings as Settings } from '@/features/AgentSetting';
import { useAgentStore } from '@/store/agent';
import { agentSelectors, builtinAgentSelectors } from '@/store/agent/selectors';
import { ChatSettingsTabs } from '@/store/global/initialState';
const Content = memo(() => {
const { t } = useTranslation('setting');
const theme = useTheme();
const [agentId, isInbox] = useAgentStore((s) => [
s.activeAgentId,
builtinAgentSelectors.isInboxAgent(s),
]);
const config = useAgentStore(agentSelectors.currentAgentConfig, isEqual);
const meta = useAgentStore(agentSelectors.currentAgentMeta, isEqual);
const [tab, setTab] = useState(ChatSettingsTabs.Chat);
const updateAgentConfig = async (config: any) => {
if (!agentId) return;
await useAgentStore.getState().optimisticUpdateAgentConfig(agentId, config);
};
const updateAgentMeta = async (meta: any) => {
if (!agentId) return;
await useAgentStore.getState().optimisticUpdateAgentMeta(agentId, meta);
};
const menuItems: ItemType[] = useMemo(
() =>
[
{
icon: <Icon icon={Settings2Icon} />,
key: ChatSettingsTabs.Chat,
label: t('agentTab.chat'),
},
!isInbox
? {
icon: <Icon icon={MessageSquareHeartIcon} />,
key: ChatSettingsTabs.Opening,
label: t('agentTab.opening'),
}
: null,
{
icon: <Icon icon={BrainIcon} />,
key: ChatSettingsTabs.Modal,
label: t('agentTab.modal'),
},
].filter(Boolean) as ItemType[],
[t, isInbox],
);
const displayTitle = isInbox ? 'Lobe AI' : meta.title || t('defaultSession', { ns: 'common' });
return (
<Flexbox
direction="horizontal"
height="100%"
style={{
padding: 0,
position: 'relative',
}}
>
<Flexbox
height={'100%'}
paddingBlock={24}
paddingInline={8}
style={{
background: theme.colorBgLayout,
borderRight: `1px solid ${theme.colorBorderSecondary}`,
}}
width={200}
>
<Block
align={'center'}
gap={8}
horizontal
paddingBlock={'14px 16px'}
paddingInline={4}
style={{
overflow: 'hidden',
}}
variant={'borderless'}
>
<Avatar
avatar={isInbox ? DEFAULT_INBOX_AVATAR : meta.avatar || DEFAULT_AVATAR}
background={meta.backgroundColor || undefined}
shape={'square'}
size={28}
/>
<Text ellipsis weight={500}>
{displayTitle}
</Text>
</Block>
<Menu
items={menuItems}
onClick={({ key }) => setTab(key as ChatSettingsTabs)}
selectable
selectedKeys={[tab]}
style={{ width: '100%' }}
/>
</Flexbox>
<Flexbox
flex={1}
paddingBlock={24}
paddingInline={64}
style={{ overflow: 'scroll', width: '100%' }}
>
<Settings
config={config}
id={agentId}
loading={false}
meta={meta}
onConfigChange={updateAgentConfig}
onMetaChange={updateAgentMeta}
tab={tab}
/>
</Flexbox>
</Flexbox>
);
});
export default Content;

View File

@@ -0,0 +1,35 @@
'use client';
import { Modal } from '@lobehub/ui';
import { memo } from 'react';
import { useAgentStore } from '@/store/agent';
import Content from './Content';
const AgentSettings = memo(() => {
const showAgentSetting = useAgentStore((s) => s.showAgentSetting);
return (
<Modal
centered
footer={null}
onCancel={() => useAgentStore.setState({ showAgentSetting: false })}
open={showAgentSetting}
styles={{
body: {
height: '60vh',
overflow: 'scroll',
padding: 0,
position: 'relative',
},
}}
title={null}
width={960}
>
<Content />
</Modal>
);
});
export default AgentSettings;

View File

@@ -3,8 +3,9 @@
import { ENABLE_BUSINESS_FEATURES } from '@lobechat/business-const';
import { Button, Flexbox } from '@lobehub/ui';
import { Divider } from 'antd';
import { useTheme } from 'antd-style';
import isEqual from 'fast-deep-equal';
import { Clock, PlayIcon } from 'lucide-react';
import { Clock, PlayIcon, Settings2Icon } from 'lucide-react';
import React, { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import urlJoin from 'url-join';
@@ -16,6 +17,7 @@ import { agentSelectors } from '@/store/agent/selectors';
import { useChatStore } from '@/store/chat';
import AgentCronJobs from '../AgentCronJobs';
import AgentSettings from '../AgentSettings';
import EditorCanvas from '../EditorCanvas';
import AgentPublishButton from '../Header/AgentPublishButton';
import AgentHeader from './AgentHeader';
@@ -23,6 +25,7 @@ import AgentTool from './AgentTool';
const ProfileEditor = memo(() => {
const { t } = useTranslation('setting');
const theme = useTheme();
const config = useAgentStore(agentSelectors.currentAgentConfig, isEqual);
const updateConfig = useAgentStore((s) => s.updateAgentConfig);
const agentId = useAgentStore((s) => s.activeAgentId);
@@ -44,7 +47,7 @@ const ProfileEditor = memo(() => {
>
{/* Header: Avatar + Name + Description */}
<AgentHeader />
{/* Config Bar: Model Selector */}
{/* Config Bar: Model Selector + Settings Button */}
<Flexbox
align={'center'}
gap={8}
@@ -59,6 +62,15 @@ const ProfileEditor = memo(() => {
provider: config.provider,
}}
/>
<Button
icon={Settings2Icon}
onClick={() => useAgentStore.setState({ showAgentSetting: true })}
size={'small'}
style={{ color: theme.colorTextSecondary }}
type={'text'}
>
{t('advancedSettings')}
</Button>
</Flexbox>
<AgentTool />
<Flexbox
@@ -93,6 +105,8 @@ const ProfileEditor = memo(() => {
<EditorCanvas />
{/* Agent Cron Jobs Display (only show if jobs exist) */}
{ENABLE_BUSINESS_FEATURES && <AgentCronJobs />}
{/* Advanced Settings Modal */}
<AgentSettings />
</>
);
});

View File

@@ -0,0 +1,140 @@
'use client';
import { Avatar, Block, Flexbox, Icon, Text } from '@lobehub/ui';
import { useTheme } from 'antd-style';
import type { ItemType } from 'antd/es/menu/interface';
import { MessageSquareHeartIcon } from 'lucide-react';
import { memo, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Menu from '@/components/Menu';
import { DEFAULT_AVATAR } from '@/const/meta';
import { AgentSettings as Settings } from '@/features/AgentSetting';
import { useAgentGroupStore } from '@/store/agentGroup';
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
import { ChatSettingsTabs } from '@/store/global/initialState';
const Content = memo(() => {
const { t } = useTranslation('setting');
const theme = useTheme();
const groupId = useAgentGroupStore(agentGroupSelectors.activeGroupId);
const currentGroup = useAgentGroupStore(agentGroupSelectors.currentGroup);
const [tab] = useState(ChatSettingsTabs.Opening);
const updateGroupConfig = async (config: any) => {
if (!groupId) return;
// Only update openingMessage and openingQuestions
const groupConfig = {
openingMessage: config.openingMessage,
openingQuestions: config.openingQuestions,
};
await useAgentGroupStore.getState().updateGroupConfig(groupConfig);
};
const updateGroupMeta = async (meta: any) => {
if (!groupId) return;
await useAgentGroupStore.getState().updateGroup(groupId, meta);
};
// Convert group config to agent config format for AgentSettings component
const agentConfig = useMemo(
() =>
({
chatConfig: {},
model: '',
openingMessage: currentGroup?.config?.openingMessage,
openingQuestions: currentGroup?.config?.openingQuestions,
params: {},
systemRole: '',
tts: {},
}) as any,
[currentGroup?.config],
);
const agentMeta = useMemo(
() => ({
avatar: currentGroup?.avatar || undefined,
backgroundColor: currentGroup?.backgroundColor || undefined,
description: currentGroup?.description || undefined,
tags: [] as string[],
title: currentGroup?.title || undefined,
}),
[currentGroup],
);
const menuItems: ItemType[] = useMemo(
() => [
{
icon: <Icon icon={MessageSquareHeartIcon} />,
key: ChatSettingsTabs.Opening,
label: t('agentTab.opening'),
},
],
[t],
);
const displayTitle = currentGroup?.title || t('defaultSession', { ns: 'common' });
return (
<Flexbox
direction="horizontal"
height="100%"
style={{
padding: 0,
position: 'relative',
}}
>
<Flexbox
height={'100%'}
paddingBlock={24}
paddingInline={8}
style={{
background: theme.colorBgLayout,
borderRight: `1px solid ${theme.colorBorderSecondary}`,
}}
width={200}
>
<Block
align={'center'}
gap={8}
horizontal
paddingBlock={'14px 16px'}
paddingInline={4}
style={{
overflow: 'hidden',
}}
variant={'borderless'}
>
<Avatar
avatar={currentGroup?.avatar || DEFAULT_AVATAR}
background={currentGroup?.backgroundColor || undefined}
shape={'square'}
size={28}
/>
<Text ellipsis weight={500}>
{displayTitle}
</Text>
</Block>
<Menu items={menuItems} selectable selectedKeys={[tab]} style={{ width: '100%' }} />
</Flexbox>
<Flexbox
flex={1}
paddingBlock={24}
paddingInline={64}
style={{ overflow: 'scroll', width: '100%' }}
>
<Settings
config={agentConfig}
id={groupId}
loading={false}
meta={agentMeta}
onConfigChange={updateGroupConfig}
onMetaChange={updateGroupMeta}
tab={tab}
/>
</Flexbox>
</Flexbox>
);
});
export default Content;

View File

@@ -0,0 +1,36 @@
'use client';
import { Modal } from '@lobehub/ui';
import { memo } from 'react';
import Content from './Content';
interface AgentSettingsProps {
onCancel: () => void;
open: boolean;
}
const AgentSettings = memo<AgentSettingsProps>(({ open, onCancel }) => {
return (
<Modal
centered
footer={null}
onCancel={onCancel}
open={open}
styles={{
body: {
height: '60vh',
overflow: 'scroll',
padding: 0,
position: 'relative',
},
}}
title={null}
width={960}
>
<Content />
</Modal>
);
});
export default AgentSettings;

View File

@@ -2,8 +2,9 @@
import { Button, Flexbox } from '@lobehub/ui';
import { Divider } from 'antd';
import { PlayIcon } from 'lucide-react';
import { memo, useCallback, useMemo } from 'react';
import { useTheme } from 'antd-style';
import { PlayIcon, Settings2Icon } from 'lucide-react';
import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import urlJoin from 'url-join';
@@ -13,12 +14,15 @@ import { useAgentGroupStore } from '@/store/agentGroup';
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
import { useGroupProfileStore } from '@/store/groupProfile';
import AgentSettings from '../AgentSettings';
import AutoSaveHint from '../Header/AutoSaveHint';
import GroupPublishButton from '../Header/GroupPublishButton';
import GroupHeader from './GroupHeader';
const GroupProfile = memo(() => {
const { t } = useTranslation(['setting', 'chat']);
const theme = useTheme();
const [showAgentSetting, setShowAgentSetting] = useState(false);
const groupId = useAgentGroupStore(agentGroupSelectors.activeGroupId);
const currentGroup = useAgentGroupStore(agentGroupSelectors.currentGroup);
const updateGroup = useAgentGroupStore((s) => s.updateGroup);
@@ -86,6 +90,15 @@ const GroupProfile = memo(() => {
{t('startConversation')}
</Button>
<GroupPublishButton />
<Button
icon={Settings2Icon}
onClick={() => setShowAgentSetting(true)}
size={'small'}
style={{ color: theme.colorTextSecondary }}
type={'text'}
>
{t('advancedSettings')}
</Button>
</Flexbox>
</Flexbox>
<Divider />
@@ -97,6 +110,8 @@ const GroupProfile = memo(() => {
onContentChange={onContentChange}
placeholder={t('group.profile.contentPlaceholder', { ns: 'chat' })}
/>
{/* Advanced Settings Modal */}
<AgentSettings onCancel={() => setShowAgentSetting(false)} open={showAgentSetting} />
</>
);
});

View File

@@ -86,13 +86,14 @@ const OpeningQuestions = memo(() => {
const isRepeat = openingQuestions.includes(questionInput.trim());
return (
<Flexbox gap={8}>
<Flexbox gap={4}>
<Space.Compact>
<Flexbox gap={8} width={'100%'}>
<Flexbox gap={4} width={'100%'}>
<Space.Compact style={{ width: '100%' }}>
<Input
onChange={(e) => setQuestionInput(e.target.value)}
onPressEnter={addQuestion}
placeholder={t('settingOpening.openingQuestions.placeholder')}
style={{ flex: 1 }}
value={questionInput}
/>
<Button

View File

@@ -4,8 +4,6 @@ import { Form } from '@lobehub/ui';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { FORM_STYLE } from '@/const/layoutTokens';
import OpeningMessage from './OpeningMessage';
import OpeningQuestions from './OpeningQuestions';
@@ -44,7 +42,6 @@ const AgentOpening = memo(() => {
]}
itemsType={'group'}
variant={'borderless'}
{...FORM_STYLE}
/>
);
});