@lobehub/chat 0.33.0 → 0.34.0

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 (60) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/package.json +2 -2
  3. package/src/components/EmojiPicker/index.tsx +48 -0
  4. package/src/components/EmojiPicker/style.ts +28 -0
  5. package/src/const/meta.ts +3 -0
  6. package/src/const/settings.ts +50 -0
  7. package/src/{pages/chat/[id]/edit → features/AgentSetting}/AgentConfig/index.tsx +13 -11
  8. package/src/{pages/chat/[id]/edit → features/AgentSetting}/AgentMeta/AutoGenerateInput.tsx +16 -14
  9. package/src/features/AgentSetting/AgentMeta/BackgroundSwatches.tsx +27 -0
  10. package/src/features/AgentSetting/AgentMeta/index.tsx +128 -0
  11. package/src/{pages/chat/[id]/edit → features/AgentSetting}/AgentPlugin/index.tsx +12 -12
  12. package/src/{pages/chat/[id]/edit → features/AgentSetting}/AgentPrompt/index.tsx +13 -16
  13. package/src/features/AgentSetting/index.ts +4 -0
  14. package/src/features/AgentSetting/test.json +40 -0
  15. package/src/features/SideBar/{BottomAction.tsx → BottomActions.tsx} +15 -5
  16. package/src/features/SideBar/TopActions.tsx +42 -0
  17. package/src/features/SideBar/index.tsx +5 -30
  18. package/src/hooks/useImportConfig.ts +3 -3
  19. package/src/locales/default/common.ts +4 -0
  20. package/src/locales/default/setting.ts +4 -0
  21. package/src/pages/chat/[id]/Conversation/ChatList/index.tsx +1 -1
  22. package/src/pages/chat/[id]/Conversation/Input/Action.tsx +1 -1
  23. package/src/pages/chat/[id]/Header.tsx +1 -1
  24. package/src/pages/chat/[id]/{Config/SideBar.tsx → Sidebar/Inner.tsx} +2 -2
  25. package/src/pages/chat/[id]/{Config → Sidebar}/Topic/TopicContent.tsx +4 -6
  26. package/src/pages/chat/[id]/{Config → Sidebar}/index.tsx +2 -2
  27. package/src/pages/chat/[id]/index.page.tsx +1 -1
  28. package/src/pages/chat/[id]/{edit → setting}/index.page.tsx +23 -9
  29. package/src/pages/settings/Settings/Agent.tsx +25 -0
  30. package/src/pages/{setting/SettingForm.tsx → settings/Settings/Common.tsx} +7 -113
  31. package/src/pages/settings/Settings/index.tsx +50 -0
  32. package/src/pages/{setting → settings}/index.page.tsx +2 -2
  33. package/src/pages/{setting → settings}/layout.tsx +1 -1
  34. package/src/plugins/searchEngine/Render.tsx +3 -1
  35. package/src/store/session/slices/agentConfig/action.ts +8 -1
  36. package/src/store/session/slices/agentConfig/initialState.ts +2 -13
  37. package/src/store/session/slices/agentConfig/selectors.ts +13 -9
  38. package/src/store/session/slices/chat/actions/message.ts +12 -5
  39. package/src/store/session/slices/chat/actions/topic.ts +4 -2
  40. package/src/store/session/slices/chat/selectors/chat.ts +1 -1
  41. package/src/store/session/slices/session/action.ts +23 -16
  42. package/src/store/session/slices/session/initialState.ts +2 -1
  43. package/src/store/settings/action.ts +82 -11
  44. package/src/store/settings/initialState.ts +4 -27
  45. package/src/store/settings/selectors.ts +12 -7
  46. package/src/store/settings/store.ts +2 -2
  47. package/src/types/settings.ts +16 -8
  48. package/src/utils/storeDebug.ts +11 -0
  49. package/src/pages/chat/[id]/edit/AgentMeta/BackgroundSwatches.tsx +0 -31
  50. package/src/pages/chat/[id]/edit/AgentMeta/EmojiPicker.tsx +0 -78
  51. package/src/pages/chat/[id]/edit/AgentMeta/index.tsx +0 -111
  52. /package/src/pages/chat/[id]/{Config → Sidebar}/Header.tsx +0 -0
  53. /package/src/pages/chat/[id]/{Config → Sidebar}/Topic/DefaultContent.tsx +0 -0
  54. /package/src/pages/chat/[id]/{Config → Sidebar}/Topic/TopicItem.tsx +0 -0
  55. /package/src/pages/chat/[id]/{Config → Sidebar}/Topic/index.tsx +0 -0
  56. /package/src/pages/chat/[id]/{edit → setting}/Header.tsx +0 -0
  57. /package/src/pages/{setting → settings}/Header.tsx +0 -0
  58. /package/src/pages/{setting → settings}/ThemeSwatches/ThemeSwatchesNeutral.tsx +0 -0
  59. /package/src/pages/{setting → settings}/ThemeSwatches/ThemeSwatchesPrimary.tsx +0 -0
  60. /package/src/pages/{setting → settings}/ThemeSwatches/index.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,33 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 0.34.0](https://github.com/lobehub/lobe-chat/compare/v0.33.0...v0.34.0)
6
+
7
+ <sup>Released on **2023-07-31**</sup>
8
+
9
+ #### ✨ Features
10
+
11
+ - **misc**: Add agent settings functionality, Add new components and features for AgentMeta, Improve organization and functionality of settings and configuration features.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's improved
19
+
20
+ - **misc**: Add agent settings functionality ([b0aaeed](https://github.com/lobehub/lobe-chat/commit/b0aaeed))
21
+ - **misc**: Add new components and features for AgentMeta ([1232d95](https://github.com/lobehub/lobe-chat/commit/1232d95))
22
+ - **misc**: Improve organization and functionality of settings and configuration features ([badde35](https://github.com/lobehub/lobe-chat/commit/badde35))
23
+
24
+ </details>
25
+
26
+ <div align="right">
27
+
28
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
29
+
30
+ </div>
31
+
5
32
  ## [Version 0.33.0](https://github.com/lobehub/lobe-chat/compare/v0.32.0...v0.33.0)
6
33
 
7
34
  <sup>Released on **2023-07-30**</sup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.33.0",
3
+ "version": "0.34.0",
4
4
  "description": "Lobe Chat is an open-source chatbot client using LangChain, Typescript and Next.js",
5
5
  "keywords": [
6
6
  "chatbot",
@@ -89,7 +89,7 @@
89
89
  "react-hotkeys-hook": "^4",
90
90
  "react-i18next": "^13",
91
91
  "react-layout-kit": "^1",
92
- "serpapi": "^1",
92
+ "serpapi": "^2",
93
93
  "swr": "^2",
94
94
  "ts-md5": "^1",
95
95
  "uuid": "^9",
@@ -0,0 +1,48 @@
1
+ import data from '@emoji-mart/data';
2
+ import i18n from '@emoji-mart/data/i18n/zh.json';
3
+ import Picker from '@emoji-mart/react';
4
+ import { Avatar } from '@lobehub/ui';
5
+ import { Popover } from 'antd';
6
+ import { memo } from 'react';
7
+
8
+ import { DEFAULT_AVATAR, DEFAULT_BACKGROUND_COLOR } from '@/const/meta';
9
+
10
+ import { useStyles } from './style';
11
+
12
+ export interface EmojiPickerProps {
13
+ avatar?: string;
14
+ backgroundColor?: string;
15
+ onChange: (emoji: string) => void;
16
+ }
17
+
18
+ const EmojiPicker = memo<EmojiPickerProps>(
19
+ ({ avatar = DEFAULT_AVATAR, backgroundColor = DEFAULT_BACKGROUND_COLOR, onChange }) => {
20
+ const { styles } = useStyles();
21
+
22
+ return (
23
+ <Popover
24
+ content={
25
+ <div className={styles.picker}>
26
+ <Picker
27
+ data={data}
28
+ i18n={i18n}
29
+ locale={'zh'}
30
+ onEmojiSelect={(e: any) => onChange(e.native)}
31
+ skinTonePosition={'none'}
32
+ theme={'auto'}
33
+ />
34
+ </div>
35
+ }
36
+ placement={'left'}
37
+ rootClassName={styles.popover}
38
+ trigger={'click'}
39
+ >
40
+ <div className={styles.avatar} style={{ width: 'fit-content' }}>
41
+ <Avatar avatar={avatar} background={backgroundColor} size={44} />
42
+ </div>
43
+ </Popover>
44
+ );
45
+ },
46
+ );
47
+
48
+ export default EmojiPicker;
@@ -0,0 +1,28 @@
1
+ import { createStyles } from 'antd-style';
2
+ import chroma from 'chroma-js';
3
+
4
+ export const useStyles = createStyles(({ css, token, prefixCls }) => ({
5
+ avatar: css`
6
+ border-radius: 50%;
7
+ transition: scale 400ms ${token.motionEaseOut}, box-shadow 100ms ${token.motionEaseOut};
8
+
9
+ &:hover {
10
+ box-shadow: 0 0 0 3px ${token.colorText};
11
+ }
12
+
13
+ &:active {
14
+ scale: 0.8;
15
+ }
16
+ `,
17
+ picker: css`
18
+ em-emoji-picker {
19
+ --rgb-accent: ${chroma(token.colorPrimary) .rgb() .join(',')};
20
+ --shadow: none;
21
+ }
22
+ `,
23
+ popover: css`
24
+ .${prefixCls}-popover-inner {
25
+ padding: 0;
26
+ }
27
+ `,
28
+ }));
package/src/const/meta.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import { MetaData } from '@/types/meta';
2
+
1
3
  export const DEFAULT_AVATAR = '🤖';
2
4
  export const DEFAULT_USER_AVATAR = '😀';
3
5
  export const DEFAULT_BACKGROUND_COLOR = 'rgba(0,0,0,0)';
6
+ export const DEFAULT_AGENT_META: MetaData = {};
@@ -0,0 +1,50 @@
1
+ import { DEFAULT_AGENT_META } from '@/const/meta';
2
+ import { LanguageModel } from '@/types/llm';
3
+ import { LobeAgentConfig } from '@/types/session';
4
+ import { GlobalBaseSettings, GlobalDefaultAgent, GlobalSettings } from '@/types/settings';
5
+
6
+ export const DEFAULT_BASE_SETTINGS: GlobalBaseSettings = {
7
+ OPENAI_API_KEY: '',
8
+ avatar: '',
9
+ compressThreshold: 24,
10
+ enableCompressThreshold: false,
11
+ enableHistoryCount: false,
12
+ enableMaxTokens: true,
13
+ endpoint: '',
14
+ fontSize: 14,
15
+ frequencyPenalty: 0,
16
+ historyCount: 24,
17
+ language: 'zh-CN',
18
+ maxTokens: 2000,
19
+ model: LanguageModel.GPT3_5,
20
+ neutralColor: '',
21
+ password: '',
22
+ presencePenalty: 0,
23
+ primaryColor: '',
24
+ temperature: 0.5,
25
+ themeMode: 'auto',
26
+ topP: 1,
27
+ };
28
+
29
+ export const DEFAULT_AGENT_CONFIG: LobeAgentConfig = {
30
+ displayMode: 'chat',
31
+ model: LanguageModel.GPT3_5,
32
+ params: {
33
+ frequency_penalty: 0,
34
+ presence_penalty: 0,
35
+ temperature: 0.6,
36
+ top_p: 1,
37
+ },
38
+ plugins: [],
39
+ systemRole: '',
40
+ };
41
+
42
+ export const DEFAULT_AGENT: GlobalDefaultAgent = {
43
+ config: DEFAULT_AGENT_CONFIG,
44
+ meta: DEFAULT_AGENT_META,
45
+ };
46
+
47
+ export const DEFAULT_SETTINGS: GlobalSettings = {
48
+ defaultAgent: DEFAULT_AGENT,
49
+ ...DEFAULT_BASE_SETTINGS,
50
+ };
@@ -1,16 +1,14 @@
1
1
  import { Form, ItemGroup } from '@lobehub/ui';
2
2
  import { ConfigProvider, Input, Segmented, Select, Switch } from 'antd';
3
3
  import { useTheme } from 'antd-style';
4
- import isEqual from 'fast-deep-equal';
5
4
  import { debounce } from 'lodash-es';
6
5
  import { BrainCog, MessagesSquare } from 'lucide-react';
7
- import { useMemo } from 'react';
6
+ import { memo, useMemo } from 'react';
8
7
  import { useTranslation } from 'react-i18next';
9
8
  import SliderWithInput from 'src/components/SliderWithInput';
10
- import { shallow } from 'zustand/shallow';
11
9
 
12
10
  import { FORM_STYLE } from '@/const/layoutTokens';
13
- import { agentSelectors, useSessionStore } from '@/store/session';
11
+ import { AgentAction } from '@/store/session/slices/agentConfig';
14
12
  import { LanguageModel } from '@/types/llm';
15
13
  import type { LobeAgentConfig } from '@/types/session';
16
14
 
@@ -20,14 +18,15 @@ type SettingItemGroup = ItemGroup & {
20
18
  }[];
21
19
  };
22
20
 
23
- const AgentConfig = () => {
21
+ export interface AgentConfigProps {
22
+ config: LobeAgentConfig;
23
+ updateConfig: AgentAction['updateAgentConfig'];
24
+ }
25
+
26
+ const AgentConfig = memo<AgentConfigProps>(({ config, updateConfig }) => {
24
27
  const { t } = useTranslation('setting');
25
28
  const theme = useTheme();
26
29
 
27
- const config = useSessionStore(agentSelectors.currentAgentConfigSafe, isEqual);
28
-
29
- const [updateAgentConfig] = useSessionStore((s) => [s.updateAgentConfig], shallow);
30
-
31
30
  const chat: SettingItemGroup = useMemo(
32
31
  () => ({
33
32
  children: [
@@ -60,6 +59,7 @@ const AgentConfig = () => {
60
59
  {
61
60
  children: <SliderWithInput max={32} min={0} />,
62
61
  desc: t('settingChat.historyCount.desc'),
62
+ divider: false,
63
63
  hidden: !config.enableHistoryCount,
64
64
  label: t('settingChat.historyCount.title'),
65
65
  name: 'historyCount',
@@ -74,6 +74,7 @@ const AgentConfig = () => {
74
74
  {
75
75
  children: <SliderWithInput max={32} min={0} />,
76
76
  desc: t('settingChat.compressThreshold.desc'),
77
+ divider: false,
77
78
  hidden: !config.enableCompressThreshold,
78
79
  label: t('settingChat.compressThreshold.title'),
79
80
  name: 'compressThreshold',
@@ -140,6 +141,7 @@ const AgentConfig = () => {
140
141
  {
141
142
  children: <SliderWithInput max={32_000} min={0} step={100} />,
142
143
  desc: t('settingModel.maxTokens.desc'),
144
+ divider: false,
143
145
  hidden: !config?.enableMaxTokens,
144
146
  label: t('settingModel.maxTokens.title'),
145
147
  name: ['params', 'max_tokens'],
@@ -165,11 +167,11 @@ const AgentConfig = () => {
165
167
  <Form
166
168
  initialValues={config}
167
169
  items={[chat, model]}
168
- onValuesChange={debounce(updateAgentConfig, 100)}
170
+ onValuesChange={debounce(updateConfig, 100)}
169
171
  {...FORM_STYLE}
170
172
  />
171
173
  </ConfigProvider>
172
174
  );
173
- };
175
+ });
174
176
 
175
177
  export default AgentConfig;
@@ -6,8 +6,8 @@ import { memo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
 
8
8
  export interface AutoGenerateInputProps extends InputProps {
9
- loading: boolean;
10
- onGenerate: () => void;
9
+ loading?: boolean;
10
+ onGenerate?: () => void;
11
11
  }
12
12
 
13
13
  const AutoGenerateInput = memo<AutoGenerateInputProps>(({ loading, onGenerate, ...props }) => {
@@ -17,18 +17,20 @@ const AutoGenerateInput = memo<AutoGenerateInputProps>(({ loading, onGenerate, .
17
17
  return (
18
18
  <Input
19
19
  suffix={
20
- <ActionIcon
21
- active
22
- icon={Wand2}
23
- loading={loading}
24
- onClick={onGenerate}
25
- size={'small'}
26
- style={{
27
- color: theme.colorInfo,
28
- marginRight: -4,
29
- }}
30
- title={t('autoGenerate')}
31
- />
20
+ onGenerate && (
21
+ <ActionIcon
22
+ active
23
+ icon={Wand2}
24
+ loading={loading}
25
+ onClick={onGenerate}
26
+ size={'small'}
27
+ style={{
28
+ color: theme.colorInfo,
29
+ marginRight: -4,
30
+ }}
31
+ title={t('autoGenerate')}
32
+ />
33
+ )
32
34
  }
33
35
  type={'block'}
34
36
  {...props}
@@ -0,0 +1,27 @@
1
+ import { Swatches, primaryColorsSwatches } from '@lobehub/ui';
2
+ import { memo } from 'react';
3
+
4
+ import { DEFAULT_BACKGROUND_COLOR } from '@/const/meta';
5
+
6
+ interface BackgroundSwatchesProps {
7
+ backgroundColor?: string;
8
+ onChange: (color: string) => void;
9
+ }
10
+
11
+ const BackgroundSwatches = memo<BackgroundSwatchesProps>(
12
+ ({ backgroundColor = DEFAULT_BACKGROUND_COLOR, onChange }) => {
13
+ const handleSelect = (v: any) => {
14
+ onChange(v || DEFAULT_BACKGROUND_COLOR);
15
+ };
16
+
17
+ return (
18
+ <Swatches
19
+ activeColor={backgroundColor}
20
+ colors={primaryColorsSwatches}
21
+ onSelect={handleSelect}
22
+ />
23
+ );
24
+ },
25
+ );
26
+
27
+ export default BackgroundSwatches;
@@ -0,0 +1,128 @@
1
+ import { Form, type FormItemProps, Icon, type ItemGroup, Tooltip } from '@lobehub/ui';
2
+ import { Button } from 'antd';
3
+ import { UserCircle, Wand2 } from 'lucide-react';
4
+ import { ReactNode, memo, useMemo } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+
7
+ import EmojiPicker from '@/components/EmojiPicker';
8
+ import { FORM_STYLE } from '@/const/layoutTokens';
9
+ import { AgentAction, SessionLoadingState } from '@/store/session/slices/agentConfig';
10
+ import { MetaData } from '@/types/meta';
11
+ import { LobeAgentConfig } from '@/types/session';
12
+
13
+ import AutoGenerateInput from './AutoGenerateInput';
14
+ import BackgroundSwatches from './BackgroundSwatches';
15
+
16
+ export interface Autocomplete {
17
+ autocompleteMeta: AgentAction['autocompleteMeta'];
18
+ autocompleteSessionAgentMeta: AgentAction['autocompleteSessionAgentMeta'];
19
+ id: string | null;
20
+ loading: SessionLoadingState;
21
+ }
22
+
23
+ export interface AgentMetaProps {
24
+ autocomplete?: Autocomplete;
25
+ config: LobeAgentConfig;
26
+ meta: MetaData;
27
+ updateMeta: AgentAction['updateAgentMeta'];
28
+ }
29
+
30
+ const AgentMeta = memo<AgentMetaProps>(({ config, meta, updateMeta, autocomplete }) => {
31
+ const { t } = useTranslation('setting');
32
+
33
+ const hasSystemRole = useMemo(() => !!config.systemRole, [config]);
34
+
35
+ let extra: ReactNode | undefined;
36
+
37
+ const basic = [
38
+ {
39
+ key: 'title',
40
+ label: t('settingAgent.name.title'),
41
+ placeholder: t('settingAgent.name.placeholder'),
42
+ },
43
+ {
44
+ key: 'description',
45
+ label: t('settingAgent.description.title'),
46
+ placeholder: t('settingAgent.description.placeholder'),
47
+ },
48
+ // { key: 'tag', label: t('agentTag'), placeholder: t('agentTagPlaceholder') },
49
+ ];
50
+
51
+ const autocompleteItems: FormItemProps[] = basic.map((item) => {
52
+ const handleGenerate = () => autocomplete?.autocompleteMeta(item.key as keyof typeof meta);
53
+ return {
54
+ children: (
55
+ <AutoGenerateInput
56
+ loading={autocomplete?.loading[item.key as keyof SessionLoadingState]}
57
+ onChange={(e) => {
58
+ updateMeta({ [item.key]: e.target.value });
59
+ }}
60
+ onGenerate={autocomplete ? handleGenerate : undefined}
61
+ placeholder={item.placeholder}
62
+ value={meta[item.key as keyof typeof meta]}
63
+ />
64
+ ),
65
+ label: item.label,
66
+ };
67
+ });
68
+
69
+ if (autocomplete) {
70
+ const { autocompleteSessionAgentMeta, loading, id } = autocomplete;
71
+
72
+ extra = (
73
+ <Tooltip title={t('autoGenerateTooltip', { ns: 'common' })}>
74
+ <Button
75
+ disabled={!hasSystemRole}
76
+ icon={<Icon icon={Wand2} />}
77
+ loading={Object.values(loading).some((i) => !!i)}
78
+ onClick={(e: any) => {
79
+ e.stopPropagation();
80
+ if (!id) return;
81
+ autocompleteSessionAgentMeta(id, true);
82
+ }}
83
+ size={'small'}
84
+ >
85
+ {t('autoGenerate', { ns: 'common' })}
86
+ </Button>
87
+ </Tooltip>
88
+ );
89
+ }
90
+
91
+ const metaData: ItemGroup = useMemo(
92
+ () => ({
93
+ children: [
94
+ {
95
+ children: (
96
+ <EmojiPicker
97
+ avatar={meta.avatar}
98
+ backgroundColor={meta.backgroundColor}
99
+ onChange={(avatar) => updateMeta({ avatar })}
100
+ />
101
+ ),
102
+ label: t('settingAgent.avatar.title'),
103
+ minWidth: undefined,
104
+ },
105
+ {
106
+ children: (
107
+ <BackgroundSwatches
108
+ backgroundColor={meta.backgroundColor}
109
+ onChange={(backgroundColor) => updateMeta({ backgroundColor })}
110
+ />
111
+ ),
112
+ divider: false,
113
+ label: t('settingAgent.backgroundColor.title'),
114
+ minWidth: undefined,
115
+ },
116
+ ...autocompleteItems,
117
+ ],
118
+ extra: extra,
119
+ icon: UserCircle,
120
+ title: t('settingAgent.title'),
121
+ }),
122
+ [autocompleteItems, extra, meta],
123
+ );
124
+
125
+ return <Form items={[metaData]} {...FORM_STYLE} />;
126
+ });
127
+
128
+ export default AgentMeta;
@@ -1,21 +1,21 @@
1
1
  import { Avatar, Form, ItemGroup } from '@lobehub/ui';
2
2
  import { Switch } from 'antd';
3
- import isEqual from 'fast-deep-equal';
4
3
  import { ToyBrick } from 'lucide-react';
5
- import { useMemo } from 'react';
4
+ import { memo, useMemo } from 'react';
6
5
  import { useTranslation } from 'react-i18next';
7
- import { shallow } from 'zustand/shallow';
8
6
 
9
7
  import { FORM_STYLE } from '@/const/layoutTokens';
10
8
  import { PluginsMap } from '@/plugins';
11
- import { agentSelectors, useSessionStore } from '@/store/session';
9
+ import { AgentAction } from '@/store/session/slices/agentConfig';
10
+ import { LobeAgentConfig } from '@/types/session';
12
11
 
13
- const PluginList = () => {
14
- const { t } = useTranslation('setting');
15
-
16
- const config = useSessionStore(agentSelectors.currentAgentConfigSafe, isEqual);
12
+ export interface AgentPluginProps {
13
+ config: LobeAgentConfig;
14
+ updateConfig: AgentAction['toggleAgentPlugin'];
15
+ }
17
16
 
18
- const toggleAgentPlugin = useSessionStore((s) => s.toggleAgentPlugin, shallow);
17
+ const AgentPlugin = memo<AgentPluginProps>(({ config, updateConfig }) => {
18
+ const { t } = useTranslation('setting');
19
19
 
20
20
  const plugin: ItemGroup = useMemo(
21
21
  () => ({
@@ -24,7 +24,7 @@ const PluginList = () => {
24
24
  children: (
25
25
  <Switch
26
26
  checked={!config.plugins ? false : config.plugins.includes(item.name)}
27
- onChange={() => toggleAgentPlugin(item.name)}
27
+ onChange={() => updateConfig(item.name)}
28
28
  />
29
29
  ),
30
30
  desc: item.schema.description,
@@ -39,6 +39,6 @@ const PluginList = () => {
39
39
  );
40
40
 
41
41
  return <Form items={[plugin]} {...FORM_STYLE} />;
42
- };
42
+ });
43
43
 
44
- export default PluginList;
44
+ export default AgentPlugin;
@@ -1,13 +1,14 @@
1
1
  import { CodeEditor, FormGroup, TokenTag } from '@lobehub/ui';
2
2
  import { createStyles } from 'antd-style';
3
+ import { encode } from 'gpt-tokenizer';
3
4
  import { Bot } from 'lucide-react';
4
- import { memo } from 'react';
5
+ import { memo, useMemo } from 'react';
5
6
  import { useTranslation } from 'react-i18next';
6
- import { shallow } from 'zustand/shallow';
7
7
 
8
8
  import { FORM_STYLE } from '@/const/layoutTokens';
9
9
  import { ModelTokens } from '@/const/modelTokens';
10
- import { agentSelectors, chatSelectors, useSessionStore } from '@/store/session';
10
+ import { AgentAction } from '@/store/session/slices/agentConfig';
11
+ import { LobeAgentConfig } from '@/types/session';
11
12
 
12
13
  export const useStyles = createStyles(({ css, token }) => ({
13
14
  input: css`
@@ -22,18 +23,16 @@ export const useStyles = createStyles(({ css, token }) => ({
22
23
  `,
23
24
  }));
24
25
 
25
- const AgentPrompt = memo(() => {
26
+ export interface AgentPromptProps {
27
+ config: LobeAgentConfig;
28
+ updateConfig: AgentAction['updateAgentConfig'];
29
+ }
30
+
31
+ const AgentPrompt = memo<AgentPromptProps>(({ config, updateConfig }) => {
26
32
  const { t } = useTranslation('setting');
27
33
 
28
- const [systemRole, model, systemTokenCount, updateAgentConfig] = useSessionStore(
29
- (s) => [
30
- agentSelectors.currentAgentSystemRole(s),
31
- agentSelectors.currentAgentModel(s),
32
- chatSelectors.systemRoleTokenCount(s),
33
- s.updateAgentConfig,
34
- ],
35
- shallow,
36
- );
34
+ const { systemRole, model } = config;
35
+ const systemTokenCount = useMemo(() => encode(systemRole || '').length, [systemRole]);
37
36
 
38
37
  return (
39
38
  <FormGroup
@@ -46,9 +45,7 @@ const AgentPrompt = memo(() => {
46
45
  >
47
46
  <CodeEditor
48
47
  language={'md'}
49
- onValueChange={(e) => {
50
- updateAgentConfig({ systemRole: e });
51
- }}
48
+ onValueChange={(e) => updateConfig({ systemRole: e })}
52
49
  placeholder={t('settingAgent.name.placeholder')}
53
50
  resize={false}
54
51
  style={{ marginTop: 16 }}
@@ -0,0 +1,4 @@
1
+ export { default as AgentConfig } from './AgentConfig';
2
+ export { default as AgentMeta } from './AgentMeta';
3
+ export { default as AgentPlugin } from './AgentPlugin';
4
+ export { default as AgentPrompt } from './AgentPrompt';
@@ -0,0 +1,40 @@
1
+ {
2
+ "exportType": "agents",
3
+ "state": {
4
+ "sessions": {
5
+ "9a2def55-ff50-4f7f-ad6c-b97dac817193": {
6
+ "chats": {},
7
+ "config": {
8
+ "model": "gpt-3.5-turbo",
9
+ "params": { "temperature": 0.6 },
10
+ "systemRole": "你是一名专业的前端。擅长书写 Typescript JSDoc 代码,代码的示例如下:\n\n```ts\ninterface Props {\n/**\n* 尺寸\n* */\nloading: boolean;\n/**\n* 头像形状\n* @default 'square'\n* @enum [\"square\",\"circle\"]\n* @enumNames [ \"方形\", \"圆形\"]\n*/\nshape?: 'square' | 'circle';\n/**\n* 返回事件\n* @ignore\n*/\nonBack: () => void;\n/**\n* 选择路由的回调函数\n* @param key - 选中的路由\n* @ignore\n*/\nonSelect?: (key: string) => any;\n/**\n* 点击事件回调函数\n* @ignore\n*/\nonClick?: () => void;\n/**\n* 引用\n* @ignore\n*/\nref: any;\n/**\n* Tooltip 提示框位置\n* @enum ['top', 'left', 'right', 'bottom', 'topLeft', 'topRight', 'bottomLeft', 'bottomRight', 'leftTop', 'leftBottom', 'rightTop', 'rightBottom']\n* @enumNames ['上', '左', '右', '下', '左上', '右上', '左下', '右下', '左上', '左下', '右上', '右下']\n* @default 'top'\n*/\nplacement?: TooltipPlacement;\n}\n```\n\n\n接下来用户会输入一串 interface 代码,需要你补全 jsdoc。其中接口的类型不可改变"
11
+ },
12
+ "createAt": 1690184262713,
13
+ "id": "9a2def55-ff50-4f7f-ad6c-b97dac817193",
14
+ "meta": { "backgroundColor": "#ec5e41", "avatar": "🥲" },
15
+ "type": "agent",
16
+ "updateAt": 1690184262713,
17
+ "topics": {}
18
+ },
19
+ "744fe028-c8a2-410c-8b0a-66cfa00d647b": {
20
+ "chats": {},
21
+ "config": {
22
+ "model": "gpt-3.5-turbo",
23
+ "params": { "temperature": 0.6 },
24
+ "systemRole": "- dafdsafa\n- da- dafdsafa\n- da- dafdsafa\n- da- dafdsafa\n- da- dafdsafa\n- da"
25
+ },
26
+ "createAt": 1690184730185,
27
+ "id": "744fe028-c8a2-410c-8b0a-66cfa00d647b",
28
+ "meta": {
29
+ "backgroundColor": "#ffef5c",
30
+ "title": "dafaa",
31
+ "description": "safsafsafsafsafsafsfasfas"
32
+ },
33
+ "type": "agent",
34
+ "updateAt": 1690184730185,
35
+ "topics": {}
36
+ }
37
+ }
38
+ },
39
+ "version": 1
40
+ }
@@ -8,17 +8,24 @@ import {
8
8
  Github,
9
9
  Heart,
10
10
  Settings,
11
+ Settings2,
11
12
  } from 'lucide-react';
12
13
  import Router from 'next/router';
13
- import { ReactNode, memo, useMemo } from 'react';
14
+ import { memo, useMemo } from 'react';
14
15
  import { useTranslation } from 'react-i18next';
15
16
 
16
17
  import { useExportConfig } from '@/hooks/useExportConfig';
17
18
  import { useImportConfig } from '@/hooks/useImportConfig';
19
+ import { SettingsStore } from '@/store/settings';
18
20
 
19
21
  import pkg from '../../../package.json';
20
22
 
21
- const BottomAction = memo<{ children: ReactNode }>(({ children }) => {
23
+ export interface BottomActionProps {
24
+ setTab: SettingsStore['switchSideBar'];
25
+ tab: SettingsStore['sidebarKey'];
26
+ }
27
+
28
+ const BottomActions = memo<BottomActionProps>(({ tab, setTab }) => {
22
29
  const { t } = useTranslation('common');
23
30
 
24
31
  const { exportSessions, exportSettings, exportAll, exportAgents } = useExportConfig();
@@ -93,7 +100,10 @@ const BottomAction = memo<{ children: ReactNode }>(({ children }) => {
93
100
  icon: <Icon icon={Settings} />,
94
101
  key: 'setting',
95
102
  label: t('setting'),
96
- onClick: () => Router.push('/setting'),
103
+ onClick: () => {
104
+ setTab('settings');
105
+ Router.push('/settings');
106
+ },
97
107
  },
98
108
  ],
99
109
  [],
@@ -103,10 +113,10 @@ const BottomAction = memo<{ children: ReactNode }>(({ children }) => {
103
113
  <>
104
114
  <ActionIcon icon={Github} onClick={() => window.open(pkg.homepage, '__blank')} />
105
115
  <Dropdown arrow={false} menu={{ items }} trigger={['click']}>
106
- {children}
116
+ <ActionIcon active={tab === 'settings'} icon={Settings2} />
107
117
  </Dropdown>
108
118
  </>
109
119
  );
110
120
  });
111
121
 
112
- export default BottomAction;
122
+ export default BottomActions;