@lobehub/chat 0.161.21 → 0.161.23

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 (111) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/package.json +1 -1
  3. package/src/app/(main)/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx +3 -3
  4. package/src/app/(main)/settings/common/features/Common.tsx +1 -1
  5. package/src/app/(main)/settings/common/features/Theme/ThemeSwatches/ThemeSwatchesNeutral.tsx +5 -5
  6. package/src/app/(main)/settings/common/features/Theme/ThemeSwatches/ThemeSwatchesPrimary.tsx +5 -5
  7. package/src/app/(main)/settings/common/features/Theme/index.tsx +5 -4
  8. package/src/app/(main)/settings/llm/Azure/index.tsx +4 -4
  9. package/src/app/(main)/settings/llm/Bedrock/index.tsx +5 -5
  10. package/src/app/(main)/settings/llm/Ollama/Checker.tsx +1 -1
  11. package/src/app/(main)/settings/llm/components/Checker.tsx +10 -6
  12. package/src/app/(main)/settings/llm/components/ProviderConfig/index.tsx +6 -5
  13. package/src/app/(main)/settings/llm/components/ProviderModelList/CustomModelOption.tsx +1 -1
  14. package/src/app/(main)/settings/llm/components/ProviderModelList/ModelFetcher.tsx +1 -1
  15. package/src/app/(main)/settings/llm/components/ProviderModelList/Option.tsx +1 -1
  16. package/src/app/(main)/settings/llm/components/ProviderModelList/index.tsx +1 -1
  17. package/src/app/(main)/settings/llm/const.ts +2 -1
  18. package/src/const/settings/agent.ts +2 -2
  19. package/src/const/settings/common.ts +2 -2
  20. package/src/const/settings/index.ts +4 -3
  21. package/src/const/settings/llm.ts +2 -21
  22. package/src/const/settings/sync.ts +2 -2
  23. package/src/const/settings/systemAgent.ts +2 -2
  24. package/src/const/settings/tts.ts +2 -2
  25. package/src/database/client/core/db.ts +19 -0
  26. package/src/database/client/core/migrations/migrateSettingsToUser/type.ts +1 -1
  27. package/src/database/client/core/schemas.ts +3 -2
  28. package/src/database/client/models/__tests__/user.test.ts +5 -5
  29. package/src/database/client/models/user.ts +2 -3
  30. package/src/database/client/schemas/user.ts +10 -4
  31. package/src/features/AgentSetting/AgentMeta/index.tsx +3 -3
  32. package/src/features/AgentSetting/AgentTTS/index.tsx +2 -2
  33. package/src/features/ChatInput/STT/browser.tsx +2 -2
  34. package/src/features/ChatInput/STT/openai.tsx +2 -2
  35. package/src/features/Conversation/Error/APIKeyForm/Bedrock.tsx +5 -5
  36. package/src/features/Conversation/Error/APIKeyForm/ProviderApiKeyForm.tsx +5 -5
  37. package/src/features/Conversation/Error/APIKeyForm/index.tsx +1 -1
  38. package/src/features/Conversation/Error/AccessCodeForm.tsx +4 -4
  39. package/src/features/Conversation/Extras/TTS/index.tsx +2 -2
  40. package/src/features/Conversation/Plugins/Render/MarkdownType/index.tsx +2 -2
  41. package/src/features/Conversation/components/BubblesLoading.tsx +49 -41
  42. package/src/features/Conversation/components/ChatItem/index.tsx +2 -2
  43. package/src/features/PluginDevModal/LocalForm.tsx +2 -2
  44. package/src/features/PluginStore/index.tsx +6 -2
  45. package/src/features/User/UserPanel/LangButton.tsx +2 -2
  46. package/src/features/User/UserPanel/ThemeButton.tsx +2 -2
  47. package/src/hooks/_header.ts +6 -3
  48. package/src/hooks/useTTS.ts +2 -2
  49. package/src/layout/GlobalProvider/AppTheme.tsx +4 -4
  50. package/src/libs/agent-runtime/types/type.ts +3 -2
  51. package/src/migrations/FromV6ToV7/fixtures/output-v7-from-v1.json +203 -0
  52. package/src/migrations/FromV6ToV7/fixtures/provider-input-v6.json +103 -0
  53. package/src/migrations/FromV6ToV7/fixtures/provider-output-v7.json +118 -0
  54. package/src/migrations/FromV6ToV7/index.ts +101 -0
  55. package/src/migrations/FromV6ToV7/migrations.test.ts +64 -0
  56. package/src/migrations/FromV6ToV7/types/v6.ts +61 -0
  57. package/src/migrations/FromV6ToV7/types/v7.ts +71 -0
  58. package/src/migrations/index.ts +9 -3
  59. package/src/services/__tests__/chat.test.ts +19 -19
  60. package/src/services/__tests__/share.test.ts +4 -4
  61. package/src/services/_auth.test.ts +10 -5
  62. package/src/services/_auth.ts +11 -7
  63. package/src/services/_header.ts +6 -3
  64. package/src/services/config.ts +2 -2
  65. package/src/services/ollama.ts +3 -3
  66. package/src/services/share.ts +3 -3
  67. package/src/services/user/client.test.ts +3 -3
  68. package/src/services/user/client.ts +3 -3
  69. package/src/services/user/type.ts +2 -2
  70. package/src/store/agent/store.ts +4 -9
  71. package/src/store/chat/store.ts +4 -8
  72. package/src/store/file/store.ts +3 -9
  73. package/src/store/global/store.ts +5 -8
  74. package/src/store/market/store.ts +5 -8
  75. package/src/store/middleware/createDevtools.ts +23 -0
  76. package/src/store/serverConfig/store.ts +5 -11
  77. package/src/store/session/store.ts +3 -1
  78. package/src/store/tool/store.ts +4 -9
  79. package/src/store/user/helpers.ts +3 -2
  80. package/src/store/user/selectors.ts +10 -2
  81. package/src/store/user/slices/common/action.test.ts +3 -3
  82. package/src/store/user/slices/common/action.ts +4 -4
  83. package/src/store/user/slices/modelList/action.test.ts +2 -2
  84. package/src/store/user/slices/modelList/action.ts +16 -4
  85. package/src/store/user/slices/modelList/selectors/index.ts +1 -0
  86. package/src/store/user/slices/modelList/selectors/keyVaults.ts +25 -0
  87. package/src/store/user/slices/modelList/selectors/modelConfig.test.ts +1 -1
  88. package/src/store/user/slices/modelList/selectors/modelConfig.ts +1 -6
  89. package/src/store/user/slices/modelList/selectors/modelProvider.ts +1 -1
  90. package/src/store/user/slices/settings/action.test.ts +16 -14
  91. package/src/store/user/slices/settings/action.ts +14 -8
  92. package/src/store/user/slices/settings/initialState.ts +3 -3
  93. package/src/store/user/slices/settings/selectors/general.test.ts +45 -0
  94. package/src/store/user/slices/settings/selectors/general.ts +40 -0
  95. package/src/store/user/slices/settings/selectors/index.ts +1 -0
  96. package/src/store/user/slices/settings/selectors/settings.test.ts +0 -39
  97. package/src/store/user/slices/settings/selectors/settings.ts +11 -34
  98. package/src/store/user/store.ts +5 -8
  99. package/src/types/exportConfig.ts +2 -2
  100. package/src/types/serverConfig.ts +2 -2
  101. package/src/types/user/index.ts +2 -2
  102. package/src/types/{settings/base.ts → user/settings/general.ts} +4 -1
  103. package/src/types/user/settings/index.ts +32 -0
  104. package/src/types/user/settings/keyVaults.ts +36 -0
  105. package/src/types/user/settings/modelProvider.ts +34 -0
  106. package/src/types/{settings → user/settings}/sync.ts +1 -1
  107. package/src/types/{settings → user/settings}/systemAgent.ts +1 -1
  108. package/src/types/user/settings/tool.ts +5 -0
  109. package/src/types/{settings → user/settings}/tts.ts +1 -1
  110. package/src/types/settings/index.ts +0 -33
  111. package/src/types/settings/modelProvider.ts +0 -62
@@ -0,0 +1,71 @@
1
+
2
+
3
+ interface OpenAICompatibleKeyVault {
4
+ apiKey?: string;
5
+ baseURL?: string;
6
+ }
7
+ interface AzureOpenAIKeyVault {
8
+ apiKey?: string;
9
+ apiVersion?: string;
10
+ endpoint?: string;
11
+ }
12
+
13
+ export interface AWSBedrockKeyVault {
14
+ accessKeyId?: string;
15
+ region?: string;
16
+ secretAccessKey?: string;
17
+ }
18
+
19
+ export interface V7KeyVaults {
20
+ anthropic: OpenAICompatibleKeyVault;
21
+ azure: AzureOpenAIKeyVault;
22
+ bedrock: AWSBedrockKeyVault;
23
+ deepseek: OpenAICompatibleKeyVault;
24
+ google: OpenAICompatibleKeyVault;
25
+ groq: OpenAICompatibleKeyVault;
26
+ minimax: OpenAICompatibleKeyVault;
27
+ mistral: OpenAICompatibleKeyVault;
28
+ moonshot: OpenAICompatibleKeyVault;
29
+ ollama: OpenAICompatibleKeyVault;
30
+ openai: OpenAICompatibleKeyVault;
31
+ openrouter: OpenAICompatibleKeyVault;
32
+ password: string;
33
+ perplexity: OpenAICompatibleKeyVault;
34
+ togetherai: OpenAICompatibleKeyVault;
35
+ zeroone: OpenAICompatibleKeyVault;
36
+ zhipu: OpenAICompatibleKeyVault;
37
+ }
38
+
39
+ interface V7ProviderConfig {
40
+ autoFetchModelLists?: boolean;
41
+ customModelCards?: any[];
42
+ enabled: boolean;
43
+ enabledModels?: string[] | null;
44
+ fetchOnClient?: boolean;
45
+ latestFetchTime?: number;
46
+ remoteModelCards?: any[];
47
+ }
48
+
49
+ export type V7ModelProviderConfig = Record<string, V7ProviderConfig>;
50
+
51
+ export interface V7GeneralSettings {
52
+ fontSize: number;
53
+ language: string;
54
+ neutralColor?: string;
55
+ primaryColor?: string;
56
+ themeMode: string;
57
+ }
58
+
59
+ export interface V7Settings {
60
+ defaultAgent: any;
61
+ general: V7GeneralSettings;
62
+ keyVaults: V7KeyVaults;
63
+ languageModel?: V7ModelProviderConfig;
64
+ sync: any;
65
+ tool: any;
66
+ tts: any;
67
+ }
68
+
69
+ export interface V7ConfigState {
70
+ settings?: V7Settings;
71
+ }
@@ -7,18 +7,24 @@ import { MigrationV1ToV2 } from './FromV1ToV2';
7
7
  import { MigrationV3ToV4 } from './FromV3ToV4';
8
8
  import { MigrationV4ToV5 } from './FromV4ToV5';
9
9
  import { MigrationV5ToV6 } from './FromV5ToV6';
10
+ import { MigrationV6ToV7 } from './FromV6ToV7';
10
11
 
11
12
  // Current latest version
12
- export const CURRENT_CONFIG_VERSION = 6;
13
+ export const CURRENT_CONFIG_VERSION = 7;
13
14
 
14
15
  // Version migrations module
15
16
  const ConfigMigrations = [
17
+ /**
18
+ * 2024.05.27
19
+ *
20
+ * apiKey in languageModel change to keyVaults
21
+ */
22
+ MigrationV6ToV7,
16
23
  /**
17
24
  * 2024.05.24
18
25
  *
19
26
  * some config in agentConfig change to chatConfig
20
- */
21
- MigrationV5ToV6,
27
+ */ MigrationV5ToV6,
22
28
  /**
23
29
  * 2024.05.11
24
30
  *
@@ -676,10 +676,10 @@ describe('AgentRuntimeOnClient', () => {
676
676
  // Mock the global store to return the user's OpenAI API key and endpoint
677
677
  merge(initialSettingsState, {
678
678
  settings: {
679
- languageModel: {
679
+ keyVaults: {
680
680
  openai: {
681
681
  apiKey: 'user-openai-key',
682
- endpoint: 'user-openai-endpoint',
682
+ baseURL: 'user-openai-endpoint',
683
683
  },
684
684
  },
685
685
  },
@@ -693,7 +693,7 @@ describe('AgentRuntimeOnClient', () => {
693
693
  it('Azure provider: with apiKey, apiVersion, endpoint', async () => {
694
694
  merge(initialSettingsState, {
695
695
  settings: {
696
- languageModel: {
696
+ keyVaults: {
697
697
  azure: {
698
698
  apiKey: 'user-azure-key',
699
699
  endpoint: 'user-azure-endpoint',
@@ -710,7 +710,7 @@ describe('AgentRuntimeOnClient', () => {
710
710
  it('Google provider: with apiKey', async () => {
711
711
  merge(initialSettingsState, {
712
712
  settings: {
713
- languageModel: {
713
+ keyVaults: {
714
714
  google: {
715
715
  apiKey: 'user-google-key',
716
716
  },
@@ -725,7 +725,7 @@ describe('AgentRuntimeOnClient', () => {
725
725
  it('Moonshot AI provider: with apiKey', async () => {
726
726
  merge(initialSettingsState, {
727
727
  settings: {
728
- languageModel: {
728
+ keyVaults: {
729
729
  moonshot: {
730
730
  apiKey: 'user-moonshot-key',
731
731
  },
@@ -740,7 +740,7 @@ describe('AgentRuntimeOnClient', () => {
740
740
  it('Bedrock provider: with accessKeyId, region, secretAccessKey', async () => {
741
741
  merge(initialSettingsState, {
742
742
  settings: {
743
- languageModel: {
743
+ keyVaults: {
744
744
  bedrock: {
745
745
  accessKeyId: 'user-bedrock-access-key',
746
746
  region: 'user-bedrock-region',
@@ -757,9 +757,9 @@ describe('AgentRuntimeOnClient', () => {
757
757
  it('Ollama provider: with endpoint', async () => {
758
758
  merge(initialSettingsState, {
759
759
  settings: {
760
- languageModel: {
760
+ keyVaults: {
761
761
  ollama: {
762
- endpoint: 'http://127.0.0.1:1234',
762
+ baseURL: 'http://127.0.0.1:1234',
763
763
  },
764
764
  },
765
765
  },
@@ -772,7 +772,7 @@ describe('AgentRuntimeOnClient', () => {
772
772
  it('Perplexity provider: with apiKey', async () => {
773
773
  merge(initialSettingsState, {
774
774
  settings: {
775
- languageModel: {
775
+ keyVaults: {
776
776
  perplexity: {
777
777
  apiKey: 'user-perplexity-key',
778
778
  },
@@ -787,7 +787,7 @@ describe('AgentRuntimeOnClient', () => {
787
787
  it('Anthropic provider: with apiKey', async () => {
788
788
  merge(initialSettingsState, {
789
789
  settings: {
790
- languageModel: {
790
+ keyVaults: {
791
791
  anthropic: {
792
792
  apiKey: 'user-anthropic-key',
793
793
  },
@@ -802,7 +802,7 @@ describe('AgentRuntimeOnClient', () => {
802
802
  it('Mistral provider: with apiKey', async () => {
803
803
  merge(initialSettingsState, {
804
804
  settings: {
805
- languageModel: {
805
+ keyVaults: {
806
806
  mistral: {
807
807
  apiKey: 'user-mistral-key',
808
808
  },
@@ -817,7 +817,7 @@ describe('AgentRuntimeOnClient', () => {
817
817
  it('OpenRouter provider: with apiKey', async () => {
818
818
  merge(initialSettingsState, {
819
819
  settings: {
820
- languageModel: {
820
+ keyVaults: {
821
821
  openrouter: {
822
822
  apiKey: 'user-openrouter-key',
823
823
  },
@@ -832,7 +832,7 @@ describe('AgentRuntimeOnClient', () => {
832
832
  it('TogetherAI provider: with apiKey', async () => {
833
833
  merge(initialSettingsState, {
834
834
  settings: {
835
- languageModel: {
835
+ keyVaults: {
836
836
  togetherai: {
837
837
  apiKey: 'user-togetherai-key',
838
838
  },
@@ -847,7 +847,7 @@ describe('AgentRuntimeOnClient', () => {
847
847
  it('ZeroOneAI provider: with apiKey', async () => {
848
848
  merge(initialSettingsState, {
849
849
  settings: {
850
- languageModel: {
850
+ keyVaults: {
851
851
  zeroone: {
852
852
  apiKey: 'user-zeroone-key',
853
853
  },
@@ -862,7 +862,7 @@ describe('AgentRuntimeOnClient', () => {
862
862
  it('Groq provider: with apiKey', async () => {
863
863
  merge(initialSettingsState, {
864
864
  settings: {
865
- languageModel: {
865
+ keyVaults: {
866
866
  groq: {
867
867
  apiKey: 'user-groq-key',
868
868
  },
@@ -877,7 +877,7 @@ describe('AgentRuntimeOnClient', () => {
877
877
  it('DeepSeek provider: with apiKey', async () => {
878
878
  merge(initialSettingsState, {
879
879
  settings: {
880
- languageModel: {
880
+ keyVaults: {
881
881
  deepseek: {
882
882
  apiKey: 'user-deepseek-key',
883
883
  },
@@ -888,7 +888,7 @@ describe('AgentRuntimeOnClient', () => {
888
888
  expect(runtime).toBeInstanceOf(AgentRuntime);
889
889
  expect(runtime['_runtime']).toBeInstanceOf(LobeDeepSeekAI);
890
890
  });
891
-
891
+
892
892
  /**
893
893
  * Should not have a unknown provider in client, but has
894
894
  * similar cases in server side
@@ -896,7 +896,7 @@ describe('AgentRuntimeOnClient', () => {
896
896
  it('Unknown provider: with apiKey', async () => {
897
897
  merge(initialSettingsState, {
898
898
  settings: {
899
- languageModel: {
899
+ keyVaults: {
900
900
  unknown: {
901
901
  apiKey: 'user-unknown-key',
902
902
  endpoint: 'user-unknown-endpoint',
@@ -924,7 +924,7 @@ describe('AgentRuntimeOnClient', () => {
924
924
  }));
925
925
  merge(initialSettingsState, {
926
926
  settings: {
927
- languageModel: {
927
+ keyVaults: {
928
928
  zhipu: {
929
929
  apiKey: 'zhipu.user-key',
930
930
  },
@@ -2,8 +2,8 @@ import { DeepPartial } from 'utility-types';
2
2
  import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
3
 
4
4
  import { LOBE_URL_IMPORT_NAME } from '@/const/url';
5
- import { GlobalSettings } from '@/types/settings';
6
5
  import { ShareGPTConversation } from '@/types/share';
6
+ import { UserSettings } from '@/types/user/settings';
7
7
  import { parseMarkdown } from '@/utils/parseMarkdown';
8
8
 
9
9
  import { SHARE_GPT_URL, shareService } from '../share';
@@ -91,8 +91,8 @@ describe('ShareGPTService', () => {
91
91
  describe('ShareViaUrl', () => {
92
92
  describe('createShareSettingsUrl', () => {
93
93
  it('should create a share settings URL with the provided settings', () => {
94
- const settings: DeepPartial<GlobalSettings> = {
95
- languageModel: {
94
+ const settings: DeepPartial<UserSettings> = {
95
+ keyVaults: {
96
96
  openai: {
97
97
  apiKey: 'user-key',
98
98
  },
@@ -100,7 +100,7 @@ describe('ShareViaUrl', () => {
100
100
  };
101
101
  const url = shareService.createShareSettingsUrl(settings);
102
102
  expect(url).toBe(
103
- `/?${LOBE_URL_IMPORT_NAME}=%7B%22languageModel%22:%7B%22openai%22:%7B%22apiKey%22:%22user-key%22%7D%7D%7D`,
103
+ `/?${LOBE_URL_IMPORT_NAME}=%7B%22keyVaults%22:%7B%22openai%22:%7B%22apiKey%22:%22user-key%22%7D%7D%7D`,
104
104
  );
105
105
  });
106
106
  });
@@ -3,7 +3,11 @@ import { describe, expect, it, vi } from 'vitest';
3
3
 
4
4
  import { ModelProvider } from '@/libs/agent-runtime';
5
5
  import { useUserStore } from '@/store/user';
6
- import { GlobalLLMConfig, GlobalLLMProviderKey } from '@/types/settings';
6
+ import {
7
+ GlobalLLMProviderKey,
8
+ UserKeyVaults,
9
+ UserModelProviderConfig,
10
+ } from '@/types/user/settings';
7
11
 
8
12
  import { getProviderAuthPayload } from './_auth';
9
13
 
@@ -21,10 +25,10 @@ vi.mock('zustand/traditional');
21
25
 
22
26
  const setModelProviderConfig = <T extends GlobalLLMProviderKey>(
23
27
  provider: T,
24
- config: Partial<GlobalLLMConfig[T]>,
28
+ config: Partial<UserKeyVaults[T]>,
25
29
  ) => {
26
30
  useUserStore.setState({
27
- settings: { languageModel: { [provider]: config } },
31
+ settings: { keyVaults: { [provider]: config } },
28
32
  });
29
33
  };
30
34
 
@@ -135,7 +139,7 @@ describe('getProviderAuthPayload', () => {
135
139
  // 假设的 Ollama 配置
136
140
  const mockOllamaProxyUrl = 'ollama-proxy-url';
137
141
  act(() => {
138
- setModelProviderConfig('ollama', { endpoint: mockOllamaProxyUrl });
142
+ setModelProviderConfig('ollama', { baseURL: mockOllamaProxyUrl });
139
143
  });
140
144
 
141
145
  const payload = getProviderAuthPayload(ModelProvider.Ollama);
@@ -148,6 +152,7 @@ describe('getProviderAuthPayload', () => {
148
152
  // 假设的 OpenAI 配置
149
153
  const mockOpenAIConfig = {
150
154
  apiKey: 'openai-api-key',
155
+ baseURL: 'openai-baseURL',
151
156
  endpoint: 'openai-endpoint',
152
157
  useAzure: true,
153
158
  azureApiVersion: 'openai-azure-api-version',
@@ -159,7 +164,7 @@ describe('getProviderAuthPayload', () => {
159
164
  const payload = getProviderAuthPayload(ModelProvider.OpenAI);
160
165
  expect(payload).toEqual({
161
166
  apiKey: mockOpenAIConfig.apiKey,
162
- endpoint: mockOpenAIConfig.endpoint,
167
+ endpoint: mockOpenAIConfig.baseURL,
163
168
  });
164
169
  });
165
170
 
@@ -1,15 +1,17 @@
1
1
  import { JWTPayload, LOBE_CHAT_AUTH_HEADER } from '@/const/auth';
2
2
  import { ModelProvider } from '@/libs/agent-runtime';
3
3
  import { useUserStore } from '@/store/user';
4
- import { modelConfigSelectors, settingsSelectors } from '@/store/user/selectors';
4
+ import { keyVaultsConfigSelectors, settingsSelectors } from '@/store/user/selectors';
5
+ import { GlobalLLMProviderKey } from '@/types/user/settings';
5
6
  import { createJWT } from '@/utils/jwt';
6
7
 
7
8
  export const getProviderAuthPayload = (provider: string) => {
8
9
  switch (provider) {
9
10
  case ModelProvider.Bedrock: {
10
- const { accessKeyId, region, secretAccessKey } = modelConfigSelectors.bedrockConfig(
11
+ const { accessKeyId, region, secretAccessKey } = keyVaultsConfigSelectors.bedrockConfig(
11
12
  useUserStore.getState(),
12
13
  );
14
+
13
15
  const awsSecretAccessKey = secretAccessKey;
14
16
  const awsAccessKeyId = accessKeyId;
15
17
 
@@ -19,7 +21,7 @@ export const getProviderAuthPayload = (provider: string) => {
19
21
  }
20
22
 
21
23
  case ModelProvider.Azure: {
22
- const azure = modelConfigSelectors.azureConfig(useUserStore.getState());
24
+ const azure = keyVaultsConfigSelectors.azureConfig(useUserStore.getState());
23
25
 
24
26
  return {
25
27
  apiKey: azure.apiKey,
@@ -29,15 +31,17 @@ export const getProviderAuthPayload = (provider: string) => {
29
31
  }
30
32
 
31
33
  case ModelProvider.Ollama: {
32
- const config = modelConfigSelectors.ollamaConfig(useUserStore.getState());
34
+ const config = keyVaultsConfigSelectors.ollamaConfig(useUserStore.getState());
33
35
 
34
- return { endpoint: config?.endpoint };
36
+ return { endpoint: config?.baseURL };
35
37
  }
36
38
 
37
39
  default: {
38
- const config = settingsSelectors.providerConfig(provider)(useUserStore.getState());
40
+ const config = keyVaultsConfigSelectors.getVaultByProvider(provider as GlobalLLMProviderKey)(
41
+ useUserStore.getState(),
42
+ );
39
43
 
40
- return { apiKey: config?.apiKey, endpoint: config?.endpoint };
44
+ return { apiKey: config?.apiKey, endpoint: config?.baseURL };
41
45
  }
42
46
  }
43
47
  };
@@ -1,6 +1,9 @@
1
1
  import { LOBE_CHAT_ACCESS_CODE, OPENAI_API_KEY_HEADER_KEY, OPENAI_END_POINT } from '@/const/fetch';
2
2
  import { useUserStore } from '@/store/user';
3
- import { modelConfigSelectors, settingsSelectors } from '@/store/user/selectors';
3
+ import {
4
+ keyVaultsConfigSelectors,
5
+ settingsSelectors,
6
+ } from '@/store/user/selectors';
4
7
 
5
8
  /**
6
9
  * TODO: Need to be removed after tts refactor
@@ -8,13 +11,13 @@ import { modelConfigSelectors, settingsSelectors } from '@/store/user/selectors'
8
11
  */
9
12
  // eslint-disable-next-line no-undef
10
13
  export const createHeaderWithOpenAI = (header?: HeadersInit): HeadersInit => {
11
- const openAIConfig = modelConfigSelectors.openAIConfig(useUserStore.getState());
14
+ const openAIConfig = keyVaultsConfigSelectors.openAIConfig(useUserStore.getState());
12
15
 
13
16
  // eslint-disable-next-line no-undef
14
17
  return {
15
18
  ...header,
16
19
  [LOBE_CHAT_ACCESS_CODE]: settingsSelectors.password(useUserStore.getState()),
17
20
  [OPENAI_API_KEY_HEADER_KEY]: openAIConfig.apiKey || '',
18
- [OPENAI_END_POINT]: openAIConfig.endpoint || '',
21
+ [OPENAI_END_POINT]: openAIConfig.baseURL || '',
19
22
  };
20
23
  };
@@ -8,8 +8,8 @@ import { settingsSelectors } from '@/store/user/selectors';
8
8
  import { ConfigFile } from '@/types/exportConfig';
9
9
  import { ChatMessage } from '@/types/message';
10
10
  import { LobeSessions, SessionGroupItem } from '@/types/session';
11
- import { GlobalSettings } from '@/types/settings';
12
11
  import { ChatTopic } from '@/types/topic';
12
+ import { UserSettings } from '@/types/user/settings';
13
13
  import { createConfigFile, exportConfigFile } from '@/utils/config';
14
14
 
15
15
  export interface ImportResult {
@@ -35,7 +35,7 @@ class ConfigService {
35
35
  importMessages = async (messages: ChatMessage[]) => {
36
36
  return messageService.batchCreateMessages(messages);
37
37
  };
38
- importSettings = async (settings: GlobalSettings) => {
38
+ importSettings = async (settings: UserSettings) => {
39
39
  useUserStore.getState().importAppSettings(settings);
40
40
  };
41
41
  importTopics = async (topics: ChatTopic[]) => {
@@ -3,7 +3,7 @@ import { ListResponse, Ollama as OllamaBrowser, ProgressResponse } from 'ollama/
3
3
  import { createErrorResponse } from '@/app/api/errorResponse';
4
4
  import { ModelProvider } from '@/libs/agent-runtime';
5
5
  import { useUserStore } from '@/store/user';
6
- import { modelConfigSelectors } from '@/store/user/selectors';
6
+ import { keyVaultsConfigSelectors } from '@/store/user/selectors';
7
7
  import { ChatErrorType } from '@/types/fetch';
8
8
  import { getMessageError } from '@/utils/fetch';
9
9
 
@@ -25,9 +25,9 @@ export class OllamaService {
25
25
  }
26
26
 
27
27
  getHost = (): string => {
28
- const config = modelConfigSelectors.ollamaConfig(useUserStore.getState());
28
+ const config = keyVaultsConfigSelectors.ollamaConfig(useUserStore.getState());
29
29
 
30
- return config.endpoint || DEFAULT_BASE_URL;
30
+ return config.baseURL || DEFAULT_BASE_URL;
31
31
  };
32
32
 
33
33
  getOllamaClient = () => {
@@ -1,8 +1,8 @@
1
1
  import { DeepPartial } from 'utility-types';
2
2
 
3
3
  import { LOBE_URL_IMPORT_NAME } from '@/const/url';
4
- import { GlobalSettings } from '@/types/settings';
5
4
  import { ShareGPTConversation } from '@/types/share';
5
+ import { UserSettings } from '@/types/user/settings';
6
6
  import { withBasePath } from '@/utils/basePath';
7
7
  import { parseMarkdown } from '@/utils/parseMarkdown';
8
8
 
@@ -40,7 +40,7 @@ class ShareService {
40
40
  * @param settings - The settings object to be encoded in the URL.
41
41
  * @returns The share settings URL.
42
42
  */
43
- public createShareSettingsUrl(settings: DeepPartial<GlobalSettings>) {
43
+ public createShareSettingsUrl(settings: DeepPartial<UserSettings>) {
44
44
  return withBasePath(`/?${LOBE_URL_IMPORT_NAME}=${encodeURI(JSON.stringify(settings))}`);
45
45
  }
46
46
 
@@ -51,7 +51,7 @@ class ShareService {
51
51
  */
52
52
  public decodeShareSettings(settings: string) {
53
53
  try {
54
- return { data: JSON.parse(settings) as DeepPartial<GlobalSettings> };
54
+ return { data: JSON.parse(settings) as DeepPartial<UserSettings> };
55
55
  } catch (e) {
56
56
  return { message: JSON.stringify(e) };
57
57
  }
@@ -2,8 +2,8 @@ import { DeepPartial } from 'utility-types';
2
2
  import { Mock, beforeEach, describe, expect, it, vi } from 'vitest';
3
3
 
4
4
  import { UserModel } from '@/database/client/models/user';
5
- import { GlobalSettings } from '@/types/settings';
6
5
  import { UserPreference } from '@/types/user';
6
+ import { UserSettings } from '@/types/user/settings';
7
7
  import { AsyncLocalStorage } from '@/utils/localStorage';
8
8
 
9
9
  import { ClientService } from './client';
@@ -19,7 +19,7 @@ vi.mock('@/database/client/models/user', () => ({
19
19
 
20
20
  const mockUser = {
21
21
  avatar: 'avatar.png',
22
- settings: { themeMode: 'light' } as unknown as GlobalSettings,
22
+ settings: { themeMode: 'light' } as unknown as UserSettings,
23
23
  uuid: 'user-id',
24
24
  };
25
25
 
@@ -58,7 +58,7 @@ describe('ClientService', () => {
58
58
  });
59
59
 
60
60
  it('should update user settings correctly', async () => {
61
- const settingsPatch: DeepPartial<GlobalSettings> = { themeMode: 'dark' };
61
+ const settingsPatch: DeepPartial<UserSettings> = { general: { themeMode: 'dark' } };
62
62
  (UserModel.updateSettings as Mock).mockResolvedValue(undefined);
63
63
 
64
64
  await clientService.updateUserSettings(settingsPatch);
@@ -3,8 +3,8 @@ import { DeepPartial } from 'utility-types';
3
3
  import { MessageModel } from '@/database/client/models/message';
4
4
  import { SessionModel } from '@/database/client/models/session';
5
5
  import { UserModel } from '@/database/client/models/user';
6
- import { GlobalSettings } from '@/types/settings';
7
6
  import { UserInitializationState, UserPreference } from '@/types/user';
7
+ import { UserSettings } from '@/types/user/settings';
8
8
  import { AsyncLocalStorage } from '@/utils/localStorage';
9
9
 
10
10
  import { IUserService } from './type';
@@ -28,12 +28,12 @@ export class ClientService implements IUserService {
28
28
  hasConversation: messageCount > 0 || sessionCount > 0,
29
29
  isOnboard: true,
30
30
  preference: await this.preferenceStorage.getFromLocalStorage(),
31
- settings: user.settings as GlobalSettings,
31
+ settings: user.settings as UserSettings,
32
32
  userId: user.uuid,
33
33
  };
34
34
  }
35
35
 
36
- updateUserSettings = async (patch: DeepPartial<GlobalSettings>) => {
36
+ updateUserSettings = async (patch: DeepPartial<UserSettings>) => {
37
37
  return UserModel.updateSettings(patch);
38
38
  };
39
39
 
@@ -1,11 +1,11 @@
1
1
  import { DeepPartial } from 'utility-types';
2
2
 
3
- import { GlobalSettings } from '@/types/settings';
4
3
  import { UserInitializationState, UserPreference } from '@/types/user';
4
+ import { UserSettings } from '@/types/user/settings';
5
5
 
6
6
  export interface IUserService {
7
7
  getUserState: () => Promise<UserInitializationState>;
8
8
  resetUserSettings: () => Promise<any>;
9
9
  updatePreference: (preference: UserPreference) => Promise<any>;
10
- updateUserSettings: (patch: DeepPartial<GlobalSettings>) => Promise<any>;
10
+ updateUserSettings: (patch: DeepPartial<UserSettings>) => Promise<any>;
11
11
  }
@@ -1,10 +1,8 @@
1
- import { devtools } from 'zustand/middleware';
2
1
  import { shallow } from 'zustand/shallow';
3
2
  import { createWithEqualityFn } from 'zustand/traditional';
4
3
  import { StateCreator } from 'zustand/vanilla';
5
4
 
6
- import { isDev } from '@/utils/env';
7
-
5
+ import { createDevtools } from '../middleware/createDevtools';
8
6
  import { SessionStoreState, initialState } from './initialState';
9
7
  import { AgentChatAction, createChatSlice } from './slices/chat/action';
10
8
 
@@ -19,9 +17,6 @@ const createStore: StateCreator<AgentStore, [['zustand/devtools', never]]> = (..
19
17
 
20
18
  // =============== implement useStore ============ //
21
19
 
22
- export const useAgentStore = createWithEqualityFn<AgentStore>()(
23
- devtools(createStore, {
24
- name: 'LobeChat_Agent' + (isDev ? '_DEV' : ''),
25
- }),
26
- shallow,
27
- );
20
+ const devtools = createDevtools('agent');
21
+
22
+ export const useAgentStore = createWithEqualityFn<AgentStore>()(devtools(createStore), shallow);
@@ -1,10 +1,9 @@
1
- import { devtools, subscribeWithSelector } from 'zustand/middleware';
1
+ import { subscribeWithSelector } from 'zustand/middleware';
2
2
  import { shallow } from 'zustand/shallow';
3
3
  import { createWithEqualityFn } from 'zustand/traditional';
4
4
  import { StateCreator } from 'zustand/vanilla';
5
5
 
6
- import { isDev } from '@/utils/env';
7
-
6
+ import { createDevtools } from '../middleware/createDevtools';
8
7
  import { ChatStoreState, initialState } from './initialState';
9
8
  import { ChatBuiltinToolAction, chatToolSlice } from './slices/builtinTool/action';
10
9
  import { ChatEnhanceAction, chatEnhance } from './slices/enchance/action';
@@ -37,12 +36,9 @@ const createStore: StateCreator<ChatStore, [['zustand/devtools', never]]> = (...
37
36
  });
38
37
 
39
38
  // =============== 实装 useStore ============ //
39
+ const devtools = createDevtools('chat');
40
40
 
41
41
  export const useChatStore = createWithEqualityFn<ChatStore>()(
42
- subscribeWithSelector(
43
- devtools(createStore, {
44
- name: 'LobeChat_Chat' + (isDev ? '_DEV' : ''),
45
- }),
46
- ),
42
+ subscribeWithSelector(devtools(createStore)),
47
43
  shallow,
48
44
  );
@@ -1,10 +1,8 @@
1
- import { devtools } from 'zustand/middleware';
2
1
  import { shallow } from 'zustand/shallow';
3
2
  import { createWithEqualityFn } from 'zustand/traditional';
4
3
  import { StateCreator } from 'zustand/vanilla';
5
4
 
6
- import { isDev } from '@/utils/env';
7
-
5
+ import { createDevtools } from '../middleware/createDevtools';
8
6
  import { FilesStoreState, initialState } from './initialState';
9
7
  import { FileAction, createFileSlice } from './slices/images';
10
8
  import { TTSFileAction, createTTSFileSlice } from './slices/tts';
@@ -20,10 +18,6 @@ const createStore: StateCreator<FileStore, [['zustand/devtools', never]]> = (...
20
18
  });
21
19
 
22
20
  // =============== 实装 useStore ============ //
21
+ const devtools = createDevtools('file');
23
22
 
24
- export const useFileStore = createWithEqualityFn<FileStore>()(
25
- devtools(createStore, {
26
- name: 'LobeChat_File' + (isDev ? '_DEV' : ''),
27
- }),
28
- shallow,
29
- );
23
+ export const useFileStore = createWithEqualityFn<FileStore>()(devtools(createStore), shallow);
@@ -1,10 +1,9 @@
1
- import { devtools, subscribeWithSelector } from 'zustand/middleware';
1
+ import { subscribeWithSelector } from 'zustand/middleware';
2
2
  import { shallow } from 'zustand/shallow';
3
3
  import { createWithEqualityFn } from 'zustand/traditional';
4
4
  import { StateCreator } from 'zustand/vanilla';
5
5
 
6
- import { isDev } from '@/utils/env';
7
-
6
+ import { createDevtools } from '../middleware/createDevtools';
8
7
  import { type GlobalStoreAction, globalActionSlice } from './action';
9
8
  import { type GlobalState, initialState } from './initialState';
10
9
 
@@ -19,11 +18,9 @@ const createStore: StateCreator<GlobalStore, [['zustand/devtools', never]]> = (.
19
18
 
20
19
  // =============== 实装 useStore ============ //
21
20
 
21
+ const devtools = createDevtools('global');
22
+
22
23
  export const useGlobalStore = createWithEqualityFn<GlobalStore>()(
23
- subscribeWithSelector(
24
- devtools(createStore, {
25
- name: 'LobeChat_Global' + (isDev ? '_DEV' : ''),
26
- }),
27
- ),
24
+ subscribeWithSelector(devtools(createStore)),
28
25
  shallow,
29
26
  );