@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.
- package/CHANGELOG.md +58 -0
- package/package.json +1 -1
- package/src/app/(main)/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx +3 -3
- package/src/app/(main)/settings/common/features/Common.tsx +1 -1
- package/src/app/(main)/settings/common/features/Theme/ThemeSwatches/ThemeSwatchesNeutral.tsx +5 -5
- package/src/app/(main)/settings/common/features/Theme/ThemeSwatches/ThemeSwatchesPrimary.tsx +5 -5
- package/src/app/(main)/settings/common/features/Theme/index.tsx +5 -4
- package/src/app/(main)/settings/llm/Azure/index.tsx +4 -4
- package/src/app/(main)/settings/llm/Bedrock/index.tsx +5 -5
- package/src/app/(main)/settings/llm/Ollama/Checker.tsx +1 -1
- package/src/app/(main)/settings/llm/components/Checker.tsx +10 -6
- package/src/app/(main)/settings/llm/components/ProviderConfig/index.tsx +6 -5
- package/src/app/(main)/settings/llm/components/ProviderModelList/CustomModelOption.tsx +1 -1
- package/src/app/(main)/settings/llm/components/ProviderModelList/ModelFetcher.tsx +1 -1
- package/src/app/(main)/settings/llm/components/ProviderModelList/Option.tsx +1 -1
- package/src/app/(main)/settings/llm/components/ProviderModelList/index.tsx +1 -1
- package/src/app/(main)/settings/llm/const.ts +2 -1
- package/src/const/settings/agent.ts +2 -2
- package/src/const/settings/common.ts +2 -2
- package/src/const/settings/index.ts +4 -3
- package/src/const/settings/llm.ts +2 -21
- package/src/const/settings/sync.ts +2 -2
- package/src/const/settings/systemAgent.ts +2 -2
- package/src/const/settings/tts.ts +2 -2
- package/src/database/client/core/db.ts +19 -0
- package/src/database/client/core/migrations/migrateSettingsToUser/type.ts +1 -1
- package/src/database/client/core/schemas.ts +3 -2
- package/src/database/client/models/__tests__/user.test.ts +5 -5
- package/src/database/client/models/user.ts +2 -3
- package/src/database/client/schemas/user.ts +10 -4
- package/src/features/AgentSetting/AgentMeta/index.tsx +3 -3
- package/src/features/AgentSetting/AgentTTS/index.tsx +2 -2
- package/src/features/ChatInput/STT/browser.tsx +2 -2
- package/src/features/ChatInput/STT/openai.tsx +2 -2
- package/src/features/Conversation/Error/APIKeyForm/Bedrock.tsx +5 -5
- package/src/features/Conversation/Error/APIKeyForm/ProviderApiKeyForm.tsx +5 -5
- package/src/features/Conversation/Error/APIKeyForm/index.tsx +1 -1
- package/src/features/Conversation/Error/AccessCodeForm.tsx +4 -4
- package/src/features/Conversation/Extras/TTS/index.tsx +2 -2
- package/src/features/Conversation/Plugins/Render/MarkdownType/index.tsx +2 -2
- package/src/features/Conversation/components/BubblesLoading.tsx +49 -41
- package/src/features/Conversation/components/ChatItem/index.tsx +2 -2
- package/src/features/PluginDevModal/LocalForm.tsx +2 -2
- package/src/features/PluginStore/index.tsx +6 -2
- package/src/features/User/UserPanel/LangButton.tsx +2 -2
- package/src/features/User/UserPanel/ThemeButton.tsx +2 -2
- package/src/hooks/_header.ts +6 -3
- package/src/hooks/useTTS.ts +2 -2
- package/src/layout/GlobalProvider/AppTheme.tsx +4 -4
- package/src/libs/agent-runtime/types/type.ts +3 -2
- package/src/migrations/FromV6ToV7/fixtures/output-v7-from-v1.json +203 -0
- package/src/migrations/FromV6ToV7/fixtures/provider-input-v6.json +103 -0
- package/src/migrations/FromV6ToV7/fixtures/provider-output-v7.json +118 -0
- package/src/migrations/FromV6ToV7/index.ts +101 -0
- package/src/migrations/FromV6ToV7/migrations.test.ts +64 -0
- package/src/migrations/FromV6ToV7/types/v6.ts +61 -0
- package/src/migrations/FromV6ToV7/types/v7.ts +71 -0
- package/src/migrations/index.ts +9 -3
- package/src/services/__tests__/chat.test.ts +19 -19
- package/src/services/__tests__/share.test.ts +4 -4
- package/src/services/_auth.test.ts +10 -5
- package/src/services/_auth.ts +11 -7
- package/src/services/_header.ts +6 -3
- package/src/services/config.ts +2 -2
- package/src/services/ollama.ts +3 -3
- package/src/services/share.ts +3 -3
- package/src/services/user/client.test.ts +3 -3
- package/src/services/user/client.ts +3 -3
- package/src/services/user/type.ts +2 -2
- package/src/store/agent/store.ts +4 -9
- package/src/store/chat/store.ts +4 -8
- package/src/store/file/store.ts +3 -9
- package/src/store/global/store.ts +5 -8
- package/src/store/market/store.ts +5 -8
- package/src/store/middleware/createDevtools.ts +23 -0
- package/src/store/serverConfig/store.ts +5 -11
- package/src/store/session/store.ts +3 -1
- package/src/store/tool/store.ts +4 -9
- package/src/store/user/helpers.ts +3 -2
- package/src/store/user/selectors.ts +10 -2
- package/src/store/user/slices/common/action.test.ts +3 -3
- package/src/store/user/slices/common/action.ts +4 -4
- package/src/store/user/slices/modelList/action.test.ts +2 -2
- package/src/store/user/slices/modelList/action.ts +16 -4
- package/src/store/user/slices/modelList/selectors/index.ts +1 -0
- package/src/store/user/slices/modelList/selectors/keyVaults.ts +25 -0
- package/src/store/user/slices/modelList/selectors/modelConfig.test.ts +1 -1
- package/src/store/user/slices/modelList/selectors/modelConfig.ts +1 -6
- package/src/store/user/slices/modelList/selectors/modelProvider.ts +1 -1
- package/src/store/user/slices/settings/action.test.ts +16 -14
- package/src/store/user/slices/settings/action.ts +14 -8
- package/src/store/user/slices/settings/initialState.ts +3 -3
- package/src/store/user/slices/settings/selectors/general.test.ts +45 -0
- package/src/store/user/slices/settings/selectors/general.ts +40 -0
- package/src/store/user/slices/settings/selectors/index.ts +1 -0
- package/src/store/user/slices/settings/selectors/settings.test.ts +0 -39
- package/src/store/user/slices/settings/selectors/settings.ts +11 -34
- package/src/store/user/store.ts +5 -8
- package/src/types/exportConfig.ts +2 -2
- package/src/types/serverConfig.ts +2 -2
- package/src/types/user/index.ts +2 -2
- package/src/types/{settings/base.ts → user/settings/general.ts} +4 -1
- package/src/types/user/settings/index.ts +32 -0
- package/src/types/user/settings/keyVaults.ts +36 -0
- package/src/types/user/settings/modelProvider.ts +34 -0
- package/src/types/{settings → user/settings}/sync.ts +1 -1
- package/src/types/{settings → user/settings}/systemAgent.ts +1 -1
- package/src/types/user/settings/tool.ts +5 -0
- package/src/types/{settings → user/settings}/tts.ts +1 -1
- package/src/types/settings/index.ts +0 -33
- 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
|
+
}
|
package/src/migrations/index.ts
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
679
|
+
keyVaults: {
|
|
680
680
|
openai: {
|
|
681
681
|
apiKey: 'user-openai-key',
|
|
682
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
760
|
+
keyVaults: {
|
|
761
761
|
ollama: {
|
|
762
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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<
|
|
95
|
-
|
|
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%
|
|
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 {
|
|
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<
|
|
28
|
+
config: Partial<UserKeyVaults[T]>,
|
|
25
29
|
) => {
|
|
26
30
|
useUserStore.setState({
|
|
27
|
-
settings: {
|
|
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', {
|
|
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.
|
|
167
|
+
endpoint: mockOpenAIConfig.baseURL,
|
|
163
168
|
});
|
|
164
169
|
});
|
|
165
170
|
|
package/src/services/_auth.ts
CHANGED
|
@@ -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 {
|
|
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 } =
|
|
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 =
|
|
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 =
|
|
34
|
+
const config = keyVaultsConfigSelectors.ollamaConfig(useUserStore.getState());
|
|
33
35
|
|
|
34
|
-
return { endpoint: config?.
|
|
36
|
+
return { endpoint: config?.baseURL };
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
default: {
|
|
38
|
-
const config =
|
|
40
|
+
const config = keyVaultsConfigSelectors.getVaultByProvider(provider as GlobalLLMProviderKey)(
|
|
41
|
+
useUserStore.getState(),
|
|
42
|
+
);
|
|
39
43
|
|
|
40
|
-
return { apiKey: config?.apiKey, endpoint: config?.
|
|
44
|
+
return { apiKey: config?.apiKey, endpoint: config?.baseURL };
|
|
41
45
|
}
|
|
42
46
|
}
|
|
43
47
|
};
|
package/src/services/_header.ts
CHANGED
|
@@ -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 {
|
|
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 =
|
|
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.
|
|
21
|
+
[OPENAI_END_POINT]: openAIConfig.baseURL || '',
|
|
19
22
|
};
|
|
20
23
|
};
|
package/src/services/config.ts
CHANGED
|
@@ -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:
|
|
38
|
+
importSettings = async (settings: UserSettings) => {
|
|
39
39
|
useUserStore.getState().importAppSettings(settings);
|
|
40
40
|
};
|
|
41
41
|
importTopics = async (topics: ChatTopic[]) => {
|
package/src/services/ollama.ts
CHANGED
|
@@ -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 {
|
|
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 =
|
|
28
|
+
const config = keyVaultsConfigSelectors.ollamaConfig(useUserStore.getState());
|
|
29
29
|
|
|
30
|
-
return config.
|
|
30
|
+
return config.baseURL || DEFAULT_BASE_URL;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
getOllamaClient = () => {
|
package/src/services/share.ts
CHANGED
|
@@ -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<
|
|
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<
|
|
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
|
|
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<
|
|
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
|
|
31
|
+
settings: user.settings as UserSettings,
|
|
32
32
|
userId: user.uuid,
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
updateUserSettings = async (patch: DeepPartial<
|
|
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<
|
|
10
|
+
updateUserSettings: (patch: DeepPartial<UserSettings>) => Promise<any>;
|
|
11
11
|
}
|
package/src/store/agent/store.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}),
|
|
26
|
-
shallow,
|
|
27
|
-
);
|
|
20
|
+
const devtools = createDevtools('agent');
|
|
21
|
+
|
|
22
|
+
export const useAgentStore = createWithEqualityFn<AgentStore>()(devtools(createStore), shallow);
|
package/src/store/chat/store.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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
|
);
|
package/src/store/file/store.ts
CHANGED
|
@@ -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 {
|
|
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 {
|
|
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 {
|
|
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
|
);
|