@lobehub/chat 0.149.4 → 0.149.5
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/.github/FUNDING.yml +1 -1
- package/CHANGELOG.md +33 -0
- package/package.json +1 -1
- package/src/app/chat/(desktop)/features/ChatHeader/Main.tsx +5 -5
- package/src/app/chat/(desktop)/features/ChatHeader/Tags.tsx +3 -3
- package/src/app/chat/(desktop)/features/ChatInput/Footer/DragUpload.tsx +9 -9
- package/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx +3 -3
- package/src/app/chat/(desktop)/features/SideBar/SystemRole/index.tsx +8 -3
- package/src/app/chat/(mobile)/mobile/ChatHeader/ChatHeaderTitle.tsx +2 -2
- package/src/app/chat/(mobile)/mobile/page.tsx +0 -6
- package/src/app/chat/_layout/Desktop/SessionList.tsx +2 -0
- package/src/app/chat/features/PageTitle/index.tsx +3 -3
- package/src/app/chat/features/PluginTag/PluginStatus.tsx +2 -2
- package/src/app/chat/features/SessionListContent/DefaultMode.tsx +4 -2
- package/src/app/chat/features/SessionListContent/List/Item/index.tsx +10 -17
- package/src/app/chat/features/SessionListContent/index.tsx +2 -0
- package/src/app/chat/features/ShareButton/Preview.tsx +15 -11
- package/src/app/chat/features/ShareButton/useScreenshot.ts +2 -2
- package/src/app/chat/settings/features/EditPage.tsx +10 -7
- package/src/app/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx +5 -3
- package/src/app/metadata.ts +3 -3
- package/src/app/settings/(mobile)/features/AvatarBanner.tsx +1 -0
- package/src/config/modelProviders/ollama.ts +11 -12
- package/src/const/session.ts +1 -0
- package/src/database/client/models/session.ts +1 -0
- package/src/database/client/models/user.ts +6 -0
- package/src/features/ChatInput/ActionBar/FileUpload.tsx +11 -5
- package/src/features/ChatInput/ActionBar/History.tsx +3 -3
- package/src/features/ChatInput/ActionBar/ModelSwitch.tsx +2 -0
- package/src/features/ChatInput/ActionBar/Temperature.tsx +3 -3
- package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +4 -4
- package/src/features/ChatInput/ActionBar/Token/index.tsx +3 -3
- package/src/features/ChatInput/ActionBar/Tools/ToolItem.tsx +3 -3
- package/src/features/ChatInput/ActionBar/Tools/index.tsx +4 -4
- package/src/features/ChatInput/STT/browser.tsx +3 -3
- package/src/features/ChatInput/STT/openai.tsx +3 -3
- package/src/features/ChatInput/useChatInput.ts +3 -3
- package/src/features/Conversation/Extras/Assistant.test.tsx +7 -7
- package/src/features/Conversation/Extras/Assistant.tsx +3 -3
- package/src/features/Conversation/Extras/TTS/index.tsx +3 -3
- package/src/features/Conversation/components/ChatItem/ActionsBar.tsx +2 -2
- package/src/features/Conversation/components/ChatItem/index.tsx +6 -4
- package/src/features/Conversation/hooks/useInitConversation.ts +10 -7
- package/src/features/Conversation/index.tsx +6 -3
- package/src/features/ModelSwitchPanel/index.tsx +6 -4
- package/src/hooks/useTTS.ts +4 -4
- package/src/services/chat.ts +3 -3
- package/src/services/session/client.ts +19 -0
- package/src/services/session/type.ts +2 -0
- package/src/store/agent/index.ts +2 -0
- package/src/store/agent/initialState.ts +7 -0
- package/src/store/agent/selectors.ts +1 -0
- package/src/store/{session/slices/agent → agent/slices/chat}/action.test.ts +26 -63
- package/src/store/agent/slices/chat/action.ts +107 -0
- package/src/store/agent/slices/chat/initialState.ts +14 -0
- package/src/store/agent/slices/chat/selectors.test.ts +82 -0
- package/src/store/agent/slices/chat/selectors.ts +81 -0
- package/src/store/agent/store.ts +27 -0
- package/src/store/chat/slices/message/action.test.ts +3 -2
- package/src/store/chat/slices/message/action.ts +3 -3
- package/src/store/chat/slices/message/selectors.test.ts +9 -2
- package/src/store/chat/slices/message/selectors.ts +6 -4
- package/src/store/chat/slices/share/action.ts +5 -3
- package/src/store/global/slices/preference/selectors.ts +3 -1
- package/src/store/session/selectors.ts +1 -2
- package/src/store/session/slices/session/action.test.ts +43 -0
- package/src/store/session/slices/session/action.ts +28 -18
- package/src/store/session/slices/session/helpers.ts +2 -3
- package/src/store/session/slices/session/initialState.ts +1 -17
- package/src/store/session/slices/session/selectors/index.ts +1 -0
- package/src/store/session/slices/session/selectors/list.test.ts +5 -3
- package/src/store/session/slices/session/selectors/list.ts +2 -3
- package/src/store/session/slices/session/selectors/meta.test.ts +108 -0
- package/src/store/session/slices/session/selectors/meta.ts +45 -0
- package/src/store/session/store.ts +1 -7
- package/src/types/session.ts +1 -0
- package/src/store/session/slices/agent/action.ts +0 -84
- package/src/store/session/slices/agent/selectors.test.ts +0 -180
- package/src/store/session/slices/agent/selectors.ts +0 -129
- /package/src/store/{session/slices/agent → agent/slices/chat}/index.ts +0 -0
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { ActionIcon, Icon } from '@lobehub/ui';
|
|
2
2
|
import { Upload } from 'antd';
|
|
3
3
|
import { useTheme } from 'antd-style';
|
|
4
|
-
import {
|
|
4
|
+
import { FileUp, LucideImage, LucideLoader2 } from 'lucide-react';
|
|
5
5
|
import { memo, useState } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import { Center } from 'react-layout-kit';
|
|
8
8
|
|
|
9
|
+
import { useAgentStore } from '@/store/agent';
|
|
10
|
+
import { agentSelectors } from '@/store/agent/slices/chat';
|
|
9
11
|
import { useFileStore } from '@/store/file';
|
|
10
12
|
import { useGlobalStore } from '@/store/global';
|
|
11
13
|
import { modelProviderSelectors } from '@/store/global/selectors';
|
|
12
|
-
import { useSessionStore } from '@/store/session';
|
|
13
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
14
14
|
|
|
15
15
|
const FileUpload = memo(() => {
|
|
16
16
|
const { t } = useTranslation('chat');
|
|
@@ -18,7 +18,7 @@ const FileUpload = memo(() => {
|
|
|
18
18
|
const theme = useTheme();
|
|
19
19
|
const upload = useFileStore((s) => s.uploadFile);
|
|
20
20
|
|
|
21
|
-
const model =
|
|
21
|
+
const model = useAgentStore(agentSelectors.currentAgentModel);
|
|
22
22
|
const [canUpload, enabledFiles] = useGlobalStore((s) => [
|
|
23
23
|
modelProviderSelectors.isModelEnabledUpload(model)(s),
|
|
24
24
|
modelProviderSelectors.isModelEnabledFiles(model)(s),
|
|
@@ -53,7 +53,13 @@ const FileUpload = memo(() => {
|
|
|
53
53
|
disable={!canUpload}
|
|
54
54
|
icon={enabledFiles ? FileUp : LucideImage}
|
|
55
55
|
placement={'bottom'}
|
|
56
|
-
title={t(
|
|
56
|
+
title={t(
|
|
57
|
+
canUpload
|
|
58
|
+
? enabledFiles
|
|
59
|
+
? 'upload.actionFiletip'
|
|
60
|
+
: 'upload.actionTooltip'
|
|
61
|
+
: 'upload.disabled',
|
|
62
|
+
)}
|
|
57
63
|
/>
|
|
58
64
|
)}
|
|
59
65
|
</Upload>
|
|
@@ -5,13 +5,13 @@ import { memo } from 'react';
|
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import { Flexbox } from 'react-layout-kit';
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import { agentSelectors } from '@/store/
|
|
8
|
+
import { useAgentStore } from '@/store/agent';
|
|
9
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
|
10
10
|
|
|
11
11
|
const History = memo(() => {
|
|
12
12
|
const { t } = useTranslation('setting');
|
|
13
13
|
|
|
14
|
-
const [historyCount, unlimited, updateAgentConfig] =
|
|
14
|
+
const [historyCount, unlimited, updateAgentConfig] = useAgentStore((s) => {
|
|
15
15
|
const config = agentSelectors.currentAgentConfig(s);
|
|
16
16
|
return [config.historyCount, !config.enableHistoryCount, s.updateAgentConfig];
|
|
17
17
|
});
|
|
@@ -4,13 +4,13 @@ import { Thermometer } from 'lucide-react';
|
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import { agentSelectors } from '@/store/
|
|
7
|
+
import { useAgentStore } from '@/store/agent';
|
|
8
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
|
9
9
|
|
|
10
10
|
const Temperature = memo(() => {
|
|
11
11
|
const { t } = useTranslation('setting');
|
|
12
12
|
|
|
13
|
-
const [temperature, updateAgentConfig] =
|
|
13
|
+
const [temperature, updateAgentConfig] = useAgentStore((s) => {
|
|
14
14
|
const config = agentSelectors.currentAgentConfig(s);
|
|
15
15
|
return [config.params.temperature, s.updateAgentConfig];
|
|
16
16
|
});
|
|
@@ -5,12 +5,12 @@ import { useTranslation } from 'react-i18next';
|
|
|
5
5
|
import { Flexbox } from 'react-layout-kit';
|
|
6
6
|
|
|
7
7
|
import { useTokenCount } from '@/hooks/useTokenCount';
|
|
8
|
+
import { useAgentStore } from '@/store/agent';
|
|
9
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
|
8
10
|
import { useChatStore } from '@/store/chat';
|
|
9
11
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
10
12
|
import { useGlobalStore } from '@/store/global';
|
|
11
13
|
import { modelProviderSelectors } from '@/store/global/selectors';
|
|
12
|
-
import { useSessionStore } from '@/store/session';
|
|
13
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
14
14
|
import { useToolStore } from '@/store/tool';
|
|
15
15
|
import { toolSelectors } from '@/store/tool/selectors';
|
|
16
16
|
|
|
@@ -24,7 +24,7 @@ const Token = memo(() => {
|
|
|
24
24
|
chatSelectors.chatsMessageString(s),
|
|
25
25
|
]);
|
|
26
26
|
|
|
27
|
-
const [systemRole, model] =
|
|
27
|
+
const [systemRole, model] = useAgentStore((s) => [
|
|
28
28
|
agentSelectors.currentAgentSystemRole(s),
|
|
29
29
|
agentSelectors.currentAgentModel(s) as string,
|
|
30
30
|
]);
|
|
@@ -33,7 +33,7 @@ const Token = memo(() => {
|
|
|
33
33
|
|
|
34
34
|
// Tool usage token
|
|
35
35
|
const canUseTool = useGlobalStore(modelProviderSelectors.isModelEnabledFunctionCall(model));
|
|
36
|
-
const plugins =
|
|
36
|
+
const plugins = useAgentStore(agentSelectors.currentAgentPlugins);
|
|
37
37
|
const toolsString = useToolStore((s) => {
|
|
38
38
|
const pluginSystemRoles = toolSelectors.enabledSystemRoles(plugins)(s);
|
|
39
39
|
const schemaNumber = toolSelectors
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import dynamic from 'next/dynamic';
|
|
2
2
|
import { memo } from 'react';
|
|
3
3
|
|
|
4
|
+
import { useAgentStore } from '@/store/agent';
|
|
5
|
+
import { agentSelectors } from '@/store/agent/slices/chat';
|
|
4
6
|
import { useGlobalStore } from '@/store/global';
|
|
5
7
|
import { modelProviderSelectors } from '@/store/global/selectors';
|
|
6
|
-
import { useSessionStore } from '@/store/session';
|
|
7
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
8
8
|
|
|
9
9
|
const LargeTokenContent = dynamic(() => import('./TokenTag'), { ssr: false });
|
|
10
10
|
|
|
11
11
|
const Token = memo(() => {
|
|
12
|
-
const model =
|
|
12
|
+
const model = useAgentStore(agentSelectors.currentAgentModel);
|
|
13
13
|
const showTag = useGlobalStore(modelProviderSelectors.isModelHasMaxToken(model));
|
|
14
14
|
|
|
15
15
|
return showTag && <LargeTokenContent />;
|
|
@@ -3,13 +3,13 @@ import { memo } from 'react';
|
|
|
3
3
|
import { Flexbox } from 'react-layout-kit';
|
|
4
4
|
|
|
5
5
|
import PluginTag from '@/features/PluginStore/PluginItem/PluginTag';
|
|
6
|
-
import {
|
|
7
|
-
import { agentSelectors } from '@/store/
|
|
6
|
+
import { useAgentStore } from '@/store/agent';
|
|
7
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
|
8
8
|
import { useToolStore } from '@/store/tool';
|
|
9
9
|
import { customPluginSelectors } from '@/store/tool/selectors';
|
|
10
10
|
|
|
11
11
|
const ToolItem = memo<{ identifier: string; label: string }>(({ identifier, label }) => {
|
|
12
|
-
const [checked, togglePlugin] =
|
|
12
|
+
const [checked, togglePlugin] = useAgentStore((s) => [
|
|
13
13
|
agentSelectors.currentAgentPlugins(s).includes(identifier),
|
|
14
14
|
s.togglePlugin,
|
|
15
15
|
]);
|
|
@@ -8,10 +8,10 @@ import { useTranslation } from 'react-i18next';
|
|
|
8
8
|
import { Flexbox } from 'react-layout-kit';
|
|
9
9
|
|
|
10
10
|
import PluginStore from '@/features/PluginStore';
|
|
11
|
+
import { useAgentStore } from '@/store/agent';
|
|
12
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
|
11
13
|
import { useGlobalStore } from '@/store/global';
|
|
12
14
|
import { modelProviderSelectors } from '@/store/global/selectors';
|
|
13
|
-
import { useSessionStore } from '@/store/session';
|
|
14
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
15
15
|
import { pluginHelpers, useToolStore } from '@/store/tool';
|
|
16
16
|
import { builtinToolSelectors, pluginSelectors } from '@/store/tool/selectors';
|
|
17
17
|
|
|
@@ -35,7 +35,7 @@ const Tools = memo(() => {
|
|
|
35
35
|
const list = useToolStore(pluginSelectors.installedPluginMetaList, isEqual);
|
|
36
36
|
const builtinList = useToolStore(builtinToolSelectors.metaList, isEqual);
|
|
37
37
|
|
|
38
|
-
const enablePluginCount =
|
|
38
|
+
const enablePluginCount = useAgentStore(
|
|
39
39
|
(s) =>
|
|
40
40
|
agentSelectors
|
|
41
41
|
.currentAgentPlugins(s)
|
|
@@ -45,7 +45,7 @@ const Tools = memo(() => {
|
|
|
45
45
|
const [open, setOpen] = useState(false);
|
|
46
46
|
const { styles } = useStyles();
|
|
47
47
|
|
|
48
|
-
const model =
|
|
48
|
+
const model = useAgentStore(agentSelectors.currentAgentModel);
|
|
49
49
|
const enableFC = useGlobalStore(modelProviderSelectors.isModelEnabledFunctionCall(model));
|
|
50
50
|
|
|
51
51
|
return (
|
|
@@ -4,11 +4,11 @@ import { memo, useCallback, useState } from 'react';
|
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import { SWRConfiguration } from 'swr';
|
|
6
6
|
|
|
7
|
+
import { useAgentStore } from '@/store/agent';
|
|
8
|
+
import { agentSelectors } from '@/store/agent/slices/chat';
|
|
7
9
|
import { useChatStore } from '@/store/chat';
|
|
8
10
|
import { useGlobalStore } from '@/store/global';
|
|
9
11
|
import { settingsSelectors } from '@/store/global/selectors';
|
|
10
|
-
import { useSessionStore } from '@/store/session';
|
|
11
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
12
12
|
import { ChatMessageError } from '@/types/message';
|
|
13
13
|
import { getMessageError } from '@/utils/fetch';
|
|
14
14
|
|
|
@@ -20,7 +20,7 @@ interface STTConfig extends SWRConfiguration {
|
|
|
20
20
|
|
|
21
21
|
const useBrowserSTT = (config: STTConfig) => {
|
|
22
22
|
const ttsSettings = useGlobalStore(settingsSelectors.currentTTS, isEqual);
|
|
23
|
-
const ttsAgentSettings =
|
|
23
|
+
const ttsAgentSettings = useAgentStore(agentSelectors.currentAgentTTS, isEqual);
|
|
24
24
|
const locale = useGlobalStore(settingsSelectors.currentLanguage);
|
|
25
25
|
|
|
26
26
|
const autoStop = ttsSettings.sttAutoStop;
|
|
@@ -7,11 +7,11 @@ import { SWRConfiguration } from 'swr';
|
|
|
7
7
|
|
|
8
8
|
import { createHeaderWithOpenAI } from '@/services/_header';
|
|
9
9
|
import { API_ENDPOINTS } from '@/services/_url';
|
|
10
|
+
import { useAgentStore } from '@/store/agent';
|
|
11
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
|
10
12
|
import { useChatStore } from '@/store/chat';
|
|
11
13
|
import { useGlobalStore } from '@/store/global';
|
|
12
14
|
import { settingsSelectors } from '@/store/global/selectors';
|
|
13
|
-
import { useSessionStore } from '@/store/session';
|
|
14
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
15
15
|
import { ChatMessageError } from '@/types/message';
|
|
16
16
|
import { getMessageError } from '@/utils/fetch';
|
|
17
17
|
|
|
@@ -23,7 +23,7 @@ interface STTConfig extends SWRConfiguration {
|
|
|
23
23
|
|
|
24
24
|
const useOpenaiSTT = (config: STTConfig) => {
|
|
25
25
|
const ttsSettings = useGlobalStore(settingsSelectors.currentTTS, isEqual);
|
|
26
|
-
const ttsAgentSettings =
|
|
26
|
+
const ttsAgentSettings = useAgentStore(agentSelectors.currentAgentTTS, isEqual);
|
|
27
27
|
const locale = useGlobalStore(settingsSelectors.currentLanguage);
|
|
28
28
|
|
|
29
29
|
const autoStop = ttsSettings.sttAutoStop;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { TextAreaRef } from 'antd/es/input/TextArea';
|
|
2
2
|
import { useCallback, useRef, useState } from 'react';
|
|
3
3
|
|
|
4
|
+
import { useAgentStore } from '@/store/agent';
|
|
5
|
+
import { agentSelectors } from '@/store/agent/slices/chat';
|
|
4
6
|
import { useChatStore } from '@/store/chat';
|
|
5
7
|
import { useGlobalStore } from '@/store/global';
|
|
6
8
|
import { modelProviderSelectors } from '@/store/global/selectors';
|
|
7
|
-
import { useSessionStore } from '@/store/session';
|
|
8
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
9
9
|
|
|
10
10
|
import { useSendMessage } from './useSend';
|
|
11
11
|
|
|
@@ -14,7 +14,7 @@ export const useChatInput = () => {
|
|
|
14
14
|
const [expand, setExpand] = useState<boolean>(false);
|
|
15
15
|
const onSend = useSendMessage();
|
|
16
16
|
|
|
17
|
-
const model =
|
|
17
|
+
const model = useAgentStore(agentSelectors.currentAgentModel);
|
|
18
18
|
const canUpload = useGlobalStore(modelProviderSelectors.isModelEnabledUpload(model));
|
|
19
19
|
|
|
20
20
|
const [loading, value, onInput, onStop] = useChatStore((s) => [
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { render, screen } from '@testing-library/react';
|
|
2
2
|
import { Mock, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import { agentSelectors } from '@/store/
|
|
4
|
+
import { useAgentStore } from '@/store/agent';
|
|
5
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
|
6
6
|
import { ChatMessage } from '@/types/message';
|
|
7
7
|
|
|
8
8
|
import { AssistantMessageExtra } from './Assistant';
|
|
@@ -16,10 +16,10 @@ vi.mock('./Translate', () => ({
|
|
|
16
16
|
}));
|
|
17
17
|
|
|
18
18
|
// Mock dependencies
|
|
19
|
-
vi.mock('@/store/
|
|
20
|
-
|
|
19
|
+
vi.mock('@/store/agent', () => ({
|
|
20
|
+
useAgentStore: vi.fn(),
|
|
21
21
|
}));
|
|
22
|
-
vi.mock('@/store/
|
|
22
|
+
vi.mock('@/store/agent/selectors', () => ({
|
|
23
23
|
agentSelectors: {
|
|
24
24
|
currentAgentModel: vi.fn(),
|
|
25
25
|
},
|
|
@@ -37,7 +37,7 @@ const mockData: ChatMessage = {
|
|
|
37
37
|
describe('AssistantMessageExtra', () => {
|
|
38
38
|
beforeEach(() => {
|
|
39
39
|
// Set default mock return values
|
|
40
|
-
(
|
|
40
|
+
(useAgentStore as unknown as Mock).mockImplementation(() => ({
|
|
41
41
|
chatLoadingId: null,
|
|
42
42
|
}));
|
|
43
43
|
(agentSelectors.currentAgentModel as Mock).mockReturnValue('defaultModel');
|
|
@@ -76,7 +76,7 @@ describe('AssistantMessageExtra', () => {
|
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
it('should receive the correct loading attribute if loading is true for TTS and Translate components', async () => {
|
|
79
|
-
(
|
|
79
|
+
(useAgentStore as unknown as Mock).mockImplementation(() => ({
|
|
80
80
|
chatLoadingId: 'test-id',
|
|
81
81
|
}));
|
|
82
82
|
render(<AssistantMessageExtra {...mockData} extra={{ translate: { to: 'abc' }, tts: {} }} />);
|
|
@@ -2,9 +2,9 @@ import { memo } from 'react';
|
|
|
2
2
|
import { Flexbox } from 'react-layout-kit';
|
|
3
3
|
|
|
4
4
|
import ModelTag from '@/components/ModelTag';
|
|
5
|
+
import { useAgentStore } from '@/store/agent';
|
|
6
|
+
import { agentSelectors } from '@/store/agent/slices/chat';
|
|
5
7
|
import { useChatStore } from '@/store/chat';
|
|
6
|
-
import { useSessionStore } from '@/store/session';
|
|
7
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
8
8
|
import { ChatMessage } from '@/types/message';
|
|
9
9
|
|
|
10
10
|
import { RenderMessageExtra } from '../types';
|
|
@@ -14,7 +14,7 @@ import Translate from './Translate';
|
|
|
14
14
|
|
|
15
15
|
export const AssistantMessageExtra: RenderMessageExtra = memo<ChatMessage>(
|
|
16
16
|
({ extra, id, content }) => {
|
|
17
|
-
const model =
|
|
17
|
+
const model = useAgentStore(agentSelectors.currentAgentModel);
|
|
18
18
|
const loading = useChatStore((s) => s.chatLoadingId === id);
|
|
19
19
|
|
|
20
20
|
const showModelTag = extra?.fromModel && model !== extra?.fromModel;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { memo, useMemo } from 'react';
|
|
2
2
|
import { Md5 } from 'ts-md5';
|
|
3
3
|
|
|
4
|
+
import { useAgentStore } from '@/store/agent';
|
|
5
|
+
import { agentSelectors } from '@/store/agent/slices/chat';
|
|
4
6
|
import { useGlobalStore } from '@/store/global';
|
|
5
7
|
import { settingsSelectors } from '@/store/global/selectors';
|
|
6
|
-
import { useSessionStore } from '@/store/session';
|
|
7
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
8
8
|
|
|
9
9
|
import FilePlayer from './FilePlayer';
|
|
10
10
|
import InitPlayer, { TTSProps } from './InitPlayer';
|
|
@@ -13,7 +13,7 @@ const TTS = memo<TTSProps>(
|
|
|
13
13
|
(props) => {
|
|
14
14
|
const { file, voice, content, contentMd5 } = props;
|
|
15
15
|
const lang = useGlobalStore(settingsSelectors.currentLanguage);
|
|
16
|
-
const currentVoice =
|
|
16
|
+
const currentVoice = useAgentStore(agentSelectors.currentAgentTTSVoice(lang));
|
|
17
17
|
|
|
18
18
|
const md5 = useMemo(() => Md5.hashStr(content).toString(), [content]);
|
|
19
19
|
|
|
@@ -5,7 +5,7 @@ import { memo, useCallback } from 'react';
|
|
|
5
5
|
import { useChatStore } from '@/store/chat';
|
|
6
6
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
7
7
|
import { useSessionStore } from '@/store/session';
|
|
8
|
-
import {
|
|
8
|
+
import { sessionMetaSelectors } from '@/store/session/selectors';
|
|
9
9
|
|
|
10
10
|
import { renderActions, useActionsClick } from '../../Actions';
|
|
11
11
|
import { useChatListActionsBar } from '../../hooks/useChatListActionsBar';
|
|
@@ -29,7 +29,7 @@ interface ActionsProps {
|
|
|
29
29
|
setEditing: (edit: boolean) => void;
|
|
30
30
|
}
|
|
31
31
|
const Actions = memo<ActionsProps>(({ index, setEditing }) => {
|
|
32
|
-
const meta = useSessionStore(
|
|
32
|
+
const meta = useSessionStore(sessionMetaSelectors.currentAgentMeta, isEqual);
|
|
33
33
|
|
|
34
34
|
const item = useChatStore(
|
|
35
35
|
(s) => chatSelectors.currentChatsWithGuideMessage(meta)(s)[index],
|
|
@@ -4,12 +4,14 @@ import isEqual from 'fast-deep-equal';
|
|
|
4
4
|
import { ReactNode, memo, useCallback, useMemo, useState } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
|
+
import { useAgentStore } from '@/store/agent';
|
|
8
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
|
7
9
|
import { useChatStore } from '@/store/chat';
|
|
8
10
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
9
11
|
import { useGlobalStore } from '@/store/global';
|
|
10
12
|
import { settingsSelectors } from '@/store/global/selectors';
|
|
11
13
|
import { useSessionStore } from '@/store/session';
|
|
12
|
-
import {
|
|
14
|
+
import { sessionMetaSelectors } from '@/store/session/selectors';
|
|
13
15
|
import { ChatMessage } from '@/types/message';
|
|
14
16
|
|
|
15
17
|
import ErrorMessageExtra, { getErrorAlertConfig } from '../../Error';
|
|
@@ -40,12 +42,12 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
|
|
|
40
42
|
const { t } = useTranslation('common');
|
|
41
43
|
const { styles, cx } = useStyles();
|
|
42
44
|
const [editing, setEditing] = useState(false);
|
|
43
|
-
const [type = 'chat'] =
|
|
45
|
+
const [type = 'chat'] = useAgentStore((s) => {
|
|
44
46
|
const config = agentSelectors.currentAgentConfig(s);
|
|
45
47
|
return [config.displayMode];
|
|
46
48
|
});
|
|
47
49
|
|
|
48
|
-
const meta = useSessionStore(
|
|
50
|
+
const meta = useSessionStore(sessionMetaSelectors.currentAgentMeta, isEqual);
|
|
49
51
|
const item = useChatStore((s) => {
|
|
50
52
|
const chats = chatSelectors.currentChatsWithGuideMessage(meta)(s);
|
|
51
53
|
|
|
@@ -99,7 +101,7 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
|
|
|
99
101
|
return { message: errorT(`response.${messageError.type}` as any), ...alertConfig };
|
|
100
102
|
}, [item?.error]);
|
|
101
103
|
|
|
102
|
-
const enableHistoryDivider =
|
|
104
|
+
const enableHistoryDivider = useAgentStore((s) => {
|
|
103
105
|
const config = agentSelectors.currentAgentConfig(s);
|
|
104
106
|
return (
|
|
105
107
|
config.enableHistoryCount &&
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
2
|
|
|
3
|
+
import { useAgentStore } from '@/store/agent';
|
|
4
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
|
3
5
|
import { useChatStore } from '@/store/chat';
|
|
4
6
|
import { useSessionStore } from '@/store/session';
|
|
5
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
6
7
|
import { useToolStore } from '@/store/tool';
|
|
7
8
|
|
|
8
9
|
export const useInitConversation = () => {
|
|
9
10
|
const [sessionId] = useSessionStore((s) => [s.activeId]);
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
11
|
+
const [useFetchAgentConfig] = useAgentStore((s) => [s.useFetchAgentConfig]);
|
|
12
|
+
const plugins = useAgentStore((s) => agentSelectors.currentAgentPlugins(s));
|
|
13
|
+
const [activeTopicId, switchTopic, useFetchMessages, useFetchTopics] = useChatStore((s) => [
|
|
13
14
|
s.activeTopicId,
|
|
14
15
|
s.switchTopic,
|
|
15
16
|
s.useFetchMessages,
|
|
@@ -18,6 +19,7 @@ export const useInitConversation = () => {
|
|
|
18
19
|
|
|
19
20
|
useFetchMessages(sessionId, activeTopicId);
|
|
20
21
|
useFetchTopics(sessionId);
|
|
22
|
+
useFetchAgentConfig(sessionId);
|
|
21
23
|
|
|
22
24
|
const [useFetchPluginStore, useFetchInstalledPlugins, checkPluginsIsInstalled] = useToolStore(
|
|
23
25
|
(s) => [s.useFetchPluginStore, s.useFetchInstalledPlugins, s.useCheckPluginsIsInstalled],
|
|
@@ -31,14 +33,15 @@ export const useInitConversation = () => {
|
|
|
31
33
|
// // when activeId changed, switch topic to undefined
|
|
32
34
|
const unsubscribe = useSessionStore.subscribe(
|
|
33
35
|
(s) => s.activeId,
|
|
34
|
-
() => {
|
|
36
|
+
(activeId) => {
|
|
35
37
|
switchTopic();
|
|
38
|
+
|
|
39
|
+
useAgentStore.setState({ activeId }, false, 'updateActiveId');
|
|
36
40
|
},
|
|
37
41
|
);
|
|
42
|
+
|
|
38
43
|
return () => {
|
|
39
44
|
unsubscribe();
|
|
40
45
|
};
|
|
41
46
|
}, []);
|
|
42
|
-
|
|
43
|
-
return init;
|
|
44
47
|
};
|
|
@@ -3,6 +3,7 @@ import { ReactNode, memo } from 'react';
|
|
|
3
3
|
import { Flexbox } from 'react-layout-kit';
|
|
4
4
|
|
|
5
5
|
import ChatHydration from '@/components/StoreHydration/ChatHydration';
|
|
6
|
+
import { useChatStore } from '@/store/chat';
|
|
6
7
|
|
|
7
8
|
import SkeletonList from './components/SkeletonList';
|
|
8
9
|
import ChatList from './components/VirtualizedList';
|
|
@@ -29,16 +30,18 @@ interface ConversationProps {
|
|
|
29
30
|
const Conversation = memo<ConversationProps>(({ chatInput, mobile }) => {
|
|
30
31
|
const { styles } = useStyles();
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
useInitConversation();
|
|
34
|
+
|
|
35
|
+
const [messagesInit] = useChatStore((s) => [s.messagesInit]);
|
|
33
36
|
|
|
34
37
|
return (
|
|
35
38
|
<Flexbox
|
|
36
39
|
flex={1}
|
|
37
|
-
//
|
|
40
|
+
// `relative` is required, ChatInput's absolute position needs it
|
|
38
41
|
style={{ position: 'relative' }}
|
|
39
42
|
>
|
|
40
43
|
<div className={styles}>
|
|
41
|
-
{
|
|
44
|
+
{messagesInit ? <ChatList mobile={mobile} /> : <SkeletonList mobile={mobile} />}
|
|
42
45
|
</div>
|
|
43
46
|
{chatInput}
|
|
44
47
|
<ChatHydration />
|
|
@@ -9,10 +9,10 @@ import { useTranslation } from 'react-i18next';
|
|
|
9
9
|
import { Flexbox } from 'react-layout-kit';
|
|
10
10
|
|
|
11
11
|
import { ModelItemRender, ProviderItemRender } from '@/components/ModelSelect';
|
|
12
|
+
import { useAgentStore } from '@/store/agent';
|
|
13
|
+
import { agentSelectors } from '@/store/agent/slices/chat';
|
|
12
14
|
import { useGlobalStore } from '@/store/global';
|
|
13
15
|
import { modelProviderSelectors } from '@/store/global/selectors';
|
|
14
|
-
import { useSessionStore } from '@/store/session';
|
|
15
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
16
16
|
import { ModelProviderCard } from '@/types/llm';
|
|
17
17
|
import { withBasePath } from '@/utils/basePath';
|
|
18
18
|
|
|
@@ -40,8 +40,10 @@ const useStyles = createStyles(({ css, prefixCls }) => ({
|
|
|
40
40
|
const ModelSwitchPanel = memo<PropsWithChildren>(({ children }) => {
|
|
41
41
|
const { t } = useTranslation('components');
|
|
42
42
|
const { styles, theme } = useStyles();
|
|
43
|
-
const model =
|
|
44
|
-
|
|
43
|
+
const [model, updateAgentConfig] = useAgentStore((s) => [
|
|
44
|
+
agentSelectors.currentAgentModel(s),
|
|
45
|
+
s.updateAgentConfig,
|
|
46
|
+
]);
|
|
45
47
|
|
|
46
48
|
const router = useRouter();
|
|
47
49
|
const enabledList = useGlobalStore(
|
package/src/hooks/useTTS.ts
CHANGED
|
@@ -11,10 +11,10 @@ import isEqual from 'fast-deep-equal';
|
|
|
11
11
|
|
|
12
12
|
import { createHeaderWithOpenAI } from '@/services/_header';
|
|
13
13
|
import { API_ENDPOINTS } from '@/services/_url';
|
|
14
|
+
import { useAgentStore } from '@/store/agent';
|
|
15
|
+
import { agentSelectors } from '@/store/agent/slices/chat';
|
|
14
16
|
import { useGlobalStore } from '@/store/global';
|
|
15
17
|
import { settingsSelectors } from '@/store/global/selectors';
|
|
16
|
-
import { useSessionStore } from '@/store/session';
|
|
17
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
18
18
|
import { TTSServer } from '@/types/agent';
|
|
19
19
|
|
|
20
20
|
interface TTSConfig extends TTSOptions {
|
|
@@ -25,9 +25,9 @@ interface TTSConfig extends TTSOptions {
|
|
|
25
25
|
|
|
26
26
|
export const useTTS = (content: string, config?: TTSConfig) => {
|
|
27
27
|
const ttsSettings = useGlobalStore(settingsSelectors.currentTTS, isEqual);
|
|
28
|
-
const ttsAgentSettings =
|
|
28
|
+
const ttsAgentSettings = useAgentStore(agentSelectors.currentAgentTTS, isEqual);
|
|
29
29
|
const lang = useGlobalStore(settingsSelectors.currentLanguage);
|
|
30
|
-
const voice =
|
|
30
|
+
const voice = useAgentStore(agentSelectors.currentAgentTTSVoice(lang));
|
|
31
31
|
let useSelectedTTS;
|
|
32
32
|
let options: any = {};
|
|
33
33
|
switch (config?.server || ttsAgentSettings.ttsService) {
|
package/src/services/chat.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
preferenceSelectors,
|
|
16
16
|
} from '@/store/global/selectors';
|
|
17
17
|
import { useSessionStore } from '@/store/session';
|
|
18
|
-
import {
|
|
18
|
+
import { sessionMetaSelectors } from '@/store/session/selectors';
|
|
19
19
|
import { useToolStore } from '@/store/tool';
|
|
20
20
|
import { pluginSelectors, toolSelectors } from '@/store/tool/selectors';
|
|
21
21
|
import { ChatErrorType } from '@/types/fetch';
|
|
@@ -267,7 +267,7 @@ class ChatService {
|
|
|
267
267
|
*/
|
|
268
268
|
if (enableFetchOnClient) {
|
|
269
269
|
try {
|
|
270
|
-
return this.fetchOnClient({ payload, provider, signal });
|
|
270
|
+
return await this.fetchOnClient({ payload, provider, signal });
|
|
271
271
|
} catch (e) {
|
|
272
272
|
const {
|
|
273
273
|
errorType = ChatErrorType.BadRequest,
|
|
@@ -447,7 +447,7 @@ class ChatService {
|
|
|
447
447
|
};
|
|
448
448
|
|
|
449
449
|
private mapTrace(trace?: TracePayload, tag?: TraceTagMap): TracePayload {
|
|
450
|
-
const tags =
|
|
450
|
+
const tags = sessionMetaSelectors.currentAgentMeta(useSessionStore.getState()).tags || [];
|
|
451
451
|
|
|
452
452
|
const enabled = preferenceSelectors.userAllowTrace(useGlobalStore.getState());
|
|
453
453
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { DeepPartial } from 'utility-types';
|
|
2
2
|
|
|
3
|
+
import { INBOX_SESSION_ID } from '@/const/session';
|
|
3
4
|
import { SessionModel } from '@/database/client/models/session';
|
|
4
5
|
import { SessionGroupModel } from '@/database/client/models/sessionGroup';
|
|
6
|
+
import { UserModel } from '@/database/client/models/user';
|
|
7
|
+
import { useGlobalStore } from '@/store/global';
|
|
5
8
|
import { LobeAgentConfig } from '@/types/agent';
|
|
6
9
|
import {
|
|
7
10
|
ChatSessionList,
|
|
@@ -40,6 +43,18 @@ export class ClientService implements ISessionService {
|
|
|
40
43
|
return SessionModel.queryWithGroups();
|
|
41
44
|
}
|
|
42
45
|
|
|
46
|
+
async getSessionConfig(id: string): Promise<LobeAgentConfig> {
|
|
47
|
+
if (!id || id === INBOX_SESSION_ID) {
|
|
48
|
+
return UserModel.getAgentConfig();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const res = await SessionModel.findById(id);
|
|
52
|
+
|
|
53
|
+
if (!res) throw new Error('Session not found');
|
|
54
|
+
|
|
55
|
+
return res.config as LobeAgentConfig;
|
|
56
|
+
}
|
|
57
|
+
|
|
43
58
|
async getSessionsByType(type: 'agent' | 'group' | 'all' = 'all'): Promise<LobeSessions> {
|
|
44
59
|
switch (type) {
|
|
45
60
|
// TODO: add a filter to get only agents or agents
|
|
@@ -81,6 +96,10 @@ export class ClientService implements ISessionService {
|
|
|
81
96
|
}
|
|
82
97
|
|
|
83
98
|
async updateSessionConfig(activeId: string, config: DeepPartial<LobeAgentConfig>) {
|
|
99
|
+
if (activeId === INBOX_SESSION_ID) {
|
|
100
|
+
return useGlobalStore.getState().updateDefaultAgent({ config });
|
|
101
|
+
}
|
|
102
|
+
|
|
84
103
|
return SessionModel.updateConfig(activeId, config);
|
|
85
104
|
}
|
|
86
105
|
|
|
@@ -28,6 +28,8 @@ export interface ISessionService {
|
|
|
28
28
|
id: string,
|
|
29
29
|
data: Partial<{ group?: SessionGroupId; pinned?: boolean }>,
|
|
30
30
|
): Promise<any>;
|
|
31
|
+
|
|
32
|
+
getSessionConfig(id: string): Promise<LobeAgentConfig>;
|
|
31
33
|
updateSessionConfig(id: string, config: DeepPartial<LobeAgentConfig>): Promise<any>;
|
|
32
34
|
|
|
33
35
|
removeSession(id: string): Promise<any>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { agentSelectors } from './slices/chat/selectors';
|