@lobehub/chat 0.107.16 → 0.109.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.
- package/CHANGELOG.md +50 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/docs/Environment-Variable.md +2 -2
- package/docs/Environment-Variable.zh-CN.md +2 -2
- package/locales/en_US/plugin.json +19 -0
- package/locales/en_US/setting.json +26 -0
- package/locales/ja_JP/plugin.json +19 -0
- package/locales/ja_JP/setting.json +26 -0
- package/locales/ko_KR/plugin.json +19 -0
- package/locales/ko_KR/setting.json +26 -0
- package/locales/ru_RU/plugin.json +19 -0
- package/locales/ru_RU/setting.json +26 -0
- package/locales/zh_CN/plugin.json +19 -0
- package/locales/zh_CN/setting.json +26 -5
- package/locales/zh_TW/plugin.json +19 -0
- package/locales/zh_TW/setting.json +26 -0
- package/package.json +3 -3
- package/src/app/chat/features/ChatHeader/PluginTag/PluginStatus.tsx +6 -6
- package/src/app/chat/features/ChatHeader/PluginTag/index.tsx +4 -4
- package/src/app/chat/features/ChatInput/ActionBar/Tools/ToolItem.tsx +37 -0
- package/src/app/chat/features/ChatInput/ActionBar/Tools/index.tsx +116 -0
- package/src/app/chat/features/ChatInput/ActionBar/config.ts +3 -1
- package/src/app/chat/features/Conversation/ChatList/Error/Plugin/PluginSettings.tsx +4 -4
- package/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/Settings.tsx +3 -3
- package/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/index.tsx +4 -4
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/DefaultType/index.tsx +2 -2
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/StandaloneType/Iframe.tsx +4 -4
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/StandaloneType/index.tsx +2 -2
- package/src/app/chat/features/Conversation/useInitConversation.ts +2 -2
- package/src/app/settings/(desktop)/index.tsx +3 -2
- package/src/app/settings/common/Common.tsx +8 -3
- package/src/app/settings/common/index.tsx +3 -3
- package/src/app/settings/common/page.tsx +7 -1
- package/src/app/settings/page.tsx +4 -1
- package/src/config/server.ts +5 -1
- package/src/features/AgentSetting/AgentPlugin/AddPluginButton.tsx +56 -0
- package/src/features/AgentSetting/AgentPlugin/LoadingList.tsx +48 -0
- package/src/features/AgentSetting/AgentPlugin/LocalPluginItem.tsx +5 -5
- package/src/features/AgentSetting/AgentPlugin/PluginAction/index.tsx +36 -0
- package/src/features/AgentSetting/AgentPlugin/index.tsx +157 -9
- package/src/features/AgentSetting/store/action.ts +0 -1
- package/src/features/PluginDevModal/MetaForm.tsx +3 -3
- package/src/features/PluginDevModal/PluginPreview.tsx +1 -1
- package/src/features/PluginDevModal/index.tsx +4 -1
- package/src/features/PluginSettings/index.tsx +3 -3
- package/src/features/PluginSettingsModal/index.tsx +22 -17
- package/src/features/PluginStore/Loading.tsx +13 -0
- package/src/features/PluginStore/PluginItem.tsx +81 -0
- package/src/features/PluginStore/PluginSettings.tsx +40 -0
- package/src/features/{AgentSetting/AgentPlugin/MarketSettingModal.tsx → PluginStore/StoreSetting.tsx} +2 -2
- package/src/features/PluginStore/index.tsx +95 -0
- package/src/layout/GlobalLayout/StoreHydration.tsx +3 -3
- package/src/locales/default/plugin.ts +19 -0
- package/src/locales/default/setting.ts +26 -5
- package/src/services/__tests__/chat.test.ts +221 -0
- package/src/services/__tests__/message.test.ts +333 -0
- package/src/services/__tests__/plugin.test.ts +88 -0
- package/src/services/__tests__/session.test.ts +227 -0
- package/src/services/__tests__/topic.test.ts +220 -0
- package/src/services/chat.ts +4 -6
- package/src/services/plugin.ts +12 -1
- package/src/store/chat/actions/message.test.ts +0 -1
- package/src/store/session/slices/agent/action.ts +24 -8
- package/src/store/{plugin → tool}/helpers.ts +2 -13
- package/src/store/tool/index.ts +2 -0
- package/src/store/tool/initialState.ts +11 -0
- package/src/store/tool/selectors.ts +3 -0
- package/src/store/tool/slices/customPlugin/action.test.ts +164 -0
- package/src/store/{plugin → tool}/slices/customPlugin/action.ts +2 -2
- package/src/store/tool/slices/customPlugin/selectors.test.ts +59 -0
- package/src/store/tool/slices/customPlugin/selectors.ts +9 -0
- package/src/store/tool/slices/plugin/action.test.ts +141 -0
- package/src/store/tool/slices/plugin/action.ts +95 -0
- package/src/store/{plugin → tool}/slices/plugin/initialState.ts +0 -7
- package/src/store/{plugin → tool/slices/plugin}/selectors.test.ts +4 -41
- package/src/store/{plugin → tool/slices/plugin}/selectors.ts +17 -19
- package/src/store/tool/slices/store/action.test.ts +396 -0
- package/src/store/tool/slices/store/action.ts +103 -0
- package/src/store/tool/slices/store/index.ts +3 -0
- package/src/store/tool/slices/store/initialState.ts +17 -0
- package/src/store/tool/slices/store/selectors.test.ts +48 -0
- package/src/store/tool/slices/store/selectors.ts +21 -0
- package/src/store/{plugin → tool}/store.ts +8 -6
- package/vitest.config.ts +1 -0
- package/src/features/AgentSetting/AgentPlugin/MarketList.tsx +0 -232
- package/src/features/AgentSetting/AgentPlugin/PluginSettings.tsx +0 -80
- package/src/store/chat/reducers/files.test.ts +0 -38
- package/src/store/chat/reducers/files.ts +0 -37
- package/src/store/plugin/hooks/useSessionHydrated.ts +0 -21
- package/src/store/plugin/index.ts +0 -2
- package/src/store/plugin/initialState.ts +0 -9
- package/src/store/plugin/slices/plugin/action.ts +0 -173
- /package/src/store/{plugin → tool}/slices/customPlugin/index.ts +0 -0
- /package/src/store/{plugin → tool}/slices/customPlugin/initialState.ts +0 -0
- /package/src/store/{plugin → tool}/slices/customPlugin/reducers/customPluginList.ts +0 -0
- /package/src/store/{plugin → tool}/slices/plugin/index.ts +0 -0
- /package/src/store/{plugin → tool}/slices/plugin/reducers/manifest.ts +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Checkbox } from 'antd';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
|
4
|
+
|
|
5
|
+
import { useSessionStore } from '@/store/session';
|
|
6
|
+
import { agentSelectors } from '@/store/session/selectors';
|
|
7
|
+
|
|
8
|
+
const ToolItem = memo<{ identifier: string; label: string }>(({ identifier, label }) => {
|
|
9
|
+
const [checked, togglePlugin] = useSessionStore((s) => [
|
|
10
|
+
agentSelectors.currentAgentPlugins(s).includes(identifier),
|
|
11
|
+
s.togglePlugin,
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Flexbox
|
|
16
|
+
gap={40}
|
|
17
|
+
horizontal
|
|
18
|
+
justify={'space-between'}
|
|
19
|
+
onClick={(e) => {
|
|
20
|
+
e.stopPropagation();
|
|
21
|
+
togglePlugin(identifier);
|
|
22
|
+
}}
|
|
23
|
+
padding={'8px 12px'}
|
|
24
|
+
>
|
|
25
|
+
{label}
|
|
26
|
+
<Checkbox
|
|
27
|
+
checked={checked}
|
|
28
|
+
onClick={(e) => {
|
|
29
|
+
e.stopPropagation();
|
|
30
|
+
togglePlugin(identifier);
|
|
31
|
+
}}
|
|
32
|
+
/>
|
|
33
|
+
</Flexbox>
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
export default ToolItem;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { ActionIcon, Avatar, Icon } from '@lobehub/ui';
|
|
2
|
+
import { Dropdown } from 'antd';
|
|
3
|
+
import { createStyles } from 'antd-style';
|
|
4
|
+
import isEqual from 'fast-deep-equal';
|
|
5
|
+
import { ArrowRight, PocketKnife, Store, ToyBrick } from 'lucide-react';
|
|
6
|
+
import { memo, useState } from 'react';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
8
|
+
import { Flexbox } from 'react-layout-kit';
|
|
9
|
+
|
|
10
|
+
import PluginStore from '@/features/PluginStore';
|
|
11
|
+
import { useSessionStore } from '@/store/session';
|
|
12
|
+
import { agentSelectors } from '@/store/session/selectors';
|
|
13
|
+
import { useToolStore } from '@/store/tool';
|
|
14
|
+
import { pluginSelectors } from '@/store/tool/selectors';
|
|
15
|
+
|
|
16
|
+
import ToolItem from './ToolItem';
|
|
17
|
+
|
|
18
|
+
const useStyles = createStyles(({ css, prefixCls }) => ({
|
|
19
|
+
menu: css`
|
|
20
|
+
&.${prefixCls}-dropdown-menu {
|
|
21
|
+
padding-block: 8px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.${prefixCls}-dropdown-menu-item-group-list .${prefixCls}-dropdown-menu-item {
|
|
25
|
+
padding: 0;
|
|
26
|
+
border-radius: 4px;
|
|
27
|
+
}
|
|
28
|
+
`,
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
const Tools = memo(() => {
|
|
32
|
+
const { t } = useTranslation('setting');
|
|
33
|
+
const list = useToolStore(pluginSelectors.installedPlugins, isEqual);
|
|
34
|
+
const enablePluginCount = useSessionStore((s) => agentSelectors.currentAgentPlugins(s).length);
|
|
35
|
+
const [open, setOpen] = useState(false);
|
|
36
|
+
const { styles } = useStyles();
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<>
|
|
40
|
+
<Dropdown
|
|
41
|
+
arrow={false}
|
|
42
|
+
menu={{
|
|
43
|
+
className: styles.menu,
|
|
44
|
+
items: [
|
|
45
|
+
// {
|
|
46
|
+
// children: [
|
|
47
|
+
// {
|
|
48
|
+
// icon: <Icon icon={PaletteIcon} size={{ fontSize: 16 }} style={{ padding: 4 }} />,
|
|
49
|
+
// key: 'dalle3',
|
|
50
|
+
// label: <ToolItem identifier={'dalle3'} label={'DALL·E 3'} />,
|
|
51
|
+
// },
|
|
52
|
+
// ],
|
|
53
|
+
// key: 'builtins',
|
|
54
|
+
// label: t('tools.builtins.groupName'),
|
|
55
|
+
// type: 'group',
|
|
56
|
+
// },
|
|
57
|
+
{
|
|
58
|
+
children: [
|
|
59
|
+
...list.map((item) => ({
|
|
60
|
+
icon: item.meta?.avatar ? (
|
|
61
|
+
<Avatar avatar={item.meta?.avatar} size={24} />
|
|
62
|
+
) : (
|
|
63
|
+
<Icon icon={ToyBrick} size={{ fontSize: 16 }} style={{ padding: 4 }} />
|
|
64
|
+
),
|
|
65
|
+
key: item.identifier,
|
|
66
|
+
label: (
|
|
67
|
+
<ToolItem
|
|
68
|
+
identifier={item.identifier}
|
|
69
|
+
label={item.meta?.title || item.identifier}
|
|
70
|
+
/>
|
|
71
|
+
),
|
|
72
|
+
})),
|
|
73
|
+
{
|
|
74
|
+
icon: <Icon icon={Store} size={{ fontSize: 16 }} style={{ padding: 4 }} />,
|
|
75
|
+
|
|
76
|
+
key: 'plugin-store',
|
|
77
|
+
label: (
|
|
78
|
+
<Flexbox gap={40} horizontal justify={'space-between'} padding={'8px 12px'}>
|
|
79
|
+
{t('tools.plugins.store')} <Icon icon={ArrowRight} />
|
|
80
|
+
</Flexbox>
|
|
81
|
+
),
|
|
82
|
+
onClick: (e) => {
|
|
83
|
+
e.domEvent.stopPropagation();
|
|
84
|
+
setOpen(true);
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
key: 'plugins',
|
|
89
|
+
label: (
|
|
90
|
+
<Flexbox align={'center'} gap={40} horizontal justify={'space-between'}>
|
|
91
|
+
{t('tools.plugins.groupName')}
|
|
92
|
+
{enablePluginCount === 0 ? null : (
|
|
93
|
+
<div style={{ fontSize: 12, marginInlineEnd: 4 }}>
|
|
94
|
+
{t('tools.plugins.enabled', { num: enablePluginCount })}
|
|
95
|
+
</div>
|
|
96
|
+
)}
|
|
97
|
+
</Flexbox>
|
|
98
|
+
),
|
|
99
|
+
type: 'group',
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
onClick: (e) => {
|
|
103
|
+
e.domEvent.preventDefault();
|
|
104
|
+
},
|
|
105
|
+
}}
|
|
106
|
+
placement={'topLeft'}
|
|
107
|
+
trigger={['click']}
|
|
108
|
+
>
|
|
109
|
+
<ActionIcon icon={PocketKnife} placement={'bottom'} title={t('tools.title')} />
|
|
110
|
+
</Dropdown>
|
|
111
|
+
<PluginStore open={open} setOpen={setOpen} />
|
|
112
|
+
</>
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
export default Tools;
|
|
@@ -5,6 +5,7 @@ import History from './History';
|
|
|
5
5
|
import ModelSwitch from './ModelSwitch';
|
|
6
6
|
import Temperature from './Temperature';
|
|
7
7
|
import Token from './Token';
|
|
8
|
+
import Tools from './Tools';
|
|
8
9
|
|
|
9
10
|
export const actionMap = {
|
|
10
11
|
clear: Clear,
|
|
@@ -14,6 +15,7 @@ export const actionMap = {
|
|
|
14
15
|
stt: STT,
|
|
15
16
|
temperature: Temperature,
|
|
16
17
|
token: Token,
|
|
18
|
+
tools: Tools,
|
|
17
19
|
} as const;
|
|
18
20
|
|
|
19
21
|
type ActionMap = typeof actionMap;
|
|
@@ -24,7 +26,7 @@ type getActionList = (mobile?: boolean) => ActionKeys[];
|
|
|
24
26
|
|
|
25
27
|
// we can make these action lists configurable in the future
|
|
26
28
|
export const getLeftActionList: getActionList = (mobile) =>
|
|
27
|
-
['model', 'fileUpload', 'temperature', 'history', !mobile && 'stt', 'token'].filter(
|
|
29
|
+
['model', 'fileUpload', 'temperature', 'history', !mobile && 'stt', 'tools', 'token'].filter(
|
|
28
30
|
Boolean,
|
|
29
31
|
) as ActionKeys[];
|
|
30
32
|
|
|
@@ -8,8 +8,8 @@ import { Center, Flexbox } from 'react-layout-kit';
|
|
|
8
8
|
|
|
9
9
|
import PluginSettingsConfig from '@/features/PluginSettings';
|
|
10
10
|
import { useChatStore } from '@/store/chat';
|
|
11
|
-
import { pluginHelpers,
|
|
12
|
-
import { pluginSelectors } from '@/store/
|
|
11
|
+
import { pluginHelpers, useToolStore } from '@/store/tool';
|
|
12
|
+
import { pluginSelectors } from '@/store/tool/selectors';
|
|
13
13
|
|
|
14
14
|
import { ErrorActionContainer, useStyles } from '../style';
|
|
15
15
|
|
|
@@ -19,8 +19,8 @@ const PluginSettings: RenderErrorMessage['Render'] = memo(({ id, plugin }) => {
|
|
|
19
19
|
const theme = useTheme();
|
|
20
20
|
const [resend, deleteMessage] = useChatStore((s) => [s.resendMessage, s.deleteMessage]);
|
|
21
21
|
const pluginIdentifier = plugin?.identifier as string;
|
|
22
|
-
const pluginMeta =
|
|
23
|
-
const manifest =
|
|
22
|
+
const pluginMeta = useToolStore(pluginSelectors.getPluginMetaById(pluginIdentifier), isEqual);
|
|
23
|
+
const manifest = useToolStore(pluginSelectors.getPluginManifestById(pluginIdentifier), isEqual);
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
26
|
<ErrorActionContainer>
|
|
@@ -4,11 +4,11 @@ import { memo, useState } from 'react';
|
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
|
|
6
6
|
import PluginSettingsModal from '@/features/PluginSettingsModal';
|
|
7
|
-
import {
|
|
8
|
-
import { pluginSelectors } from '@/store/
|
|
7
|
+
import { useToolStore } from '@/store/tool';
|
|
8
|
+
import { pluginSelectors } from '@/store/tool/selectors';
|
|
9
9
|
|
|
10
10
|
const Settings = memo<{ id: string }>(({ id }) => {
|
|
11
|
-
const item =
|
|
11
|
+
const item = useToolStore(pluginSelectors.getPluginManifestById(id));
|
|
12
12
|
const [open, setOpen] = useState(false);
|
|
13
13
|
const { t } = useTranslation('plugin');
|
|
14
14
|
return (
|
|
@@ -14,8 +14,8 @@ import { memo, useState } from 'react';
|
|
|
14
14
|
import { useTranslation } from 'react-i18next';
|
|
15
15
|
import { Flexbox } from 'react-layout-kit';
|
|
16
16
|
|
|
17
|
-
import { pluginHelpers,
|
|
18
|
-
import { pluginSelectors } from '@/store/
|
|
17
|
+
import { pluginHelpers, useToolStore } from '@/store/tool';
|
|
18
|
+
import { pluginSelectors } from '@/store/tool/selectors';
|
|
19
19
|
|
|
20
20
|
import PluginResult from './PluginResultJSON';
|
|
21
21
|
import Settings from './Settings';
|
|
@@ -47,8 +47,8 @@ const Inspector = memo<InspectorProps>(
|
|
|
47
47
|
const { styles } = useStyles();
|
|
48
48
|
const [open, setOpen] = useState(false);
|
|
49
49
|
|
|
50
|
-
const item =
|
|
51
|
-
const showRightAction =
|
|
50
|
+
const item = useToolStore(pluginSelectors.getPluginMetaById(id), isEqual);
|
|
51
|
+
const showRightAction = useToolStore(pluginSelectors.hasPluginUI(id));
|
|
52
52
|
const pluginAvatar = pluginHelpers.getPluginAvatar(item?.meta);
|
|
53
53
|
const pluginTitle = pluginHelpers.getPluginTitle(item?.meta);
|
|
54
54
|
|
|
@@ -5,7 +5,7 @@ import { Suspense, memo, useMemo } from 'react';
|
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import { Flexbox } from 'react-layout-kit';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { useToolStore } from '@/store/tool';
|
|
9
9
|
|
|
10
10
|
import IFrameRender from './IFrameRender';
|
|
11
11
|
|
|
@@ -72,7 +72,7 @@ export interface PluginDefaultTypeProps {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
const PluginDefaultType = memo<PluginDefaultTypeProps>(({ content, name }) => {
|
|
75
|
-
const manifest =
|
|
75
|
+
const manifest = useToolStore((s) => s.pluginManifestMap[name || '']);
|
|
76
76
|
let isJSON = true;
|
|
77
77
|
try {
|
|
78
78
|
JSON.parse(content);
|
package/src/app/chat/features/Conversation/ChatList/Plugins/Render/StandaloneType/Iframe.tsx
CHANGED
|
@@ -4,8 +4,8 @@ import { memo, useRef, useState } from 'react';
|
|
|
4
4
|
|
|
5
5
|
import { useChatStore } from '@/store/chat';
|
|
6
6
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
7
|
-
import {
|
|
8
|
-
import { pluginSelectors } from '@/store/
|
|
7
|
+
import { useToolStore } from '@/store/tool';
|
|
8
|
+
import { pluginSelectors } from '@/store/tool/selectors';
|
|
9
9
|
|
|
10
10
|
import { useOnPluginReadyForInteraction } from '../utils/iframeOnReady';
|
|
11
11
|
import {
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
|
|
26
26
|
// just to simplify code a little, don't use this pattern everywhere
|
|
27
27
|
const getSettings = (identifier: string) =>
|
|
28
|
-
pluginSelectors.getPluginSettingsById(identifier)(
|
|
28
|
+
pluginSelectors.getPluginSettingsById(identifier)(useToolStore.getState());
|
|
29
29
|
const getMessage = (id: string) => chatSelectors.getMessageById(id)(useChatStore.getState());
|
|
30
30
|
|
|
31
31
|
interface IFrameRenderProps {
|
|
@@ -111,7 +111,7 @@ const IFrameRender = memo<IFrameRenderProps>(({ url, id, payload, width = 600, h
|
|
|
111
111
|
});
|
|
112
112
|
|
|
113
113
|
// when plugin update settings, we should update it to the plugin settings
|
|
114
|
-
const updatePluginSettings =
|
|
114
|
+
const updatePluginSettings = useToolStore((s) => s.updatePluginSettings);
|
|
115
115
|
useOnPluginSettingsUpdate((value) => {
|
|
116
116
|
if (!payload?.identifier) return;
|
|
117
117
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PluginRequestPayload } from '@lobehub/chat-plugin-sdk';
|
|
2
2
|
import { memo } from 'react';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { useToolStore } from '@/store/tool';
|
|
5
5
|
|
|
6
6
|
import IFrameRender from './Iframe';
|
|
7
7
|
|
|
@@ -12,7 +12,7 @@ export interface PluginStandaloneTypeProps {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const PluginDefaultType = memo<PluginStandaloneTypeProps>(({ payload, id, name = 'unknown' }) => {
|
|
15
|
-
const manifest =
|
|
15
|
+
const manifest = useToolStore((s) => s.pluginManifestMap[name]);
|
|
16
16
|
|
|
17
17
|
if (!manifest?.ui) return;
|
|
18
18
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
2
|
|
|
3
3
|
import { useChatStore } from '@/store/chat';
|
|
4
|
-
import { usePluginStore } from '@/store/plugin';
|
|
5
4
|
import { useSessionStore } from '@/store/session';
|
|
6
5
|
import { agentSelectors } from '@/store/session/selectors';
|
|
6
|
+
import { useToolStore } from '@/store/tool';
|
|
7
7
|
|
|
8
8
|
export const useInitConversation = () => {
|
|
9
9
|
const [sessionId] = useSessionStore((s) => [s.activeId]);
|
|
@@ -18,7 +18,7 @@ export const useInitConversation = () => {
|
|
|
18
18
|
useFetchMessages(sessionId, activeTopicId);
|
|
19
19
|
useFetchTopics(sessionId);
|
|
20
20
|
|
|
21
|
-
const [useFetchPluginStore, checkPluginsIsInstalled] =
|
|
21
|
+
const [useFetchPluginStore, checkPluginsIsInstalled] = useToolStore((s) => [
|
|
22
22
|
s.useFetchPluginStore,
|
|
23
23
|
s.useCheckPluginsIsInstalled,
|
|
24
24
|
]);
|
|
@@ -6,14 +6,15 @@ import { FC, memo } from 'react';
|
|
|
6
6
|
import ResponsiveIndex from '@/components/ResponsiveIndex';
|
|
7
7
|
|
|
8
8
|
import Common from '../common';
|
|
9
|
+
import { SettingsCommonProps } from '../common/Common';
|
|
9
10
|
import Layout from './layout.desktop';
|
|
10
11
|
|
|
11
12
|
const Mobile: FC = dynamic(() => import('../(mobile)'), { ssr: false }) as FC;
|
|
12
13
|
|
|
13
|
-
export default memo(() => (
|
|
14
|
+
export default memo<SettingsCommonProps>((props) => (
|
|
14
15
|
<ResponsiveIndex Mobile={Mobile}>
|
|
15
16
|
<Layout>
|
|
16
|
-
<Common />
|
|
17
|
+
<Common {...props} />
|
|
17
18
|
</Layout>
|
|
18
19
|
</ResponsiveIndex>
|
|
19
20
|
));
|
|
@@ -13,15 +13,19 @@ import { localeOptions } from '@/locales/options';
|
|
|
13
13
|
import { useChatStore } from '@/store/chat';
|
|
14
14
|
import { useFileStore } from '@/store/file';
|
|
15
15
|
import { settingsSelectors, useGlobalStore } from '@/store/global';
|
|
16
|
-
import { usePluginStore } from '@/store/plugin';
|
|
17
16
|
import { useSessionStore } from '@/store/session';
|
|
17
|
+
import { useToolStore } from '@/store/tool';
|
|
18
18
|
import { switchLang } from '@/utils/switchLang';
|
|
19
19
|
|
|
20
20
|
import { ThemeSwatchesNeutral, ThemeSwatchesPrimary } from '../features/ThemeSwatches';
|
|
21
21
|
|
|
22
22
|
type SettingItemGroup = ItemGroup;
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
export interface SettingsCommonProps {
|
|
25
|
+
showAccessCodeConfig: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const Common = memo<SettingsCommonProps>(({ showAccessCodeConfig }) => {
|
|
25
29
|
const { t } = useTranslation('setting');
|
|
26
30
|
const [form] = AntForm.useForm();
|
|
27
31
|
|
|
@@ -31,7 +35,7 @@ const Common = memo(() => {
|
|
|
31
35
|
s.clearAllMessages,
|
|
32
36
|
]);
|
|
33
37
|
const [removeAllFiles] = useFileStore((s) => [s.removeAllFiles]);
|
|
34
|
-
const resetPluginSettings =
|
|
38
|
+
const resetPluginSettings = useToolStore((s) => s.resetPluginSettings);
|
|
35
39
|
|
|
36
40
|
const settings = useGlobalStore(settingsSelectors.currentSettings, isEqual);
|
|
37
41
|
const [setThemeMode, setSettings, resetSettings] = useGlobalStore((s) => [
|
|
@@ -154,6 +158,7 @@ const Common = memo(() => {
|
|
|
154
158
|
{
|
|
155
159
|
children: <Input.Password placeholder={t('settingSystem.accessCode.placeholder')} />,
|
|
156
160
|
desc: t('settingSystem.accessCode.desc'),
|
|
161
|
+
hidden: !showAccessCodeConfig,
|
|
157
162
|
label: t('settingSystem.accessCode.title'),
|
|
158
163
|
name: 'password',
|
|
159
164
|
},
|
|
@@ -9,16 +9,16 @@ import { useSwitchSideBarOnInit } from '@/store/global/hooks/useSwitchSettingsOn
|
|
|
9
9
|
import { SettingsTabs } from '@/store/global/initialState';
|
|
10
10
|
|
|
11
11
|
import Footer from '../features/Footer';
|
|
12
|
-
import Common from './Common';
|
|
12
|
+
import Common, { SettingsCommonProps } from './Common';
|
|
13
13
|
|
|
14
|
-
export default memo(() => {
|
|
14
|
+
export default memo<SettingsCommonProps>((props) => {
|
|
15
15
|
useSwitchSideBarOnInit(SettingsTabs.Common);
|
|
16
16
|
const { t } = useTranslation('setting');
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
19
|
<>
|
|
20
20
|
<PageTitle title={t('tab.common')} />
|
|
21
|
-
<Common />
|
|
21
|
+
<Common {...props} />
|
|
22
22
|
<Footer>LobeChat v{CURRENT_VERSION}</Footer>
|
|
23
23
|
</>
|
|
24
24
|
);
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { getServerConfig } from '@/config/server';
|
|
2
|
+
|
|
1
3
|
import Index from './index';
|
|
2
4
|
|
|
3
|
-
export default () =>
|
|
5
|
+
export default () => {
|
|
6
|
+
const { SHOW_ACCESS_CODE_CONFIG } = getServerConfig();
|
|
7
|
+
|
|
8
|
+
return <Index showAccessCodeConfig={SHOW_ACCESS_CODE_CONFIG} />;
|
|
9
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getServerConfig } from '@/config/server';
|
|
1
2
|
import { isMobileDevice } from '@/utils/responsive';
|
|
2
3
|
|
|
3
4
|
import DesktopPage from './(desktop)';
|
|
@@ -8,7 +9,9 @@ const Page = () => {
|
|
|
8
9
|
|
|
9
10
|
const Page = mobile ? MobilePage : DesktopPage;
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
const { SHOW_ACCESS_CODE_CONFIG } = getServerConfig();
|
|
13
|
+
|
|
14
|
+
return <Page showAccessCodeConfig={SHOW_ACCESS_CODE_CONFIG} />;
|
|
12
15
|
};
|
|
13
16
|
|
|
14
17
|
export default Page;
|
package/src/config/server.ts
CHANGED
|
@@ -33,8 +33,12 @@ export const getServerConfig = () => {
|
|
|
33
33
|
regions = process.env.OPENAI_FUNCTION_REGIONS.split(',');
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
const ACCESS_CODE = process.env.ACCESS_CODE;
|
|
37
|
+
|
|
36
38
|
return {
|
|
37
|
-
ACCESS_CODE
|
|
39
|
+
ACCESS_CODE,
|
|
40
|
+
|
|
41
|
+
SHOW_ACCESS_CODE_CONFIG: !!ACCESS_CODE,
|
|
38
42
|
|
|
39
43
|
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
|
|
40
44
|
OPENAI_PROXY_URL: process.env.OPENAI_PROXY_URL,
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Icon } from '@lobehub/ui';
|
|
2
|
+
import { Button } from 'antd';
|
|
3
|
+
import { LucideBlocks } from 'lucide-react';
|
|
4
|
+
import { forwardRef, useState } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
|
|
7
|
+
import { useStore } from '@/features/AgentSetting/store';
|
|
8
|
+
import DevModal from '@/features/PluginDevModal';
|
|
9
|
+
import { useToolStore } from '@/store/tool';
|
|
10
|
+
|
|
11
|
+
const AddPluginButton = forwardRef<HTMLButtonElement>((props, ref) => {
|
|
12
|
+
const { t } = useTranslation('setting');
|
|
13
|
+
const [showModal, setModal] = useState(false);
|
|
14
|
+
const [toggleAgentPlugin] = useStore((s) => [s.toggleAgentPlugin]);
|
|
15
|
+
const [installPlugin, saveToDevList, updateNewDevPlugin] = useToolStore((s) => [
|
|
16
|
+
s.installPlugin,
|
|
17
|
+
s.saveToCustomPluginList,
|
|
18
|
+
s.updateNewCustomPlugin,
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
const togglePlugin = async (pluginId: string, fetchManifest?: boolean) => {
|
|
22
|
+
toggleAgentPlugin(pluginId);
|
|
23
|
+
if (fetchManifest) {
|
|
24
|
+
await installPlugin(pluginId);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<>
|
|
30
|
+
<DevModal
|
|
31
|
+
onOpenChange={setModal}
|
|
32
|
+
onSave={async (devPlugin) => {
|
|
33
|
+
// 先保存
|
|
34
|
+
saveToDevList(devPlugin);
|
|
35
|
+
// 再开启插件
|
|
36
|
+
await togglePlugin(devPlugin.identifier, true);
|
|
37
|
+
}}
|
|
38
|
+
onValueChange={updateNewDevPlugin}
|
|
39
|
+
open={showModal}
|
|
40
|
+
/>
|
|
41
|
+
<Button
|
|
42
|
+
icon={<Icon icon={LucideBlocks} />}
|
|
43
|
+
onClick={(e) => {
|
|
44
|
+
e.stopPropagation();
|
|
45
|
+
setModal(true);
|
|
46
|
+
}}
|
|
47
|
+
ref={ref}
|
|
48
|
+
size={'small'}
|
|
49
|
+
>
|
|
50
|
+
{t('plugin.addTooltip')}
|
|
51
|
+
</Button>
|
|
52
|
+
</>
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export default AddPluginButton;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Skeleton } from 'antd';
|
|
2
|
+
import { createStyles } from 'antd-style';
|
|
3
|
+
|
|
4
|
+
const useStyles = createStyles(({ css, prefixCls }) => ({
|
|
5
|
+
avatar: css`
|
|
6
|
+
.${prefixCls}-skeleton-header {
|
|
7
|
+
padding-right: 0;
|
|
8
|
+
}
|
|
9
|
+
`,
|
|
10
|
+
label: css`
|
|
11
|
+
li {
|
|
12
|
+
height: 14px !important;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
li + li {
|
|
16
|
+
margin-block-start: 12px !important;
|
|
17
|
+
}
|
|
18
|
+
`,
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
const LoadingList = () => {
|
|
22
|
+
const { styles } = useStyles();
|
|
23
|
+
|
|
24
|
+
const loadingItem = {
|
|
25
|
+
avatar: (
|
|
26
|
+
<Skeleton
|
|
27
|
+
active
|
|
28
|
+
avatar={{ size: 40 }}
|
|
29
|
+
className={styles.avatar}
|
|
30
|
+
paragraph={false}
|
|
31
|
+
title={false}
|
|
32
|
+
/>
|
|
33
|
+
),
|
|
34
|
+
label: (
|
|
35
|
+
<Skeleton
|
|
36
|
+
active
|
|
37
|
+
avatar={false}
|
|
38
|
+
paragraph={{ className: styles.label, style: { marginBottom: 0 } }}
|
|
39
|
+
style={{ width: 300 }}
|
|
40
|
+
title={false}
|
|
41
|
+
/>
|
|
42
|
+
),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return [loadingItem, loadingItem, loadingItem];
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default LoadingList;
|
|
@@ -5,8 +5,8 @@ import { useTranslation } from 'react-i18next';
|
|
|
5
5
|
import { Flexbox } from 'react-layout-kit';
|
|
6
6
|
|
|
7
7
|
import DevModal from '@/features/PluginDevModal';
|
|
8
|
-
import {
|
|
9
|
-
import { pluginSelectors } from '@/store/
|
|
8
|
+
import { useToolStore } from '@/store/tool';
|
|
9
|
+
import { pluginSelectors } from '@/store/tool/selectors';
|
|
10
10
|
|
|
11
11
|
import { useStore } from '../store';
|
|
12
12
|
|
|
@@ -19,15 +19,15 @@ const MarketList = memo<{ id: string }>(({ id }) => {
|
|
|
19
19
|
const plugins = useStore((s) => s.config.plugins || []);
|
|
20
20
|
|
|
21
21
|
const [useFetchPluginList, fetchPluginManifest, deleteCustomPlugin, updateCustomPlugin] =
|
|
22
|
-
|
|
22
|
+
useToolStore((s) => [
|
|
23
23
|
s.useFetchPluginStore,
|
|
24
24
|
s.installPlugin,
|
|
25
25
|
s.deleteCustomPlugin,
|
|
26
26
|
s.updateCustomPlugin,
|
|
27
27
|
]);
|
|
28
28
|
|
|
29
|
-
const pluginManifestLoading =
|
|
30
|
-
const devPlugin =
|
|
29
|
+
const pluginManifestLoading = useToolStore((s) => s.pluginInstallLoading, isEqual);
|
|
30
|
+
const devPlugin = useToolStore(pluginSelectors.getDevPluginById(id), isEqual);
|
|
31
31
|
|
|
32
32
|
useFetchPluginList();
|
|
33
33
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Switch } from 'antd';
|
|
2
|
+
import isEqual from 'fast-deep-equal';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
|
+
|
|
6
|
+
import { useToolStore } from '@/store/tool';
|
|
7
|
+
|
|
8
|
+
import { useStore } from '../../store';
|
|
9
|
+
|
|
10
|
+
const PluginSwitch = memo<{ identifier: string }>(({ identifier }) => {
|
|
11
|
+
const pluginManifestLoading = useToolStore((s) => s.pluginInstallLoading, isEqual);
|
|
12
|
+
const [userEnabledPlugins, hasPlugin, toggleAgentPlugin] = useStore((s) => [
|
|
13
|
+
s.config.plugins || [],
|
|
14
|
+
!!s.config.plugins,
|
|
15
|
+
s.toggleAgentPlugin,
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
|
20
|
+
<Switch
|
|
21
|
+
checked={
|
|
22
|
+
// 如果在加载中,说明激活了
|
|
23
|
+
pluginManifestLoading[identifier] || !hasPlugin
|
|
24
|
+
? false
|
|
25
|
+
: userEnabledPlugins.includes(identifier)
|
|
26
|
+
}
|
|
27
|
+
loading={pluginManifestLoading[identifier]}
|
|
28
|
+
onChange={() => {
|
|
29
|
+
toggleAgentPlugin(identifier);
|
|
30
|
+
}}
|
|
31
|
+
/>
|
|
32
|
+
</Flexbox>
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export default PluginSwitch;
|