mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-27 13:29:15 +07:00
🐛 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:
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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 />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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} />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user