@lobehub/chat 0.149.3 → 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.
Files changed (88) hide show
  1. package/.github/FUNDING.yml +1 -1
  2. package/CHANGELOG.md +58 -0
  3. package/package.json +1 -1
  4. package/src/app/chat/(desktop)/features/ChatHeader/Main.tsx +5 -5
  5. package/src/app/chat/(desktop)/features/ChatHeader/Tags.tsx +3 -3
  6. package/src/app/chat/(desktop)/features/ChatInput/Footer/DragUpload.tsx +9 -9
  7. package/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx +3 -3
  8. package/src/app/chat/(desktop)/features/SideBar/SystemRole/index.tsx +8 -3
  9. package/src/app/chat/(mobile)/mobile/ChatHeader/ChatHeaderTitle.tsx +2 -2
  10. package/src/app/chat/(mobile)/mobile/page.tsx +0 -6
  11. package/src/app/chat/_layout/Desktop/SessionList.tsx +2 -0
  12. package/src/app/chat/features/PageTitle/index.tsx +3 -3
  13. package/src/app/chat/features/PluginTag/PluginStatus.tsx +2 -2
  14. package/src/app/chat/features/SessionListContent/DefaultMode.tsx +4 -2
  15. package/src/app/chat/features/SessionListContent/List/Item/index.tsx +10 -17
  16. package/src/app/chat/features/SessionListContent/index.tsx +2 -0
  17. package/src/app/chat/features/ShareButton/Preview.tsx +15 -11
  18. package/src/app/chat/features/ShareButton/useScreenshot.ts +2 -2
  19. package/src/app/chat/settings/features/EditPage.tsx +10 -7
  20. package/src/app/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx +5 -3
  21. package/src/app/metadata.ts +3 -3
  22. package/src/app/settings/(mobile)/features/AvatarBanner.tsx +1 -0
  23. package/src/config/modelProviders/ollama.ts +11 -12
  24. package/src/const/session.ts +1 -0
  25. package/src/database/client/models/session.ts +1 -0
  26. package/src/database/client/models/user.ts +6 -0
  27. package/src/features/ChatInput/ActionBar/FileUpload.tsx +11 -5
  28. package/src/features/ChatInput/ActionBar/History.tsx +3 -3
  29. package/src/features/ChatInput/ActionBar/ModelSwitch.tsx +2 -0
  30. package/src/features/ChatInput/ActionBar/Temperature.tsx +3 -3
  31. package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +4 -4
  32. package/src/features/ChatInput/ActionBar/Token/index.tsx +3 -3
  33. package/src/features/ChatInput/ActionBar/Tools/ToolItem.tsx +3 -3
  34. package/src/features/ChatInput/ActionBar/Tools/index.tsx +4 -4
  35. package/src/features/ChatInput/STT/browser.tsx +3 -3
  36. package/src/features/ChatInput/STT/openai.tsx +3 -3
  37. package/src/features/ChatInput/useChatInput.ts +3 -3
  38. package/src/features/Conversation/Extras/Assistant.test.tsx +7 -7
  39. package/src/features/Conversation/Extras/Assistant.tsx +3 -3
  40. package/src/features/Conversation/Extras/TTS/index.tsx +3 -3
  41. package/src/features/Conversation/components/ChatItem/ActionsBar.tsx +2 -2
  42. package/src/features/Conversation/components/ChatItem/index.tsx +6 -4
  43. package/src/features/Conversation/hooks/useInitConversation.ts +10 -7
  44. package/src/features/Conversation/index.tsx +6 -3
  45. package/src/features/ModelSwitchPanel/index.tsx +6 -4
  46. package/src/hooks/useTTS.ts +4 -4
  47. package/src/libs/agent-runtime/anthropic/index.test.ts +44 -32
  48. package/src/libs/agent-runtime/anthropic/index.ts +12 -9
  49. package/src/libs/agent-runtime/azureOpenai/index.ts +3 -4
  50. package/src/libs/agent-runtime/bedrock/index.ts +1 -1
  51. package/src/libs/agent-runtime/ollama/index.ts +7 -0
  52. package/src/libs/agent-runtime/perplexity/index.ts +1 -0
  53. package/src/libs/agent-runtime/types/chat.ts +2 -1
  54. package/src/libs/agent-runtime/utils/openaiCompatibleFactory/index.ts +1 -0
  55. package/src/services/chat.ts +18 -15
  56. package/src/services/session/client.ts +19 -0
  57. package/src/services/session/type.ts +2 -0
  58. package/src/store/agent/index.ts +2 -0
  59. package/src/store/agent/initialState.ts +7 -0
  60. package/src/store/agent/selectors.ts +1 -0
  61. package/src/store/{session/slices/agent → agent/slices/chat}/action.test.ts +26 -63
  62. package/src/store/agent/slices/chat/action.ts +107 -0
  63. package/src/store/agent/slices/chat/initialState.ts +14 -0
  64. package/src/store/agent/slices/chat/selectors.test.ts +82 -0
  65. package/src/store/agent/slices/chat/selectors.ts +81 -0
  66. package/src/store/agent/store.ts +27 -0
  67. package/src/store/chat/slices/message/action.test.ts +3 -2
  68. package/src/store/chat/slices/message/action.ts +3 -3
  69. package/src/store/chat/slices/message/selectors.test.ts +9 -2
  70. package/src/store/chat/slices/message/selectors.ts +6 -4
  71. package/src/store/chat/slices/share/action.ts +5 -3
  72. package/src/store/global/slices/preference/selectors.ts +3 -1
  73. package/src/store/session/selectors.ts +1 -2
  74. package/src/store/session/slices/session/action.test.ts +43 -0
  75. package/src/store/session/slices/session/action.ts +28 -18
  76. package/src/store/session/slices/session/helpers.ts +2 -3
  77. package/src/store/session/slices/session/initialState.ts +1 -17
  78. package/src/store/session/slices/session/selectors/index.ts +1 -0
  79. package/src/store/session/slices/session/selectors/list.test.ts +5 -3
  80. package/src/store/session/slices/session/selectors/list.ts +2 -3
  81. package/src/store/session/slices/session/selectors/meta.test.ts +108 -0
  82. package/src/store/session/slices/session/selectors/meta.ts +45 -0
  83. package/src/store/session/store.ts +1 -7
  84. package/src/types/session.ts +1 -0
  85. package/src/store/session/slices/agent/action.ts +0 -84
  86. package/src/store/session/slices/agent/selectors.test.ts +0 -180
  87. package/src/store/session/slices/agent/selectors.ts +0 -129
  88. /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 { 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) {
@@ -72,14 +72,17 @@ describe('LobeAnthropicAI', () => {
72
72
  });
73
73
 
74
74
  // Assert
75
- expect(instance['client'].messages.create).toHaveBeenCalledWith({
76
- max_tokens: 4096,
77
- messages: [{ content: 'Hello', role: 'user' }],
78
- model: 'claude-3-haiku-20240307',
79
- stream: true,
80
- temperature: 0,
81
- top_p: 1,
82
- });
75
+ expect(instance['client'].messages.create).toHaveBeenCalledWith(
76
+ {
77
+ max_tokens: 4096,
78
+ messages: [{ content: 'Hello', role: 'user' }],
79
+ model: 'claude-3-haiku-20240307',
80
+ stream: true,
81
+ temperature: 0,
82
+ top_p: 1,
83
+ },
84
+ {},
85
+ );
83
86
  expect(result).toBeInstanceOf(Response);
84
87
  });
85
88
 
@@ -105,14 +108,17 @@ describe('LobeAnthropicAI', () => {
105
108
  });
106
109
 
107
110
  // Assert
108
- expect(instance['client'].messages.create).toHaveBeenCalledWith({
109
- max_tokens: 4096,
110
- messages: [{ content: 'Hello', role: 'user' }],
111
- model: 'claude-3-haiku-20240307',
112
- stream: true,
113
- system: 'You are an awesome greeter',
114
- temperature: 0,
115
- });
111
+ expect(instance['client'].messages.create).toHaveBeenCalledWith(
112
+ {
113
+ max_tokens: 4096,
114
+ messages: [{ content: 'Hello', role: 'user' }],
115
+ model: 'claude-3-haiku-20240307',
116
+ stream: true,
117
+ system: 'You are an awesome greeter',
118
+ temperature: 0,
119
+ },
120
+ {},
121
+ );
116
122
  expect(result).toBeInstanceOf(Response);
117
123
  });
118
124
 
@@ -137,14 +143,17 @@ describe('LobeAnthropicAI', () => {
137
143
  });
138
144
 
139
145
  // Assert
140
- expect(instance['client'].messages.create).toHaveBeenCalledWith({
141
- max_tokens: 2048,
142
- messages: [{ content: 'Hello', role: 'user' }],
143
- model: 'claude-3-haiku-20240307',
144
- stream: true,
145
- temperature: 0.5,
146
- top_p: 1,
147
- });
146
+ expect(instance['client'].messages.create).toHaveBeenCalledWith(
147
+ {
148
+ max_tokens: 2048,
149
+ messages: [{ content: 'Hello', role: 'user' }],
150
+ model: 'claude-3-haiku-20240307',
151
+ stream: true,
152
+ temperature: 0.5,
153
+ top_p: 1,
154
+ },
155
+ {},
156
+ );
148
157
  expect(result).toBeInstanceOf(Response);
149
158
  });
150
159
 
@@ -171,14 +180,17 @@ describe('LobeAnthropicAI', () => {
171
180
  });
172
181
 
173
182
  // Assert
174
- expect(instance['client'].messages.create).toHaveBeenCalledWith({
175
- max_tokens: 2048,
176
- messages: [{ content: 'Hello', role: 'user' }],
177
- model: 'claude-3-haiku-20240307',
178
- stream: true,
179
- temperature: 0.5,
180
- top_p: 1,
181
- });
183
+ expect(instance['client'].messages.create).toHaveBeenCalledWith(
184
+ {
185
+ max_tokens: 2048,
186
+ messages: [{ content: 'Hello', role: 'user' }],
187
+ model: 'claude-3-haiku-20240307',
188
+ stream: true,
189
+ temperature: 0.5,
190
+ top_p: 1,
191
+ },
192
+ {},
193
+ );
182
194
  expect(result).toBeInstanceOf(Response);
183
195
  });
184
196