@lobehub/chat 0.150.9 → 0.150.10

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 (131) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/package.json +1 -1
  3. package/src/app/chat/(desktop)/features/ChatHeader/Tags.tsx +3 -3
  4. package/src/app/chat/(desktop)/features/ChatInput/Footer/DragUpload.tsx +3 -3
  5. package/src/app/chat/(desktop)/features/ChatInput/Footer/SendMore.tsx +3 -3
  6. package/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx +3 -3
  7. package/src/app/chat/(desktop)/features/ChatInput/TextArea.test.tsx +5 -5
  8. package/src/app/chat/(desktop)/features/ChatInput/TextArea.tsx +3 -3
  9. package/src/app/chat/(mobile)/features/SessionHeader.tsx +3 -3
  10. package/src/app/chat/features/ShareButton/ShareModal.tsx +3 -3
  11. package/src/app/chat/features/TelemetryNotification/index.tsx +2 -2
  12. package/src/app/chat/features/TopicListContent/Topic/index.tsx +2 -2
  13. package/src/app/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx +3 -3
  14. package/src/app/settings/(mobile)/index.tsx +3 -3
  15. package/src/app/settings/about/Analytics.tsx +4 -4
  16. package/src/app/settings/agent/Agent.tsx +4 -4
  17. package/src/app/settings/common/Common.tsx +4 -4
  18. package/src/app/settings/common/Theme.tsx +4 -4
  19. package/src/app/settings/features/ThemeSwatches/ThemeSwatchesNeutral.tsx +3 -3
  20. package/src/app/settings/features/ThemeSwatches/ThemeSwatchesPrimary.tsx +3 -3
  21. package/src/app/settings/hooks/useSyncSettings.ts +3 -3
  22. package/src/app/settings/llm/Azure/index.tsx +3 -3
  23. package/src/app/settings/llm/components/ProviderConfig/index.tsx +3 -3
  24. package/src/app/settings/llm/components/ProviderModelList/CustomModelOption.tsx +4 -4
  25. package/src/app/settings/llm/components/ProviderModelList/ModelConfigModal.tsx +4 -4
  26. package/src/app/settings/llm/components/ProviderModelList/ModelFetcher.tsx +6 -6
  27. package/src/app/settings/llm/components/ProviderModelList/Option.tsx +3 -3
  28. package/src/app/settings/llm/components/ProviderModelList/index.tsx +6 -6
  29. package/src/app/settings/sync/Alert.tsx +3 -3
  30. package/src/app/settings/sync/DeviceInfo/DeviceName.tsx +3 -3
  31. package/src/app/settings/sync/WebRTC/index.tsx +2 -2
  32. package/src/app/settings/tts/TTS/index.tsx +4 -4
  33. package/src/chains/__tests__/summaryAgentName.test.ts +2 -2
  34. package/src/chains/__tests__/summaryDescription.test.ts +2 -2
  35. package/src/chains/__tests__/summaryTags.test.ts +2 -2
  36. package/src/chains/__tests__/summaryTitle.test.ts +2 -2
  37. package/src/chains/summaryAgentName.ts +1 -1
  38. package/src/chains/summaryDescription.ts +1 -1
  39. package/src/chains/summaryTags.ts +1 -1
  40. package/src/chains/summaryTitle.ts +1 -1
  41. package/src/features/AgentSetting/AgentConfig/ModelSelect.tsx +3 -6
  42. package/src/features/AgentSetting/AgentMeta/index.tsx +3 -3
  43. package/src/features/AgentSetting/AgentPrompt/TokenTag.tsx +4 -4
  44. package/src/features/AgentSetting/AgentTTS/index.tsx +3 -3
  45. package/src/features/AvatarWithUpload/index.tsx +3 -3
  46. package/src/features/ChatInput/ActionBar/FileUpload.tsx +3 -3
  47. package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +4 -4
  48. package/src/features/ChatInput/ActionBar/Token/index.tsx +3 -3
  49. package/src/features/ChatInput/ActionBar/Tools/index.tsx +3 -3
  50. package/src/features/ChatInput/STT/browser.tsx +4 -4
  51. package/src/features/ChatInput/STT/index.tsx +3 -3
  52. package/src/features/ChatInput/STT/openai.tsx +4 -4
  53. package/src/features/ChatInput/useChatInput.ts +3 -3
  54. package/src/features/Conversation/Error/APIKeyForm/Bedrock.tsx +3 -3
  55. package/src/features/Conversation/Error/APIKeyForm/ProviderApiKeyForm.tsx +3 -3
  56. package/src/features/Conversation/Error/AccessCodeForm.tsx +3 -3
  57. package/src/features/Conversation/Extras/TTS/index.tsx +3 -3
  58. package/src/features/Conversation/Plugins/Render/MarkdownType/index.tsx +3 -3
  59. package/src/features/Conversation/components/ChatItem/index.tsx +3 -3
  60. package/src/features/ModelSwitchPanel/index.tsx +3 -6
  61. package/src/features/PluginDevModal/LocalForm.tsx +3 -3
  62. package/src/features/SyncStatusInspector/DisableSync.tsx +3 -3
  63. package/src/features/SyncStatusInspector/EnableSync.tsx +4 -4
  64. package/src/features/SyncStatusInspector/index.tsx +2 -2
  65. package/src/hooks/_header.ts +4 -4
  66. package/src/hooks/useSyncData.ts +3 -3
  67. package/src/hooks/useTTS.ts +4 -4
  68. package/src/layout/DefaultLayout/Desktop/SideBar/BottomActions.tsx +2 -2
  69. package/src/layout/DefaultLayout/Desktop/SideBar/TopActions.tsx +2 -2
  70. package/src/layout/DefaultLayout/Mobile/index.tsx +1 -1
  71. package/src/layout/GlobalProvider/AppTheme.tsx +4 -4
  72. package/src/layout/GlobalProvider/StoreInitialization.tsx +6 -1
  73. package/src/services/__tests__/chat.test.ts +17 -20
  74. package/src/services/__tests__/tool.test.ts +2 -2
  75. package/src/services/_auth.test.ts +2 -2
  76. package/src/services/_auth.ts +7 -7
  77. package/src/services/_header.ts +4 -4
  78. package/src/services/chat.ts +13 -13
  79. package/src/services/config.ts +4 -4
  80. package/src/services/models.ts +3 -3
  81. package/src/services/ollama.ts +3 -3
  82. package/src/services/session/client.ts +2 -2
  83. package/src/services/tool.ts +1 -1
  84. package/src/services/trace.ts +3 -3
  85. package/src/store/agent/slices/chat/selectors.test.ts +2 -2
  86. package/src/store/chat/slices/message/selectors.test.ts +1 -1
  87. package/src/store/chat/slices/message/selectors.ts +3 -3
  88. package/src/store/global/{slices/preference/action.test.ts → action.test.ts} +65 -13
  89. package/src/store/global/{slices/preference/action.ts → action.ts} +30 -16
  90. package/src/store/global/initialState.ts +58 -8
  91. package/src/store/global/selectors.ts +9 -8
  92. package/src/store/global/store.ts +3 -7
  93. package/src/store/market/action.ts +1 -1
  94. package/src/store/session/slices/session/action.ts +3 -3
  95. package/src/store/{global → user}/helpers.ts +2 -2
  96. package/src/store/user/index.ts +1 -0
  97. package/src/store/user/initialState.ts +11 -0
  98. package/src/store/user/selectors.ts +8 -0
  99. package/src/store/{global → user}/slices/common/action.test.ts +29 -81
  100. package/src/store/{global → user}/slices/common/action.ts +2 -20
  101. package/src/store/user/slices/common/initialState.ts +18 -0
  102. package/src/store/user/slices/common/selectors.ts +6 -0
  103. package/src/store/user/slices/preference/action.test.ts +41 -0
  104. package/src/store/user/slices/preference/action.ts +50 -0
  105. package/src/store/user/slices/preference/initialState.ts +33 -0
  106. package/src/store/user/slices/preference/selectors.ts +13 -0
  107. package/src/store/{global → user}/slices/settings/actions/general.test.ts +6 -6
  108. package/src/store/{global → user}/slices/settings/actions/general.ts +2 -2
  109. package/src/store/{global → user}/slices/settings/actions/index.ts +2 -2
  110. package/src/store/{global → user}/slices/settings/actions/llm.test.ts +11 -14
  111. package/src/store/{global → user}/slices/settings/actions/llm.ts +2 -2
  112. package/src/store/{global → user}/slices/settings/initialState.ts +2 -2
  113. package/src/store/{global → user}/slices/settings/selectors/modelConfig.test.ts +8 -8
  114. package/src/store/{global → user}/slices/settings/selectors/modelConfig.ts +12 -12
  115. package/src/store/{global → user}/slices/settings/selectors/modelProvider.test.ts +17 -17
  116. package/src/store/{global → user}/slices/settings/selectors/modelProvider.ts +19 -20
  117. package/src/store/{global → user}/slices/settings/selectors/selectors.test.ts +8 -8
  118. package/src/store/{global → user}/slices/settings/selectors/settings.ts +12 -12
  119. package/src/store/user/slices/settings/selectors/sync.ts +14 -0
  120. package/src/store/user/store.ts +33 -0
  121. package/src/tools/dalle/Render/ToolBar.tsx +3 -3
  122. package/src/utils/localStorage.ts +3 -1
  123. package/src/store/global/slices/common/initialState.ts +0 -42
  124. package/src/store/global/slices/common/selectors.ts +0 -6
  125. package/src/store/global/slices/preference/initialState.ts +0 -51
  126. package/src/store/global/slices/preference/selectors.ts +0 -18
  127. package/src/store/global/slices/settings/selectors/sync.ts +0 -14
  128. /package/src/store/{global → user}/slices/settings/reducers/customModelCard.test.ts +0 -0
  129. /package/src/store/{global → user}/slices/settings/reducers/customModelCard.ts +0 -0
  130. /package/src/store/{global → user}/slices/settings/selectors/__snapshots__/selectors.test.ts.snap +0 -0
  131. /package/src/store/{global → user}/slices/settings/selectors/index.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  import { createHeaderWithAuth } from '@/services/_auth';
2
- import { useGlobalStore } from '@/store/global';
3
- import { modelConfigSelectors } from '@/store/global/selectors';
2
+ import { useUserStore } from '@/store/user';
3
+ import { modelConfigSelectors } from '@/store/user/selectors';
4
4
  import { ChatModelCard } from '@/types/llm';
5
5
 
6
6
  import { API_ENDPOINTS } from './_url';
@@ -17,7 +17,7 @@ class ModelsService {
17
17
  * Use browser agent runtime
18
18
  */
19
19
  const enableFetchOnClient = modelConfigSelectors.isProviderFetchOnClient(provider)(
20
- useGlobalStore.getState(),
20
+ useUserStore.getState(),
21
21
  );
22
22
  if (enableFetchOnClient) {
23
23
  const agentRuntime = await initializeWithClientStore(provider, {});
@@ -2,8 +2,8 @@ import { ListResponse, Ollama as OllamaBrowser, ProgressResponse } from 'ollama/
2
2
 
3
3
  import { createErrorResponse } from '@/app/api/errorResponse';
4
4
  import { ModelProvider } from '@/libs/agent-runtime';
5
- import { useGlobalStore } from '@/store/global';
6
- import { modelConfigSelectors } from '@/store/global/selectors';
5
+ import { useUserStore } from '@/store/user';
6
+ import { modelConfigSelectors } from '@/store/user/selectors';
7
7
  import { ChatErrorType } from '@/types/fetch';
8
8
  import { getMessageError } from '@/utils/fetch';
9
9
 
@@ -25,7 +25,7 @@ export class OllamaService {
25
25
  }
26
26
 
27
27
  getHost = (): string => {
28
- const config = modelConfigSelectors.ollamaConfig(useGlobalStore.getState());
28
+ const config = modelConfigSelectors.ollamaConfig(useUserStore.getState());
29
29
 
30
30
  return config.endpoint || DEFAULT_BASE_URL;
31
31
  };
@@ -4,7 +4,7 @@ import { INBOX_SESSION_ID } from '@/const/session';
4
4
  import { SessionModel } from '@/database/client/models/session';
5
5
  import { SessionGroupModel } from '@/database/client/models/sessionGroup';
6
6
  import { UserModel } from '@/database/client/models/user';
7
- import { useGlobalStore } from '@/store/global';
7
+ import { useUserStore } from '@/store/user';
8
8
  import { LobeAgentConfig } from '@/types/agent';
9
9
  import {
10
10
  ChatSessionList,
@@ -97,7 +97,7 @@ export class ClientService implements ISessionService {
97
97
 
98
98
  async updateSessionConfig(activeId: string, config: DeepPartial<LobeAgentConfig>) {
99
99
  if (activeId === INBOX_SESSION_ID) {
100
- return useGlobalStore.getState().updateDefaultAgent({ config });
100
+ return useUserStore.getState().updateDefaultAgent({ config });
101
101
  }
102
102
 
103
103
  return SessionModel.updateConfig(activeId, config);
@@ -4,7 +4,7 @@ import {
4
4
  pluginManifestSchema,
5
5
  } from '@lobehub/chat-plugin-sdk';
6
6
 
7
- import { globalHelpers } from '@/store/global/helpers';
7
+ import { globalHelpers } from '@/store/user/helpers';
8
8
  import { OpenAIPluginManifest } from '@/types/openai/plugin';
9
9
 
10
10
  import { API_ENDPOINTS } from './_url';
@@ -1,6 +1,6 @@
1
1
  import { API_ENDPOINTS } from '@/services/_url';
2
- import { useGlobalStore } from '@/store/global';
3
- import { preferenceSelectors } from '@/store/global/selectors';
2
+ import { useUserStore } from '@/store/user';
3
+ import { preferenceSelectors } from '@/store/user/selectors';
4
4
  import { TraceEventBasePayload, TraceEventPayloads } from '@/types/trace';
5
5
 
6
6
  class TraceService {
@@ -17,7 +17,7 @@ class TraceService {
17
17
  }
18
18
 
19
19
  async traceEvent(data: TraceEventPayloads & TraceEventBasePayload) {
20
- const enabled = preferenceSelectors.userAllowTrace(useGlobalStore.getState());
20
+ const enabled = preferenceSelectors.userAllowTrace(useUserStore.getState());
21
21
 
22
22
  if (!enabled) return;
23
23
 
@@ -3,8 +3,8 @@ import { describe, expect, it } from 'vitest';
3
3
  import { INBOX_SESSION_ID } from '@/const/session';
4
4
  import { DEFAULT_AGENT_CONFIG, DEFAUTT_AGENT_TTS_CONFIG } from '@/const/settings';
5
5
  import { AgentStore } from '@/store/agent';
6
- import { GlobalStore } from '@/store/global';
7
- import { settingsSelectors } from '@/store/global/slices/settings/selectors';
6
+ import { UserStore } from '@/store/user';
7
+ import { settingsSelectors } from '@/store/user/slices/settings/selectors';
8
8
  import { LobeAgentConfig } from '@/types/agent';
9
9
 
10
10
  import { agentSelectors } from './selectors';
@@ -6,8 +6,8 @@ import { INBOX_SESSION_ID } from '@/const/session';
6
6
  import { useAgentStore } from '@/store/agent';
7
7
  import { ChatStore } from '@/store/chat';
8
8
  import { initialState } from '@/store/chat/initialState';
9
- import { useGlobalStore } from '@/store/global';
10
9
  import { useSessionStore } from '@/store/session';
10
+ import { useUserStore } from '@/store/user';
11
11
  import { LobeAgentConfig } from '@/types/agent';
12
12
  import { ChatMessage } from '@/types/message';
13
13
  import { MetaData } from '@/types/meta';
@@ -5,10 +5,10 @@ import { DEFAULT_INBOX_AVATAR, DEFAULT_USER_AVATAR } from '@/const/meta';
5
5
  import { INBOX_SESSION_ID } from '@/const/session';
6
6
  import { useAgentStore } from '@/store/agent';
7
7
  import { agentSelectors } from '@/store/agent/selectors';
8
- import { useGlobalStore } from '@/store/global';
9
- import { commonSelectors } from '@/store/global/selectors';
10
8
  import { useSessionStore } from '@/store/session';
11
9
  import { sessionMetaSelectors } from '@/store/session/selectors';
10
+ import { useUserStore } from '@/store/user';
11
+ import { commonSelectors } from '@/store/user/selectors';
12
12
  import { ChatMessage } from '@/types/message';
13
13
  import { MetaData } from '@/types/meta';
14
14
  import { merge } from '@/utils/merge';
@@ -20,7 +20,7 @@ const getMeta = (message: ChatMessage) => {
20
20
  switch (message.role) {
21
21
  case 'user': {
22
22
  return {
23
- avatar: commonSelectors.userAvatar(useGlobalStore.getState()) || DEFAULT_USER_AVATAR,
23
+ avatar: commonSelectors.userAvatar(useUserStore.getState()) || DEFAULT_USER_AVATAR,
24
24
  };
25
25
  }
26
26
 
@@ -1,9 +1,23 @@
1
- import { act, renderHook } from '@testing-library/react';
1
+ import { act, renderHook, waitFor } from '@testing-library/react';
2
2
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import { withSWR } from '~test-utils';
3
4
 
4
- import { useGlobalStore } from '@/store/global';
5
+ import { globalService } from '@/services/global';
6
+ import { useGlobalStore } from '@/store/global/index';
5
7
 
6
- import { type Guide } from './initialState';
8
+ vi.mock('zustand/traditional');
9
+
10
+ vi.mock('@/utils/client/switchLang', () => ({
11
+ switchLang: vi.fn(),
12
+ }));
13
+
14
+ vi.mock('swr', async (importOriginal) => {
15
+ const modules = await importOriginal();
16
+ return {
17
+ ...(modules as any),
18
+ mutate: vi.fn(),
19
+ };
20
+ });
7
21
 
8
22
  beforeEach(() => {
9
23
  vi.clearAllMocks();
@@ -64,29 +78,67 @@ describe('createPreferenceSlice', () => {
64
78
  });
65
79
  });
66
80
 
67
- describe('updateGuideState', () => {
68
- it('should update guide state', () => {
81
+ describe('updatePreference', () => {
82
+ it('should update preference', () => {
69
83
  const { result } = renderHook(() => useGlobalStore());
70
- const guide: Guide = { topic: true };
84
+ const preference = { inputHeight: 200 };
71
85
 
72
86
  act(() => {
73
- result.current.updateGuideState(guide);
87
+ result.current.updatePreference(preference);
74
88
  });
75
89
 
76
- expect(result.current.preference.guide).toEqual(guide);
90
+ expect(result.current.preference.inputHeight).toEqual(200);
77
91
  });
78
92
  });
79
93
 
80
- describe('updatePreference', () => {
81
- it('should update preference', () => {
94
+ describe('switchBackToChat', () => {
95
+ it('should switch back to chat', () => {
82
96
  const { result } = renderHook(() => useGlobalStore());
83
- const preference = { inputHeight: 200 };
97
+ const sessionId = 'session-id';
98
+ const router = { push: vi.fn() } as any;
84
99
 
85
100
  act(() => {
86
- result.current.updatePreference(preference);
101
+ useGlobalStore.setState({ router });
102
+ result.current.switchBackToChat(sessionId);
87
103
  });
88
104
 
89
- expect(result.current.preference.inputHeight).toEqual(200);
105
+ expect(router.push).toHaveBeenCalledWith('/chat?session=session-id');
106
+ });
107
+ });
108
+
109
+ describe('useCheckLatestVersion', () => {
110
+ it('should set hasNewVersion to false if there is no new version', async () => {
111
+ const latestVersion = '0.0.1';
112
+
113
+ vi.spyOn(globalService, 'getLatestVersion').mockResolvedValueOnce(latestVersion);
114
+
115
+ const { result } = renderHook(() => useGlobalStore().useCheckLatestVersion(), {
116
+ wrapper: withSWR,
117
+ });
118
+
119
+ await waitFor(() => {
120
+ expect(result.current.data).toBe(latestVersion);
121
+ });
122
+
123
+ expect(useGlobalStore.getState().hasNewVersion).toBeUndefined();
124
+ expect(useGlobalStore.getState().latestVersion).toBeUndefined();
125
+ });
126
+
127
+ it('should set hasNewVersion to true if there is a new version', async () => {
128
+ const latestVersion = '10000000.0.0';
129
+
130
+ vi.spyOn(globalService, 'getLatestVersion').mockResolvedValueOnce(latestVersion);
131
+
132
+ const { result } = renderHook(() => useGlobalStore().useCheckLatestVersion(), {
133
+ wrapper: withSWR,
134
+ });
135
+
136
+ await waitFor(() => {
137
+ expect(result.current.data).toBe(latestVersion);
138
+ });
139
+
140
+ expect(useGlobalStore.getState().hasNewVersion).toBe(true);
141
+ expect(useGlobalStore.getState().latestVersion).toBe(latestVersion);
90
142
  });
91
143
  });
92
144
  });
@@ -1,35 +1,44 @@
1
1
  import { produce } from 'immer';
2
- import { SWRResponse } from 'swr';
2
+ import { gt } from 'semver';
3
+ import useSWR, { SWRResponse } from 'swr';
3
4
  import type { StateCreator } from 'zustand/vanilla';
4
5
 
6
+ import { INBOX_SESSION_ID } from '@/const/session';
7
+ import { SESSION_CHAT_URL } from '@/const/url';
8
+ import { CURRENT_VERSION } from '@/const/version';
5
9
  import { useClientDataSWR } from '@/libs/swr';
6
- import type { GlobalStore } from '@/store/global';
10
+ import { globalService } from '@/services/global';
11
+ import type { GlobalStore } from '@/store/global/index';
7
12
  import { merge } from '@/utils/merge';
8
13
  import { setNamespace } from '@/utils/storeDebug';
9
14
 
10
- import type { GlobalPreference, Guide } from './initialState';
15
+ import type { GlobalPreference } from './initialState';
11
16
 
12
17
  const n = setNamespace('preference');
13
18
 
14
19
  /**
15
20
  * 设置操作
16
21
  */
17
- export interface PreferenceAction {
22
+ export interface GlobalStoreAction {
23
+ switchBackToChat: (sessionId?: string) => void;
18
24
  toggleChatSideBar: (visible?: boolean) => void;
19
25
  toggleExpandSessionGroup: (id: string, expand: boolean) => void;
20
26
  toggleMobileTopic: (visible?: boolean) => void;
21
27
  toggleSystemRole: (visible?: boolean) => void;
22
- updateGuideState: (guide: Partial<Guide>) => void;
23
28
  updatePreference: (preference: Partial<GlobalPreference>, action?: any) => void;
24
- useInitPreference: () => SWRResponse;
29
+ useCheckLatestVersion: () => SWRResponse<string>;
30
+ useInitGlobalPreference: () => SWRResponse;
25
31
  }
26
32
 
27
- export const createPreferenceSlice: StateCreator<
33
+ export const globalActionSlice: StateCreator<
28
34
  GlobalStore,
29
35
  [['zustand/devtools', never]],
30
36
  [],
31
- PreferenceAction
37
+ GlobalStoreAction
32
38
  > = (set, get) => ({
39
+ switchBackToChat: (sessionId) => {
40
+ get().router?.push(SESSION_CHAT_URL(sessionId || INBOX_SESSION_ID, get().isMobile));
41
+ },
33
42
  toggleChatSideBar: (newValue) => {
34
43
  const showChatSideBar =
35
44
  typeof newValue === 'boolean' ? newValue : !get().preference.showChatSideBar;
@@ -38,7 +47,7 @@ export const createPreferenceSlice: StateCreator<
38
47
  },
39
48
  toggleExpandSessionGroup: (id, expand) => {
40
49
  const { preference } = get();
41
- const nextExpandSessionGroup = produce(preference.expandSessionGroupKeys, (draft) => {
50
+ const nextExpandSessionGroup = produce(preference.expandSessionGroupKeys, (draft: string[]) => {
42
51
  if (expand) {
43
52
  if (draft.includes(id)) return;
44
53
  draft.push(id);
@@ -61,11 +70,6 @@ export const createPreferenceSlice: StateCreator<
61
70
 
62
71
  get().updatePreference({ showSystemRole }, n('toggleMobileTopic', newValue));
63
72
  },
64
- updateGuideState: (guide) => {
65
- const { updatePreference } = get();
66
- const nextGuide = merge(get().preference.guide, guide);
67
- updatePreference({ guide: nextGuide });
68
- },
69
73
  updatePreference: (preference, action) => {
70
74
  const nextPreference = merge(get().preference, preference);
71
75
 
@@ -74,9 +78,19 @@ export const createPreferenceSlice: StateCreator<
74
78
  get().preferenceStorage.saveToLocalStorage(nextPreference);
75
79
  },
76
80
 
77
- useInitPreference: () =>
81
+ useCheckLatestVersion: () =>
82
+ useSWR('checkLatestVersion', globalService.getLatestVersion, {
83
+ // check latest version every 30 minutes
84
+ focusThrottleInterval: 1000 * 60 * 30,
85
+ onSuccess: (data: string) => {
86
+ if (gt(data, CURRENT_VERSION))
87
+ set({ hasNewVersion: true, latestVersion: data }, false, n('checkLatestVersion'));
88
+ },
89
+ }),
90
+
91
+ useInitGlobalPreference: () =>
78
92
  useClientDataSWR<GlobalPreference>(
79
- 'preference',
93
+ 'initGlobalPreference',
80
94
  () => get().preferenceStorage.getFromLocalStorage(),
81
95
  {
82
96
  onSuccess: (preference) => {
@@ -1,13 +1,63 @@
1
- import { GlobalCommonState, initialCommonState } from './slices/common/initialState';
2
- import { GlobalPreferenceState, initialPreferenceState } from './slices/preference/initialState';
3
- import { GlobalSettingsState, initialSettingsState } from './slices/settings/initialState';
1
+ import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime';
4
2
 
5
- export { SettingsTabs, SidebarTabKey } from './slices/common/initialState';
3
+ import { SessionDefaultGroup } from '@/types/session';
4
+ import { AsyncLocalStorage } from '@/utils/localStorage';
6
5
 
7
- export type GlobalState = GlobalCommonState & GlobalSettingsState & GlobalPreferenceState;
6
+ export enum SidebarTabKey {
7
+ Chat = 'chat',
8
+ Market = 'market',
9
+ Setting = 'settings',
10
+ }
11
+
12
+ export enum SettingsTabs {
13
+ About = 'about',
14
+ Agent = 'agent',
15
+ Common = 'common',
16
+ LLM = 'llm',
17
+ Sync = 'sync',
18
+ TTS = 'tts',
19
+ }
20
+
21
+ export interface GlobalPreference {
22
+ // which sessionGroup should expand
23
+ expandSessionGroupKeys: string[];
24
+ inputHeight: number;
25
+ mobileShowTopic?: boolean;
26
+ sessionsWidth: number;
27
+ showChatSideBar?: boolean;
28
+ showSessionPanel?: boolean;
29
+ showSystemRole?: boolean;
30
+ }
31
+
32
+ export interface GlobalPreferenceState {
33
+ /**
34
+ * the user preference, which only store in local storage
35
+ */
36
+ preference: GlobalPreference;
37
+ preferenceStorage: AsyncLocalStorage<GlobalPreference>;
38
+ }
39
+
40
+ export interface GlobalCommonState {
41
+ hasNewVersion?: boolean;
42
+ isMobile?: boolean;
43
+ latestVersion?: string;
44
+ router?: AppRouterInstance;
45
+ sidebarKey: SidebarTabKey;
46
+ }
47
+
48
+ export type GlobalState = GlobalCommonState & GlobalPreferenceState;
8
49
 
9
50
  export const initialState: GlobalState = {
10
- ...initialCommonState,
11
- ...initialSettingsState,
12
- ...initialPreferenceState,
51
+ isMobile: false,
52
+ preference: {
53
+ expandSessionGroupKeys: [SessionDefaultGroup.Pinned, SessionDefaultGroup.Default],
54
+ inputHeight: 200,
55
+ mobileShowTopic: false,
56
+ sessionsWidth: 320,
57
+ showChatSideBar: true,
58
+ showSessionPanel: true,
59
+ showSystemRole: false,
60
+ },
61
+ preferenceStorage: new AsyncLocalStorage('LOBE_GLOBAL_PREFERENCE'),
62
+ sidebarKey: SidebarTabKey.Chat,
13
63
  };
@@ -1,8 +1,9 @@
1
- export { commonSelectors } from './slices/common/selectors';
2
- export { preferenceSelectors } from './slices/preference/selectors';
3
- export {
4
- modelConfigSelectors,
5
- modelProviderSelectors,
6
- settingsSelectors,
7
- syncSettingsSelectors,
8
- } from './slices/settings/selectors';
1
+ import { GlobalStore } from '@/store/global';
2
+ import { SessionDefaultGroup } from '@/types/session';
3
+
4
+ const sessionGroupKeys = (s: GlobalStore): string[] =>
5
+ s.preference.expandSessionGroupKeys || [SessionDefaultGroup.Pinned, SessionDefaultGroup.Default];
6
+
7
+ export const preferenceSelectors = {
8
+ sessionGroupKeys,
9
+ };
@@ -5,20 +5,16 @@ import { StateCreator } from 'zustand/vanilla';
5
5
 
6
6
  import { isDev } from '@/utils/env';
7
7
 
8
+ import { type GlobalStoreAction, globalActionSlice } from './action';
8
9
  import { type GlobalState, initialState } from './initialState';
9
- import { type CommonAction, createCommonSlice } from './slices/common/action';
10
- import { type PreferenceAction, createPreferenceSlice } from './slices/preference/action';
11
- import { type SettingsAction, createSettingsSlice } from './slices/settings/actions';
12
10
 
13
11
  // =============== 聚合 createStoreFn ============ //
14
12
 
15
- export type GlobalStore = CommonAction & GlobalState & SettingsAction & PreferenceAction;
13
+ export type GlobalStore = GlobalState & GlobalStoreAction;
16
14
 
17
15
  const createStore: StateCreator<GlobalStore, [['zustand/devtools', never]]> = (...parameters) => ({
18
16
  ...initialState,
19
- ...createCommonSlice(...parameters),
20
- ...createSettingsSlice(...parameters),
21
- ...createPreferenceSlice(...parameters),
17
+ ...globalActionSlice(...parameters),
22
18
  });
23
19
 
24
20
  // =============== 实装 useStore ============ //
@@ -4,7 +4,7 @@ import useSWR, { SWRResponse } from 'swr';
4
4
  import type { StateCreator } from 'zustand/vanilla';
5
5
 
6
6
  import { marketService } from '@/services/market';
7
- import { globalHelpers } from '@/store/global/helpers';
7
+ import { globalHelpers } from '@/store/user/helpers';
8
8
  import { AgentsMarketItem, LobeChatAgentsMarketIndex } from '@/types/market';
9
9
 
10
10
  import type { Store } from './store';
@@ -8,9 +8,9 @@ import { message } from '@/components/AntdStaticMethods';
8
8
  import { DEFAULT_AGENT_LOBE_SESSION, INBOX_SESSION_ID } from '@/const/session';
9
9
  import { useClientDataSWR } from '@/libs/swr';
10
10
  import { sessionService } from '@/services/session';
11
- import { useGlobalStore } from '@/store/global';
12
- import { settingsSelectors } from '@/store/global/selectors';
13
11
  import { SessionStore } from '@/store/session';
12
+ import { useUserStore } from '@/store/user';
13
+ import { settingsSelectors } from '@/store/user/selectors';
14
14
  import { MetaData } from '@/types/meta';
15
15
  import {
16
16
  ChatSessionList,
@@ -111,7 +111,7 @@ export const createSessionSlice: StateCreator<
111
111
  // merge the defaultAgent in settings
112
112
  const defaultAgent = merge(
113
113
  DEFAULT_AGENT_LOBE_SESSION,
114
- settingsSelectors.defaultAgent(useGlobalStore.getState()),
114
+ settingsSelectors.defaultAgent(useUserStore.getState()),
115
115
  );
116
116
 
117
117
  const newSession: LobeAgentSession = merge(defaultAgent, agent);
@@ -1,7 +1,7 @@
1
1
  import { settingsSelectors } from './slices/settings/selectors';
2
- import { useGlobalStore } from './store';
2
+ import { useUserStore } from './store';
3
3
 
4
- const getCurrentLanguage = () => settingsSelectors.currentLanguage(useGlobalStore.getState());
4
+ const getCurrentLanguage = () => settingsSelectors.currentLanguage(useUserStore.getState());
5
5
 
6
6
  export const globalHelpers = {
7
7
  getCurrentLanguage,
@@ -0,0 +1 @@
1
+ export * from './store';
@@ -0,0 +1,11 @@
1
+ import { UserCommonState, initialCommonState } from './slices/common/initialState';
2
+ import { UserPreferenceState, initialPreferenceState } from './slices/preference/initialState';
3
+ import { UserSettingsState, initialSettingsState } from './slices/settings/initialState';
4
+
5
+ export type UserState = UserCommonState & UserSettingsState & UserPreferenceState;
6
+
7
+ export const initialState: UserState = {
8
+ ...initialCommonState,
9
+ ...initialSettingsState,
10
+ ...initialPreferenceState,
11
+ };
@@ -0,0 +1,8 @@
1
+ export { commonSelectors } from './slices/common/selectors';
2
+ export { preferenceSelectors } from './slices/preference/selectors';
3
+ export {
4
+ modelConfigSelectors,
5
+ modelProviderSelectors,
6
+ settingsSelectors,
7
+ syncSettingsSelectors,
8
+ } from './slices/settings/selectors';