@lobehub/lobehub 2.0.0-next.15 → 2.0.0-next.17

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 +50 -0
  2. package/README.md +2 -45
  3. package/README.zh-CN.md +2 -45
  4. package/changelog/v1.json +18 -0
  5. package/docs/self-hosting/advanced/feature-flags.mdx +0 -1
  6. package/docs/self-hosting/advanced/feature-flags.zh-CN.mdx +0 -1
  7. package/e2e/src/features/discover/smoke.feature +34 -1
  8. package/e2e/src/steps/discover/smoke.steps.ts +116 -4
  9. package/package.json +1 -1
  10. package/packages/model-runtime/src/utils/googleErrorParser.test.ts +125 -0
  11. package/packages/model-runtime/src/utils/googleErrorParser.ts +103 -77
  12. package/packages/types/src/serverConfig.ts +2 -6
  13. package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -8
  14. package/src/app/[variants]/(main)/(mobile)/me/(home)/features/UserBanner.tsx +3 -6
  15. package/src/app/[variants]/(main)/discover/(list)/features/Pagination.tsx +1 -0
  16. package/src/app/[variants]/(main)/discover/(list)/features/SortButton/index.tsx +1 -1
  17. package/src/app/[variants]/(main)/discover/(list)/mcp/features/List/Item.tsx +1 -0
  18. package/src/app/[variants]/(main)/discover/(list)/model/features/List/Item.tsx +1 -0
  19. package/src/app/[variants]/(main)/discover/(list)/provider/features/List/Item.tsx +1 -0
  20. package/src/app/[variants]/(main)/discover/components/CategoryMenu.tsx +9 -1
  21. package/src/app/[variants]/(main)/labs/components/LabCard.tsx +3 -1
  22. package/src/app/[variants]/(main)/settings/provider/detail/azure/index.tsx +5 -7
  23. package/src/components/InvalidAPIKey/APIKeyForm/Bedrock.tsx +8 -13
  24. package/src/config/featureFlags/schema.test.ts +0 -2
  25. package/src/config/featureFlags/schema.ts +0 -6
  26. package/src/config/modelProviders/ai21.ts +1 -16
  27. package/src/config/modelProviders/ai302.ts +1 -128
  28. package/src/config/modelProviders/ai360.ts +1 -32
  29. package/src/config/modelProviders/anthropic.ts +1 -71
  30. package/src/config/modelProviders/azure.ts +1 -51
  31. package/src/config/modelProviders/baichuan.ts +1 -57
  32. package/src/config/modelProviders/bedrock.ts +1 -276
  33. package/src/config/modelProviders/cloudflare.ts +1 -64
  34. package/src/config/modelProviders/deepseek.ts +1 -19
  35. package/src/config/modelProviders/fireworksai.ts +1 -174
  36. package/src/config/modelProviders/giteeai.ts +1 -135
  37. package/src/config/modelProviders/github.ts +1 -254
  38. package/src/config/modelProviders/google.ts +1 -130
  39. package/src/config/modelProviders/groq.ts +1 -119
  40. package/src/config/modelProviders/higress.ts +1 -1713
  41. package/src/config/modelProviders/huggingface.ts +1 -54
  42. package/src/config/modelProviders/hunyuan.ts +1 -83
  43. package/src/config/modelProviders/infiniai.ts +1 -74
  44. package/src/config/modelProviders/internlm.ts +1 -20
  45. package/src/config/modelProviders/mistral.ts +1 -95
  46. package/src/config/modelProviders/modelscope.ts +1 -27
  47. package/src/config/modelProviders/moonshot.ts +1 -29
  48. package/src/config/modelProviders/novita.ts +1 -105
  49. package/src/config/modelProviders/ollama.ts +1 -325
  50. package/src/config/modelProviders/openai.ts +1 -242
  51. package/src/config/modelProviders/openrouter.ts +1 -240
  52. package/src/config/modelProviders/perplexity.ts +1 -45
  53. package/src/config/modelProviders/ppio.ts +1 -152
  54. package/src/config/modelProviders/qiniu.ts +1 -18
  55. package/src/config/modelProviders/qwen.ts +1 -245
  56. package/src/config/modelProviders/search1api.ts +1 -34
  57. package/src/config/modelProviders/sensenova.ts +1 -69
  58. package/src/config/modelProviders/siliconcloud.ts +1 -417
  59. package/src/config/modelProviders/spark.ts +1 -59
  60. package/src/config/modelProviders/stepfun.ts +1 -98
  61. package/src/config/modelProviders/taichu.ts +1 -18
  62. package/src/config/modelProviders/togetherai.ts +1 -274
  63. package/src/config/modelProviders/upstage.ts +1 -28
  64. package/src/config/modelProviders/wenxin.ts +1 -140
  65. package/src/config/modelProviders/xai.ts +1 -38
  66. package/src/config/modelProviders/zeroone.ts +1 -81
  67. package/src/config/modelProviders/zhipu.ts +1 -108
  68. package/src/helpers/isCanUseFC.ts +0 -8
  69. package/src/hooks/useEnabledChatModels.ts +0 -8
  70. package/src/hooks/useModelContextWindowTokens.ts +0 -8
  71. package/src/hooks/useModelHasContextWindowToken.ts +1 -10
  72. package/src/hooks/useModelSupportFiles.ts +1 -11
  73. package/src/hooks/useModelSupportReasoning.ts +1 -11
  74. package/src/hooks/useModelSupportToolUse.ts +1 -11
  75. package/src/hooks/useModelSupportVision.ts +1 -11
  76. package/src/layout/AuthProvider/Clerk/index.tsx +2 -16
  77. package/src/server/globalConfig/index.ts +0 -23
  78. package/src/server/routers/lambda/config/__snapshots__/index.test.ts.snap +175 -12
  79. package/src/server/routers/lambda/config/index.test.ts +36 -28
  80. package/src/services/chat/chat.test.ts +12 -0
  81. package/src/services/chat/helper.ts +7 -31
  82. package/src/services/models.ts +2 -11
  83. package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +41 -14
  84. package/src/store/global/store.ts +1 -7
  85. package/src/store/user/initialState.ts +1 -7
  86. package/src/store/user/selectors.ts +1 -5
  87. package/src/store/user/slices/common/action.ts +5 -4
  88. package/src/store/user/slices/settings/selectors/index.ts +1 -0
  89. package/src/store/user/slices/settings/selectors/keyVaults.ts +21 -0
  90. package/src/store/user/store.ts +0 -3
  91. package/src/tools/web-browsing/Render/Search/ConfigForm/Form.tsx +1 -1
  92. package/packages/utils/src/_deprecated/__snapshots__/parseModels.test.ts.snap +0 -104
  93. package/packages/utils/src/_deprecated/parseModels.test.ts +0 -287
  94. package/packages/utils/src/_deprecated/parseModels.ts +0 -165
  95. package/src/hooks/_header.ts +0 -23
  96. package/src/server/globalConfig/_deprecated.test.ts +0 -92
  97. package/src/server/globalConfig/_deprecated.ts +0 -41
  98. package/src/store/global/actions/clientDb.ts +0 -67
  99. package/src/store/user/slices/modelList/__snapshots__/action.test.ts.snap +0 -12
  100. package/src/store/user/slices/modelList/action.test.ts +0 -359
  101. package/src/store/user/slices/modelList/action.ts +0 -223
  102. package/src/store/user/slices/modelList/initialState.ts +0 -15
  103. package/src/store/user/slices/modelList/reducers/customModelCard.test.ts +0 -204
  104. package/src/store/user/slices/modelList/reducers/customModelCard.ts +0 -64
  105. package/src/store/user/slices/modelList/selectors/index.ts +0 -3
  106. package/src/store/user/slices/modelList/selectors/keyVaults.test.ts +0 -201
  107. package/src/store/user/slices/modelList/selectors/keyVaults.ts +0 -50
  108. package/src/store/user/slices/modelList/selectors/modelConfig.test.ts +0 -219
  109. package/src/store/user/slices/modelList/selectors/modelConfig.ts +0 -95
  110. package/src/store/user/slices/modelList/selectors/modelProvider.test.ts +0 -138
  111. package/src/store/user/slices/modelList/selectors/modelProvider.ts +0 -170
@@ -1,219 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
-
3
- import { UserStore } from '@/store/user';
4
- import { merge } from '@/utils/merge';
5
-
6
- import { UserState } from '../../../initialState';
7
- import { UserSettingsState, initialSettingsState } from '../../settings/initialState';
8
- import { modelConfigSelectors } from './modelConfig';
9
-
10
- describe('modelConfigSelectors', () => {
11
- describe('isProviderEnabled', () => {
12
- it('should return true if provider is enabled', () => {
13
- const s = merge(initialSettingsState, {
14
- settings: {
15
- languageModel: {
16
- ollama: { enabled: true },
17
- },
18
- },
19
- } as UserSettingsState) as unknown as UserStore;
20
-
21
- expect(modelConfigSelectors.isProviderEnabled('ollama')(s)).toBe(true);
22
- });
23
-
24
- it('should return false if provider is not enabled', () => {
25
- const s = merge(initialSettingsState, {
26
- settings: {
27
- languageModel: {
28
- perplexity: { enabled: false },
29
- },
30
- },
31
- } as UserSettingsState) as unknown as UserStore;
32
-
33
- expect(modelConfigSelectors.isProviderEnabled('perplexity')(s)).toBe(false);
34
- });
35
-
36
- it('should follow the user settings if provider is in the whitelist', () => {
37
- const s = merge(initialSettingsState, {
38
- settings: {
39
- languageModel: {
40
- ollama: { enabled: false },
41
- },
42
- },
43
- } as UserSettingsState) as unknown as UserStore;
44
-
45
- expect(modelConfigSelectors.isProviderEnabled('ollama')(s)).toBe(false);
46
- });
47
-
48
- it('ollama should be enabled by default', () => {
49
- const s = merge(initialSettingsState, {
50
- settings: {
51
- languageModel: {},
52
- },
53
- } as UserSettingsState) as unknown as UserStore;
54
- expect(modelConfigSelectors.isProviderEnabled('ollama')(s)).toBe(true);
55
- });
56
- });
57
-
58
- describe('isProviderFetchOnClient', () => {
59
- // The next 4 case are base on the rules on https://github.com/lobehub/lobe-chat/pull/2753
60
- it('client fetch should disabled on default', () => {
61
- const s = merge(initialSettingsState, {
62
- settings: {
63
- keyVaults: {
64
- azure: {
65
- endpoint: 'endpoint',
66
- apiKey: 'apikey',
67
- },
68
- },
69
- },
70
- } as UserSettingsState) as unknown as UserStore;
71
- expect(modelConfigSelectors.isProviderFetchOnClient('azure')(s)).toBe(false);
72
- });
73
-
74
- it('client fetch should disabled if no apikey or endpoint provided even user set it enabled', () => {
75
- const s = merge(initialSettingsState, {
76
- settings: {
77
- languageModel: {
78
- azure: { fetchOnClient: true },
79
- },
80
- },
81
- } as UserSettingsState) as unknown as UserStore;
82
- expect(modelConfigSelectors.isProviderFetchOnClient('azure')(s)).toBe(false);
83
- });
84
-
85
- it('client fetch should enable if only endpoint provided', () => {
86
- const s = merge(initialSettingsState, {
87
- settings: {
88
- languageModel: {
89
- azure: { fetchOnClient: false },
90
- },
91
- keyVaults: {
92
- azure: { endpoint: 'https://example.com' },
93
- },
94
- },
95
- } as UserSettingsState) as unknown as UserStore;
96
- expect(modelConfigSelectors.isProviderFetchOnClient('azure')(s)).toBe(true);
97
- });
98
-
99
- it('client fetch should control by user when a apikey or endpoint provided', () => {
100
- const s = merge(initialSettingsState, {
101
- settings: {
102
- languageModel: {
103
- azure: { fetchOnClient: true },
104
- },
105
- keyVaults: {
106
- azure: { apiKey: 'some-key' },
107
- },
108
- },
109
- } as UserSettingsState) as unknown as UserStore;
110
- expect(modelConfigSelectors.isProviderFetchOnClient('azure')(s)).toBe(true);
111
- });
112
-
113
- // Qwen provider not work in browser request. Please skip this case if it work in future.
114
- // Issue: https://github.com/lobehub/lobe-chat/issues/3108
115
- // PR: https://github.com/lobehub/lobe-chat/pull/3133
116
- it('client fecth should be disabled if provider is disable browser request', () => {
117
- const s = merge(initialSettingsState, {
118
- settings: {
119
- languageModel: {
120
- qwen: { fetchOnClient: true },
121
- },
122
- keyVaults: {
123
- qwen: {
124
- apiKey: 'apikey',
125
- },
126
- },
127
- },
128
- } as UserSettingsState) as unknown as UserStore;
129
- expect(modelConfigSelectors.isAutoFetchModelsEnabled('qwen')(s)).toBe(false);
130
- });
131
- });
132
-
133
- describe('getCustomModelCardById', () => {
134
- it('should return the custom model card with the given id and provider', () => {
135
- const s = merge(initialSettingsState, {
136
- settings: {
137
- languageModel: {
138
- perplexity: {
139
- customModelCards: [
140
- { id: 'custom-model-1', displayName: 'Custom Model 1' },
141
- { id: 'custom-model-2', displayName: 'Custom Model 2' },
142
- ],
143
- },
144
- },
145
- },
146
- } as UserSettingsState) as unknown as UserStore;
147
-
148
- const customModelCard = modelConfigSelectors.getCustomModelCard({
149
- id: 'custom-model-2',
150
- provider: 'perplexity',
151
- })(s);
152
-
153
- expect(customModelCard).toEqual({ id: 'custom-model-2', displayName: 'Custom Model 2' });
154
- });
155
-
156
- it('should return undefined if no custom model card is found with the given id and provider', () => {
157
- const s = merge(initialSettingsState, {
158
- settings: {
159
- languageModel: {
160
- perplexity: {
161
- customModelCards: [{ id: 'custom-model-1', displayName: 'Custom Model 1' }],
162
- },
163
- },
164
- },
165
- } as UserSettingsState) as unknown as UserStore;
166
-
167
- const customModelCard = modelConfigSelectors.getCustomModelCard({
168
- id: 'nonexistent-model',
169
- provider: 'perplexity',
170
- })(s);
171
-
172
- expect(customModelCard).toBeUndefined();
173
- });
174
- });
175
-
176
- describe('currentEditingCustomModelCard', () => {
177
- it('should return the custom model card that is currently being edited', () => {
178
- const s = merge(initialSettingsState, {
179
- settings: {
180
- languageModel: {
181
- perplexity: {
182
- customModelCards: [
183
- { id: 'custom-model-1', displayName: 'Custom Model 1' },
184
- { id: 'custom-model-2', displayName: 'Custom Model 2' },
185
- ],
186
- },
187
- },
188
- },
189
- editingCustomCardModel: {
190
- id: 'custom-model-2',
191
- provider: 'perplexity',
192
- },
193
- } as UserState) as unknown as UserStore;
194
-
195
- const currentEditingModelCard = modelConfigSelectors.currentEditingCustomModelCard(s);
196
-
197
- expect(currentEditingModelCard).toEqual({
198
- id: 'custom-model-2',
199
- displayName: 'Custom Model 2',
200
- });
201
- });
202
-
203
- it('should return undefined if no custom model card is currently being edited', () => {
204
- const s = merge(initialSettingsState, {
205
- settings: {
206
- languageModel: {
207
- perplexity: {
208
- customModelCards: [{ id: 'custom-model-1', displayName: 'Custom Model 1' }],
209
- },
210
- },
211
- },
212
- } as UserSettingsState) as unknown as UserStore;
213
-
214
- const currentEditingModelCard = modelConfigSelectors.currentEditingCustomModelCard(s);
215
-
216
- expect(currentEditingModelCard).toBeUndefined();
217
- });
218
- });
219
- });
@@ -1,95 +0,0 @@
1
- import { isProviderDisableBrowserRequest } from '@/config/modelProviders';
2
- import { isDesktop } from '@/const/version';
3
- import { UserStore } from '@/store/user';
4
- import { GlobalLLMProviderKey } from '@/types/user/settings';
5
-
6
- import { currentLLMSettings, getProviderConfigById } from '../../settings/selectors/settings';
7
- import { keyVaultsConfigSelectors } from './keyVaults';
8
-
9
- const isProviderEnabled = (provider: GlobalLLMProviderKey) => (s: UserStore) =>
10
- getProviderConfigById(provider)(s)?.enabled || false;
11
-
12
- const providerWhitelist = new Set(['ollama', 'lmstudio']);
13
- /**
14
- * @description The conditions to enable client fetch
15
- * 1. If no baseUrl and apikey input, force on Server.
16
- * 2. If only contains baseUrl, force on Client
17
- * 3. Follow the user settings.
18
- * 4. On Server, by default.
19
- */
20
- const isProviderFetchOnClient = (provider: GlobalLLMProviderKey | string) => (s: UserStore) => {
21
- const config = getProviderConfigById(provider)(s);
22
-
23
- // if is desktop, force on Server.
24
- if (isDesktop) return false;
25
-
26
- // If the provider already disable browser request in model config, force on Server.
27
- if (isProviderDisableBrowserRequest(provider)) return false;
28
-
29
- // If the provider in the whitelist, follow the user settings
30
- if (providerWhitelist.has(provider) && typeof config?.fetchOnClient !== 'undefined')
31
- return config?.fetchOnClient;
32
-
33
- // 1. If no baseUrl and apikey input, force on Server.
34
- const isProviderEndpointNotEmpty =
35
- keyVaultsConfigSelectors.isProviderEndpointNotEmpty(provider)(s);
36
- const isProviderApiKeyNotEmpty = keyVaultsConfigSelectors.isProviderApiKeyNotEmpty(provider)(s);
37
- if (!isProviderEndpointNotEmpty && !isProviderApiKeyNotEmpty) return false;
38
-
39
- // 2. If only contains baseUrl, force on Client
40
- if (isProviderEndpointNotEmpty && !isProviderApiKeyNotEmpty) return true;
41
-
42
- // 3. Follow the user settings.
43
- if (typeof config?.fetchOnClient !== 'undefined') return config?.fetchOnClient;
44
-
45
- // 4. On Server, by default.
46
- return false;
47
- };
48
-
49
- const getCustomModelCard =
50
- ({ id, provider }: { id?: string; provider?: string }) =>
51
- (s: UserStore) => {
52
- if (!provider) return;
53
-
54
- const config = getProviderConfigById(provider)(s);
55
-
56
- return config?.customModelCards?.find((m) => m.id === id);
57
- };
58
-
59
- const currentEditingCustomModelCard = (s: UserStore) => {
60
- if (!s.editingCustomCardModel) return;
61
- const { id, provider } = s.editingCustomCardModel;
62
-
63
- return getCustomModelCard({ id, provider })(s);
64
- };
65
-
66
- const isAutoFetchModelsEnabled =
67
- (provider: GlobalLLMProviderKey) =>
68
- (s: UserStore): boolean => {
69
- return getProviderConfigById(provider)(s)?.autoFetchModelLists || false;
70
- };
71
-
72
- const openAIConfig = (s: UserStore) => currentLLMSettings(s).openai;
73
- const bedrockConfig = (s: UserStore) => currentLLMSettings(s).bedrock;
74
- const ollamaConfig = (s: UserStore) => currentLLMSettings(s).ollama;
75
- const azureConfig = (s: UserStore) => currentLLMSettings(s).azure;
76
- const cloudflareConfig = (s: UserStore) => currentLLMSettings(s).cloudflare;
77
-
78
- const isAzureEnabled = (s: UserStore) => currentLLMSettings(s).azure.enabled;
79
-
80
- export const modelConfigSelectors = {
81
- azureConfig,
82
- bedrockConfig,
83
- cloudflareConfig,
84
-
85
- currentEditingCustomModelCard,
86
- getCustomModelCard,
87
-
88
- isAutoFetchModelsEnabled,
89
- isAzureEnabled,
90
- isProviderEnabled,
91
- isProviderFetchOnClient,
92
-
93
- ollamaConfig,
94
- openAIConfig,
95
- };
@@ -1,138 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
-
3
- import { merge } from '@/utils/merge';
4
-
5
- import { UserState, initialState } from '../../../initialState';
6
- import { UserStore, useUserStore } from '../../../store';
7
- import { getDefaultModeProviderById, modelProviderSelectors } from './modelProvider';
8
-
9
- describe('modelProviderSelectors', () => {
10
- describe('getDefaultModeProviderById', () => {
11
- it('should return the correct ModelProviderCard when provider ID matches', () => {
12
- const s = merge(initialState, {}) as unknown as UserStore;
13
-
14
- const result = getDefaultModeProviderById('openai')(s);
15
- expect(result).not.toBeUndefined();
16
- });
17
-
18
- it('should return undefined when provider ID does not exist', () => {
19
- const s = merge(initialState, {}) as unknown as UserStore;
20
- const result = getDefaultModeProviderById('nonExistingProvider')(s);
21
- expect(result).toBeUndefined();
22
- });
23
- });
24
-
25
- describe('getModelCardsById', () => {
26
- it('should return model cards including custom model cards', () => {
27
- const s = merge(initialState, {
28
- settings: {
29
- languageModel: {
30
- perplexity: {
31
- customModelCards: [{ id: 'custom-model', displayName: 'Custom Model' }],
32
- },
33
- },
34
- },
35
- } as UserState) as unknown as UserStore;
36
-
37
- const modelCards = modelProviderSelectors.getModelCardsById('perplexity')(s);
38
-
39
- expect(modelCards).toContainEqual({
40
- id: 'custom-model',
41
- displayName: 'Custom Model',
42
- isCustom: true,
43
- });
44
- });
45
- });
46
-
47
- describe('defaultEnabledProviderModels', () => {
48
- it('should return undefined for a non-existing provider', () => {
49
- const s = merge(initialState, {}) as unknown as UserStore;
50
-
51
- const result = modelProviderSelectors.getDefaultEnabledModelsById('nonExistingProvider')(s);
52
- expect(result).toBeUndefined();
53
- });
54
- });
55
- describe('modelEnabledVision', () => {
56
- it('should return true if the model has vision ability', () => {
57
- const hasAbility = modelProviderSelectors.isModelEnabledVision('gpt-4-vision-preview')(
58
- useUserStore.getState(),
59
- );
60
- expect(hasAbility).toBeTruthy();
61
- });
62
-
63
- it('should return false if the model does not have vision ability', () => {
64
- const hasAbility = modelProviderSelectors.isModelEnabledVision('some-other-model')(
65
- useUserStore.getState(),
66
- );
67
-
68
- expect(hasAbility).toBeFalsy();
69
- });
70
-
71
- it('should return false if the model include vision in id', () => {
72
- const hasAbility = modelProviderSelectors.isModelEnabledVision('some-other-model-vision')(
73
- useUserStore.getState(),
74
- );
75
-
76
- expect(hasAbility).toBeTruthy();
77
- });
78
- });
79
-
80
- describe('modelEnabledFiles', () => {
81
- it('should return false if the model does not have file ability', () => {
82
- const enabledFiles = modelProviderSelectors.isModelEnabledFiles('gpt-4-vision-preview')(
83
- useUserStore.getState(),
84
- );
85
- expect(enabledFiles).toBeFalsy();
86
- });
87
-
88
- it.skip('should return true if the model has file ability', () => {
89
- const enabledFiles = modelProviderSelectors.isModelEnabledFiles('gpt-4-all')(
90
- useUserStore.getState(),
91
- );
92
- expect(enabledFiles).toBeTruthy();
93
- });
94
- });
95
-
96
- describe('modelHasMaxToken', () => {
97
- it('should return true if the model is in the list of models that show tokens', () => {
98
- const show = modelProviderSelectors.isModelHasMaxToken('gpt-3.5-turbo')(
99
- useUserStore.getState(),
100
- );
101
- expect(show).toBeTruthy();
102
- });
103
-
104
- it('should return false if the model is not in the list of models that show tokens', () => {
105
- const show = modelProviderSelectors.isModelHasMaxToken('some-other-model')(
106
- useUserStore.getState(),
107
- );
108
- expect(show).toBe(false);
109
- });
110
- });
111
-
112
- describe('modelMaxToken', () => {
113
- it('should return the correct token count for a model with specified tokens', () => {
114
- const model1Tokens = modelProviderSelectors.modelMaxToken('gpt-3.5-turbo')(
115
- useUserStore.getState(),
116
- );
117
-
118
- expect(model1Tokens).toEqual(16385);
119
- });
120
-
121
- it('should return 0 for a model without a specified token count', () => {
122
- // 测试未指定tokens属性的模型的tokens值,期望为0
123
- const tokens = modelProviderSelectors.modelMaxToken('chat-bison-001')(
124
- useUserStore.getState(),
125
- );
126
- expect(tokens).toEqual(0);
127
- });
128
-
129
- it('should return 0 for a non-existing model', () => {
130
- // 测试一个不存在的模型的tokens值,期望为0
131
- const tokens = modelProviderSelectors.modelMaxToken('nonExistingModel')(
132
- useUserStore.getState(),
133
- );
134
-
135
- expect(tokens).toEqual(0);
136
- });
137
- });
138
- });
@@ -1,170 +0,0 @@
1
- import type {
2
- ChatModelCard,
3
- EnabledProviderWithModels,
4
- GlobalLLMProviderKey,
5
- ModelProviderCard,
6
- } from '@lobechat/types';
7
- import { ServerModelProviderConfig } from '@lobechat/types';
8
- import { uniqBy } from 'lodash-es';
9
-
10
- import { filterEnabledModels } from '@/config/modelProviders';
11
- import type { UserStore } from '@/store/user';
12
-
13
- import { currentSettings, getProviderConfigById } from '../../settings/selectors/settings';
14
-
15
- /**
16
- * get the server side model cards
17
- */
18
- const serverProviderModelCards =
19
- (provider: GlobalLLMProviderKey) =>
20
- (s: UserStore): ChatModelCard[] | undefined => {
21
- const config = s.serverLanguageModel?.[provider] as ServerModelProviderConfig | undefined;
22
-
23
- if (!config) return;
24
-
25
- return config.serverModelCards;
26
- };
27
-
28
- const remoteProviderModelCards =
29
- (provider: GlobalLLMProviderKey) =>
30
- (s: UserStore): ChatModelCard[] | undefined => {
31
- const cards = currentSettings(s).languageModel?.[provider]?.remoteModelCards as
32
- | ChatModelCard[]
33
- | undefined;
34
-
35
- if (!cards) return;
36
-
37
- return cards;
38
- };
39
-
40
- const isProviderEnabled = (provider: GlobalLLMProviderKey) => (s: UserStore) =>
41
- getProviderConfigById(provider)(s)?.enabled || false;
42
-
43
- // Default Model Provider List
44
-
45
- /**
46
- * define all the model list of providers
47
- */
48
- const defaultModelProviderList = (s: UserStore): ModelProviderCard[] => s.defaultModelProviderList;
49
-
50
- export const getDefaultModeProviderById = (provider: string) => (s: UserStore) =>
51
- defaultModelProviderList(s).find((s) => s.id === provider);
52
-
53
- /**
54
- * get the default enabled models for a provider
55
- * it's a default enabled model list by Lobe Chat
56
- * e.g. openai is ['gpt-4o-mini','gpt-4o','gpt-4-turbo']
57
- */
58
- const getDefaultEnabledModelsById = (provider: string) => (s: UserStore) => {
59
- const modelProvider = getDefaultModeProviderById(provider)(s);
60
-
61
- if (modelProvider) return filterEnabledModels(modelProvider);
62
-
63
- return undefined;
64
- };
65
-
66
- const getDefaultModelCardById = (id: string) => (s: UserStore) => {
67
- const list = defaultModelProviderList(s);
68
-
69
- return list.flatMap((i) => i.chatModels).find((m) => m.id === id);
70
- };
71
-
72
- // Model Provider List
73
-
74
- const getModelCardsById =
75
- (provider: string) =>
76
- (s: UserStore): ChatModelCard[] => {
77
- const builtinCards = getDefaultModeProviderById(provider)(s)?.chatModels || [];
78
-
79
- const userCards = (getProviderConfigById(provider)(s)?.customModelCards || []).map((model) => ({
80
- ...model,
81
- isCustom: true,
82
- }));
83
-
84
- return uniqBy([...userCards, ...builtinCards], 'id');
85
- };
86
-
87
- const getEnableModelsById = (provider: string) => (s: UserStore) => {
88
- if (!getProviderConfigById(provider)(s)?.enabledModels) return;
89
-
90
- return getProviderConfigById(provider)(s)?.enabledModels?.filter(Boolean);
91
- };
92
-
93
- const modelProviderList = (s: UserStore): ModelProviderCard[] => s.modelProviderList;
94
-
95
- const modelProviderListForModelSelect = (s: UserStore): EnabledProviderWithModels[] =>
96
- modelProviderList(s)
97
- .filter((s) => s.enabled)
98
- .map((provider) => ({
99
- ...provider,
100
- children: provider.chatModels
101
- .filter((model) => model.enabled)
102
- .map((m) => ({
103
- abilities: {
104
- functionCall: m.functionCall,
105
- vision: m.vision,
106
- },
107
- contextWindowTokens: m.contextWindowTokens,
108
- displayName: m.displayName,
109
- id: m.id,
110
- })),
111
- source: 'builtin',
112
- }));
113
-
114
- const getModelCardById = (id: string, provider?: GlobalLLMProviderKey) => (s: UserStore) => {
115
- const list = modelProviderList(s);
116
-
117
- return list
118
- .filter((i) => !provider || i.id === provider)
119
- .flatMap((i) => i.chatModels)
120
- .find((m) => m.id === id);
121
- };
122
-
123
- const isModelEnabledFunctionCall = (id: string) => (s: UserStore) =>
124
- getModelCardById(id)(s)?.functionCall || false;
125
-
126
- // vision model white list, these models will change the content from string to array
127
- // refs: https://github.com/lobehub/lobe-chat/issues/790
128
- const isModelEnabledVision = (id: string) => (s: UserStore) =>
129
- getModelCardById(id)(s)?.vision || id.includes('vision');
130
-
131
- const isModelEnabledReasoning = (id: string) => (s: UserStore) =>
132
- getModelCardById(id)(s)?.reasoning || false;
133
-
134
- const isModelEnabledFiles = (id: string) => (s: UserStore) => getModelCardById(id)(s)?.files;
135
-
136
- const isModelEnabledUpload = (id: string) => (s: UserStore) =>
137
- isModelEnabledVision(id)(s) || isModelEnabledFiles(id)(s);
138
-
139
- const isModelHasMaxToken = (id: string) => (s: UserStore) =>
140
- typeof getModelCardById(id)(s)?.contextWindowTokens !== 'undefined';
141
-
142
- const modelMaxToken = (id: string) => (s: UserStore) =>
143
- getModelCardById(id)(s)?.contextWindowTokens || 0;
144
-
145
- export const modelProviderSelectors = {
146
- defaultModelProviderList,
147
- getDefaultEnabledModelsById,
148
- getDefaultModelCardById,
149
-
150
- getEnableModelsById,
151
- getModelCardById,
152
-
153
- getModelCardsById,
154
- isModelEnabledFiles,
155
- isModelEnabledFunctionCall,
156
- isModelEnabledReasoning,
157
- isModelEnabledUpload,
158
- isModelEnabledVision,
159
- isModelHasMaxToken,
160
-
161
- isProviderEnabled,
162
-
163
- modelMaxToken,
164
- modelProviderList,
165
-
166
- modelProviderListForModelSelect,
167
-
168
- remoteProviderModelCards,
169
- serverProviderModelCards,
170
- };