@lobehub/chat 0.149.4 → 0.149.6

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 (83) hide show
  1. package/.github/FUNDING.yml +1 -1
  2. package/CHANGELOG.md +58 -0
  3. package/docs/self-hosting/platform/docker-compose.zh-CN.mdx +15 -21
  4. package/package.json +1 -1
  5. package/src/app/chat/(desktop)/features/ChatHeader/Main.tsx +5 -5
  6. package/src/app/chat/(desktop)/features/ChatHeader/Tags.tsx +3 -3
  7. package/src/app/chat/(desktop)/features/ChatInput/Footer/DragUpload.tsx +9 -9
  8. package/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx +3 -3
  9. package/src/app/chat/(desktop)/features/SideBar/SystemRole/index.tsx +8 -3
  10. package/src/app/chat/(mobile)/mobile/ChatHeader/ChatHeaderTitle.tsx +2 -2
  11. package/src/app/chat/(mobile)/mobile/page.tsx +0 -6
  12. package/src/app/chat/_layout/Desktop/SessionList.tsx +2 -0
  13. package/src/app/chat/features/PageTitle/index.tsx +3 -3
  14. package/src/app/chat/features/PluginTag/PluginStatus.tsx +2 -2
  15. package/src/app/chat/features/SessionListContent/DefaultMode.tsx +4 -2
  16. package/src/app/chat/features/SessionListContent/List/Item/index.tsx +10 -17
  17. package/src/app/chat/features/SessionListContent/index.tsx +2 -0
  18. package/src/app/chat/features/ShareButton/Preview.tsx +15 -11
  19. package/src/app/chat/features/ShareButton/useScreenshot.ts +2 -2
  20. package/src/app/chat/settings/features/EditPage.tsx +10 -7
  21. package/src/app/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx +5 -3
  22. package/src/app/metadata.ts +3 -3
  23. package/src/app/settings/(mobile)/features/AvatarBanner.tsx +1 -0
  24. package/src/config/modelProviders/ollama.ts +11 -12
  25. package/src/const/session.ts +1 -0
  26. package/src/database/client/models/session.ts +1 -0
  27. package/src/database/client/models/user.ts +6 -0
  28. package/src/features/ChatInput/ActionBar/FileUpload.tsx +11 -5
  29. package/src/features/ChatInput/ActionBar/History.tsx +3 -3
  30. package/src/features/ChatInput/ActionBar/ModelSwitch.tsx +2 -0
  31. package/src/features/ChatInput/ActionBar/Temperature.tsx +3 -3
  32. package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +4 -4
  33. package/src/features/ChatInput/ActionBar/Token/index.tsx +3 -3
  34. package/src/features/ChatInput/ActionBar/Tools/ToolItem.tsx +3 -3
  35. package/src/features/ChatInput/ActionBar/Tools/index.tsx +4 -4
  36. package/src/features/ChatInput/STT/browser.tsx +3 -3
  37. package/src/features/ChatInput/STT/openai.tsx +3 -3
  38. package/src/features/ChatInput/useChatInput.ts +3 -3
  39. package/src/features/Conversation/Extras/Assistant.test.tsx +7 -7
  40. package/src/features/Conversation/Extras/Assistant.tsx +3 -3
  41. package/src/features/Conversation/Extras/TTS/index.tsx +3 -3
  42. package/src/features/Conversation/components/ChatItem/ActionsBar.tsx +2 -2
  43. package/src/features/Conversation/components/ChatItem/index.tsx +6 -4
  44. package/src/features/Conversation/hooks/useInitConversation.ts +10 -7
  45. package/src/features/Conversation/index.tsx +6 -3
  46. package/src/features/ModelSwitchPanel/index.tsx +6 -4
  47. package/src/hooks/useTTS.ts +4 -4
  48. package/src/libs/agent-runtime/ollama/index.ts +1 -1
  49. package/src/services/chat.ts +3 -3
  50. package/src/services/ollama.ts +1 -2
  51. package/src/services/session/client.ts +19 -0
  52. package/src/services/session/type.ts +2 -0
  53. package/src/store/agent/index.ts +2 -0
  54. package/src/store/agent/initialState.ts +7 -0
  55. package/src/store/agent/selectors.ts +1 -0
  56. package/src/store/{session/slices/agent → agent/slices/chat}/action.test.ts +26 -63
  57. package/src/store/agent/slices/chat/action.ts +107 -0
  58. package/src/store/agent/slices/chat/initialState.ts +14 -0
  59. package/src/store/agent/slices/chat/selectors.test.ts +82 -0
  60. package/src/store/agent/slices/chat/selectors.ts +81 -0
  61. package/src/store/agent/store.ts +27 -0
  62. package/src/store/chat/slices/message/action.test.ts +3 -2
  63. package/src/store/chat/slices/message/action.ts +3 -3
  64. package/src/store/chat/slices/message/selectors.test.ts +9 -2
  65. package/src/store/chat/slices/message/selectors.ts +6 -4
  66. package/src/store/chat/slices/share/action.ts +5 -3
  67. package/src/store/global/slices/preference/selectors.ts +3 -1
  68. package/src/store/session/selectors.ts +1 -2
  69. package/src/store/session/slices/session/action.test.ts +43 -0
  70. package/src/store/session/slices/session/action.ts +28 -18
  71. package/src/store/session/slices/session/helpers.ts +2 -3
  72. package/src/store/session/slices/session/initialState.ts +1 -17
  73. package/src/store/session/slices/session/selectors/index.ts +1 -0
  74. package/src/store/session/slices/session/selectors/list.test.ts +5 -3
  75. package/src/store/session/slices/session/selectors/list.ts +2 -3
  76. package/src/store/session/slices/session/selectors/meta.test.ts +108 -0
  77. package/src/store/session/slices/session/selectors/meta.ts +45 -0
  78. package/src/store/session/store.ts +1 -7
  79. package/src/types/session.ts +1 -0
  80. package/src/store/session/slices/agent/action.ts +0 -84
  81. package/src/store/session/slices/agent/selectors.test.ts +0 -180
  82. package/src/store/session/slices/agent/selectors.ts +0 -129
  83. /package/src/store/{session/slices/agent → agent/slices/chat}/index.ts +0 -0
@@ -2,6 +2,17 @@ import { ModelProviderCard } from '@/types/llm';
2
2
 
3
3
  const Ollama: ModelProviderCard = {
4
4
  chatModels: [
5
+ {
6
+ displayName: 'Llama3 8B',
7
+ enabled: true,
8
+ id: 'llama3',
9
+ tokens: 8000,
10
+ },
11
+ {
12
+ displayName: 'Llama3 70B',
13
+ id: 'llama3:70b',
14
+ tokens: 8000,
15
+ },
5
16
  {
6
17
  displayName: 'Command R 35B',
7
18
  enabled: true,
@@ -21,7 +32,6 @@ const Ollama: ModelProviderCard = {
21
32
  },
22
33
  {
23
34
  displayName: 'Gemma 2B',
24
- enabled: true,
25
35
  id: 'gemma:2b',
26
36
  tokens: 4000,
27
37
  },
@@ -50,17 +60,6 @@ const Ollama: ModelProviderCard = {
50
60
  id: 'llama2-chinese',
51
61
  tokens: 4000,
52
62
  },
53
- {
54
- displayName: 'Llama3 8B',
55
- enabled: true,
56
- id: 'llama3',
57
- tokens: 8000,
58
- },
59
- {
60
- displayName: 'Llama3 70B',
61
- id: 'llama3:70b',
62
- tokens: 8000,
63
- },
64
63
  {
65
64
  displayName: 'WizardLM 2 7B',
66
65
  enabled: true,
@@ -10,6 +10,7 @@ export const DEFAULT_AGENT_LOBE_SESSION: LobeAgentSession = {
10
10
  createdAt: Date.now(),
11
11
  id: '',
12
12
  meta: DEFAULT_AGENT_META,
13
+ model: DEFAULT_AGENT_CONFIG.model,
13
14
  type: LobeSessionType.Agent,
14
15
  updatedAt: Date.now(),
15
16
  };
@@ -254,6 +254,7 @@ class _SessionModel extends BaseModel {
254
254
  private DB_SessionToAgentSession(session: DBModel<DB_Session>) {
255
255
  return {
256
256
  ...session,
257
+ model: session.config.model,
257
258
  pinned: !!session.pinned,
258
259
  } as LobeAgentSession;
259
260
  }
@@ -1,6 +1,7 @@
1
1
  import { DeepPartial } from 'utility-types';
2
2
 
3
3
  import { BaseModel } from '@/database/client/core';
4
+ import { LobeAgentConfig } from '@/types/agent';
4
5
  import { GlobalSettings } from '@/types/settings';
5
6
  import { uuid } from '@/utils/uuid';
6
7
 
@@ -22,6 +23,11 @@ class _UserModel extends BaseModel {
22
23
  return list[0];
23
24
  };
24
25
 
26
+ getAgentConfig = async () => {
27
+ const user = await this.getUser();
28
+
29
+ return user.settings?.defaultAgent?.config as LobeAgentConfig;
30
+ };
25
31
  // **************** Create *************** //
26
32
 
27
33
  create = async (user: DB_User) => {
@@ -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 { LucideImage, FileUp, LucideLoader2 } from 'lucide-react';
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 = useSessionStore(agentSelectors.currentAgentModel);
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(canUpload ? (enabledFiles ? 'upload.actionFiletip' : 'upload.actionTooltip') : 'upload.disabled')}
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 { useSessionStore } from '@/store/session';
9
- import { agentSelectors } from '@/store/session/selectors';
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] = useSessionStore((s) => {
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
  });
@@ -15,4 +15,6 @@ const ModelSwitch = memo(() => {
15
15
  );
16
16
  });
17
17
 
18
+ ModelSwitch.displayName = 'ModelSwitch';
19
+
18
20
  export default ModelSwitch;
@@ -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 { useSessionStore } from '@/store/session';
8
- import { agentSelectors } from '@/store/session/selectors';
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] = useSessionStore((s) => {
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] = useSessionStore((s) => [
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 = useSessionStore(agentSelectors.currentAgentPlugins);
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 = useSessionStore(agentSelectors.currentAgentModel);
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 { useSessionStore } from '@/store/session';
7
- import { agentSelectors } from '@/store/session/selectors';
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] = useSessionStore((s) => [
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 = useSessionStore(
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 = useSessionStore(agentSelectors.currentAgentModel);
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 = useSessionStore(agentSelectors.currentAgentTTS, isEqual);
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 = useSessionStore(agentSelectors.currentAgentTTS, isEqual);
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 = useSessionStore(agentSelectors.currentAgentModel);
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 { useSessionStore } from '@/store/session';
5
- import { agentSelectors } from '@/store/session/selectors';
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/session', () => ({
20
- useSessionStore: vi.fn(),
19
+ vi.mock('@/store/agent', () => ({
20
+ useAgentStore: vi.fn(),
21
21
  }));
22
- vi.mock('@/store/session/selectors', () => ({
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
- (useSessionStore as unknown as Mock).mockImplementation(() => ({
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
- (useSessionStore as unknown as Mock).mockImplementation(() => ({
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 = useSessionStore(agentSelectors.currentAgentModel);
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 = useSessionStore(agentSelectors.currentAgentTTSVoice(lang));
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 { agentSelectors } from '@/store/session/selectors';
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(agentSelectors.currentAgentMeta, isEqual);
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 { agentSelectors } from '@/store/session/selectors';
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'] = useSessionStore((s) => {
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(agentSelectors.currentAgentMeta, isEqual);
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 = useSessionStore((s) => {
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 plugins = useSessionStore((s) => agentSelectors.currentAgentPlugins(s));
11
- const [init, activeTopicId, switchTopic, useFetchMessages, useFetchTopics] = useChatStore((s) => [
12
- s.messagesInit,
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
- const init = useInitConversation();
33
+ useInitConversation();
34
+
35
+ const [messagesInit] = useChatStore((s) => [s.messagesInit]);
33
36
 
34
37
  return (
35
38
  <Flexbox
36
39
  flex={1}
37
- // position: 'relative' is required, ChatInput's absolute position needs it
40
+ // `relative` is required, ChatInput's absolute position needs it
38
41
  style={{ position: 'relative' }}
39
42
  >
40
43
  <div className={styles}>
41
- {init ? <ChatList mobile={mobile} /> : <SkeletonList mobile={mobile} />}
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 = useSessionStore(agentSelectors.currentAgentModel);
44
- const updateAgentConfig = useSessionStore((s) => s.updateAgentConfig);
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(
@@ -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 = useSessionStore(agentSelectors.currentAgentTTS, isEqual);
28
+ const ttsAgentSettings = useAgentStore(agentSelectors.currentAgentTTS, isEqual);
29
29
  const lang = useGlobalStore(settingsSelectors.currentLanguage);
30
- const voice = useSessionStore(agentSelectors.currentAgentTTSVoice(lang));
30
+ const voice = useAgentStore(agentSelectors.currentAgentTTSVoice(lang));
31
31
  let useSelectedTTS;
32
32
  let options: any = {};
33
33
  switch (config?.server || ttsAgentSettings.ttsService) {
@@ -24,7 +24,7 @@ export class LobeOllamaAI implements LobeRuntimeAI {
24
24
  throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidOllamaArgs);
25
25
  }
26
26
 
27
- this.client = new Ollama(!baseURL ? undefined : { host: new URL(baseURL).host });
27
+ this.client = new Ollama(!baseURL ? undefined : { host: baseURL });
28
28
 
29
29
  if (baseURL) this.baseURL = baseURL;
30
30
  }