@lobehub/lobehub 2.0.0-next.68 → 2.0.0-next.69

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 (59) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/package.json +1 -1
  4. package/packages/const/src/version.ts +0 -5
  5. package/packages/database/src/models/__tests__/chunk.test.ts +38 -0
  6. package/src/app/(backend)/api/webhooks/clerk/route.ts +1 -2
  7. package/src/app/[variants]/(main)/(mobile)/me/(home)/__tests__/useCategory.test.tsx +0 -20
  8. package/src/app/[variants]/(main)/(mobile)/me/(home)/features/useCategory.tsx +4 -33
  9. package/src/app/[variants]/(main)/(mobile)/me/profile/features/Category.tsx +18 -23
  10. package/src/app/[variants]/(main)/(mobile)/me/settings/features/useCategory.tsx +5 -15
  11. package/src/app/[variants]/(main)/discover/(detail)/provider/[...slugs]/features/Sidebar/ActionButton/ProviderConfig.tsx +4 -11
  12. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/ModelSelect/index.tsx +12 -27
  13. package/src/app/[variants]/(main)/image/layout.tsx +0 -4
  14. package/src/app/[variants]/(main)/profile/hooks/useCategory.tsx +10 -13
  15. package/src/app/[variants]/(main)/profile/stats/features/ShareButton/Preview.tsx +2 -14
  16. package/src/app/[variants]/(main)/settings/_layout/Desktop/index.tsx +2 -3
  17. package/src/app/[variants]/(main)/settings/_layout/SettingsContent.tsx +1 -12
  18. package/src/app/[variants]/(main)/settings/_layout/type.ts +0 -1
  19. package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +8 -16
  20. package/src/app/[variants]/(main)/settings/page.tsx +3 -7
  21. package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/index.tsx +2 -4
  22. package/src/app/[variants]/(main)/settings/storage/index.tsx +1 -9
  23. package/src/app/[variants]/(main)/settings/system-agent/index.tsx +1 -2
  24. package/src/components/InvalidAPIKey/APIKeyForm/useApiKey.ts +0 -12
  25. package/src/config/featureFlags/schema.test.ts +1 -3
  26. package/src/config/featureFlags/schema.ts +0 -3
  27. package/src/features/ChatInput/ActionBar/Knowledge/index.tsx +2 -3
  28. package/src/features/ChatInput/ActionBar/Search/index.tsx +5 -7
  29. package/src/features/ChatInput/ActionBar/Upload/index.tsx +1 -3
  30. package/src/features/Conversation/Messages/Assistant/index.tsx +1 -1
  31. package/src/features/Conversation/components/ShareMessageModal/index.tsx +3 -8
  32. package/src/features/DevPanel/PostgresViewer/usePgTable.ts +3 -11
  33. package/src/features/ModelSwitchPanel/index.tsx +9 -24
  34. package/src/features/ShareModal/index.tsx +7 -13
  35. package/src/features/User/UserPanel/PanelContent.tsx +6 -8
  36. package/src/hooks/useCheckPluginsIsInstalled.ts +1 -4
  37. package/src/hooks/useFetchGroups.ts +1 -4
  38. package/src/hooks/useFetchInstalledPlugins.ts +1 -4
  39. package/src/hooks/useFetchMessages.ts +1 -4
  40. package/src/hooks/useFetchSessions.ts +1 -4
  41. package/src/hooks/useFetchThreads.ts +1 -5
  42. package/src/hooks/useFetchTopics.ts +1 -4
  43. package/src/hooks/useInterceptingRoutes.test.ts +0 -19
  44. package/src/hooks/useInterceptingRoutes.ts +1 -7
  45. package/src/layout/GlobalProvider/StoreInitialization.tsx +2 -4
  46. package/src/services/_auth.ts +2 -11
  47. package/src/services/_header.ts +2 -10
  48. package/src/services/chat/chat.test.ts +53 -10
  49. package/src/services/chat/clientModelRuntime.test.ts +108 -172
  50. package/src/services/chat/contextEngineering.ts +2 -2
  51. package/src/services/config.ts +2 -2
  52. package/src/store/aiInfra/slices/aiProvider/action.ts +3 -4
  53. package/src/store/chat/slices/thread/action.ts +2 -2
  54. package/src/store/global/selectors/systemStatus.test.ts +0 -98
  55. package/src/store/global/selectors/systemStatus.ts +0 -30
  56. package/src/store/serverConfig/selectors.test.ts +2 -2
  57. package/src/store/serverConfig/store.test.ts +0 -1
  58. package/src/app/[variants]/(main)/settings/storage/IndexedDBStorage.tsx +0 -55
  59. package/src/features/ChatInput/ActionBar/Upload/ClientMode.tsx +0 -62
@@ -1,11 +1,9 @@
1
1
  import { useMemo } from 'react';
2
2
 
3
- import { INBOX_SESSION_ID } from '@/const/session';
4
- import { isDeprecatedEdition } from '@/const/version';
5
3
  import { useIsMobile } from '@/hooks/useIsMobile';
6
4
  import { useQueryRoute } from '@/hooks/useQueryRoute';
7
5
  import { useAgentStore } from '@/store/agent';
8
- import { ChatSettingsTabs, SettingsTabs } from '@/store/global/initialState';
6
+ import { ChatSettingsTabs } from '@/store/global/initialState';
9
7
  import { useSessionStore } from '@/store/session';
10
8
 
11
9
  export const useOpenChatSettings = (tab: ChatSettingsTabs = ChatSettingsTabs.Meta) => {
@@ -15,10 +13,6 @@ export const useOpenChatSettings = (tab: ChatSettingsTabs = ChatSettingsTabs.Met
15
13
  const router = useQueryRoute();
16
14
 
17
15
  return useMemo(() => {
18
- if (isDeprecatedEdition && activeId === INBOX_SESSION_ID) {
19
- return () => router.push(`/settings?active=${SettingsTabs.Agent}`);
20
- }
21
-
22
16
  if (isMobile) return () => router.push('/chat/settings', { query: { session: activeId } });
23
17
 
24
18
  return () => {
@@ -1,16 +1,15 @@
1
1
  'use client';
2
2
 
3
+ import { enableNextAuth } from '@lobechat/const';
3
4
  import { useRouter } from 'next/navigation';
4
5
  import { memo } from 'react';
5
6
  import { useTranslation } from 'react-i18next';
6
7
  import { createStoreUpdater } from 'zustand-utils';
7
8
 
8
- import { enableNextAuth } from '@/const/auth';
9
9
  import { useIsMobile } from '@/hooks/useIsMobile';
10
10
  import { useAgentStore } from '@/store/agent';
11
11
  import { useAiInfraStore } from '@/store/aiInfra';
12
12
  import { useGlobalStore } from '@/store/global';
13
- import { systemStatusSelectors } from '@/store/global/selectors';
14
13
  import { useServerConfigStore } from '@/store/serverConfig';
15
14
  import { serverConfigSelectors } from '@/store/serverConfig/selectors';
16
15
  import { useUserStore } from '@/store/user';
@@ -54,8 +53,7 @@ const StoreInitialization = memo(() => {
54
53
  * IMPORTANT: Explicitly convert to boolean to avoid passing null/undefined downstream,
55
54
  * which would cause unnecessary API requests with invalid login state.
56
55
  */
57
- const isDBInited = useGlobalStore(systemStatusSelectors.isDBInited);
58
- const isLoginOnInit = isDBInited ? Boolean(enableNextAuth ? isSignedIn : isLogin) : false;
56
+ const isLoginOnInit = Boolean(enableNextAuth ? isSignedIn : isLogin);
59
57
 
60
58
  // init inbox agent and default agent config
61
59
  useInitAgentStore(isLoginOnInit, serverConfig.defaultAgent?.config);
@@ -1,4 +1,4 @@
1
- import { LOBE_CHAT_AUTH_HEADER, isDeprecatedEdition } from '@lobechat/const';
1
+ import { LOBE_CHAT_AUTH_HEADER } from '@lobechat/const';
2
2
  import {
3
3
  AWSBedrockKeyVault,
4
4
  AzureOpenAIKeyVault,
@@ -119,16 +119,7 @@ interface AuthParams {
119
119
  }
120
120
 
121
121
  export const createPayloadWithKeyVaults = (provider: string) => {
122
- let keyVaults = {};
123
-
124
- // TODO: remove this condition in V2.0
125
- if (isDeprecatedEdition) {
126
- keyVaults = keyVaultsConfigSelectors.getVaultByProvider(provider as any)(
127
- useUserStore.getState(),
128
- );
129
- } else {
130
- keyVaults = aiProviderSelectors.providerKeyVaults(provider)(useAiInfraStore.getState()) || {};
131
- }
122
+ let keyVaults = aiProviderSelectors.providerKeyVaults(provider)(useAiInfraStore.getState()) || {};
132
123
 
133
124
  const runtimeProvider = resolveRuntimeProvider(provider);
134
125
 
@@ -4,7 +4,6 @@ import {
4
4
  OPENAI_API_KEY_HEADER_KEY,
5
5
  OPENAI_END_POINT,
6
6
  } from '@/const/fetch';
7
- import { isDeprecatedEdition } from '@/const/version';
8
7
  import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
9
8
  import { useUserStore } from '@/store/user';
10
9
  import { keyVaultsConfigSelectors } from '@/store/user/selectors';
@@ -17,16 +16,9 @@ import { keyVaultsConfigSelectors } from '@/store/user/selectors';
17
16
  export const createHeaderWithOpenAI = (header?: HeadersInit): HeadersInit => {
18
17
  const state = useUserStore.getState();
19
18
 
20
- let keyVaults: Record<string, any> = {};
19
+ const keyVaults: Record<string, any> =
20
+ aiProviderSelectors.providerKeyVaults('openai')(useAiInfraStore.getState()) || {};
21
21
 
22
- // TODO: remove this condition in V2.0
23
- if (isDeprecatedEdition) {
24
- keyVaults = keyVaultsConfigSelectors.getVaultByProvider('openai' as any)(
25
- useUserStore.getState(),
26
- );
27
- } else {
28
- keyVaults = aiProviderSelectors.providerKeyVaults('openai')(useAiInfraStore.getState()) || {};
29
- }
30
22
  // eslint-disable-next-line no-undef
31
23
  return {
32
24
  ...header,
@@ -278,15 +278,16 @@ describe('ChatService', () => {
278
278
 
279
279
  describe('should handle content correctly for vision models', () => {
280
280
  it('should include image content when with vision model', async () => {
281
+ // Mock helpers to return true for vision support (must be first)
282
+ const helpers = await import('./helper');
283
+ vi.spyOn(helpers, 'isCanUseVision').mockReturnValue(true);
284
+
281
285
  // Mock utility functions used in processImageList
282
286
  const { parseDataUri } = await import('@lobechat/utils/uriParser');
283
287
  const { isDesktopLocalStaticServerUrl } = await import('@lobechat/utils/url');
284
288
  vi.mocked(parseDataUri).mockReturnValue({ type: 'url', base64: null, mimeType: null });
285
289
  vi.mocked(isDesktopLocalStaticServerUrl).mockReturnValue(false); // Not a local URL
286
290
 
287
- // Mock aiModelSelectors to return true for vision support
288
- vi.spyOn(aiModelSelectors, 'isModelSupportVision').mockReturnValue(() => true);
289
-
290
291
  const messages = [
291
292
  {
292
293
  content: 'Hello',
@@ -315,13 +316,23 @@ describe('ChatService', () => {
315
316
  {
316
317
  content: [
317
318
  {
318
- text: 'Hello',
319
+ text: `Hello
320
+
321
+ <!-- SYSTEM CONTEXT (NOT PART OF USER QUERY) -->
322
+ <context.instruction>following part contains context information injected by the system. Please follow these instructions:
323
+
324
+ 1. Always prioritize handling user-visible content.
325
+ 2. the context is only required when user's queries rely on it.
326
+ </context.instruction>
327
+ <files_info>
328
+ <images>
329
+ <images_docstring>here are user upload images you can refer to</images_docstring>
330
+ <image name="abc.png" url="http://example.com/image.jpg"></image>
331
+ </images>
332
+ </files_info>
333
+ <!-- END SYSTEM CONTEXT -->`,
319
334
  type: 'text',
320
335
  },
321
- {
322
- image_url: { detail: 'auto', url: 'http://example.com/image.jpg' },
323
- type: 'image_url',
324
- },
325
336
  ],
326
337
  role: 'user',
327
338
  },
@@ -417,7 +428,21 @@ describe('ChatService', () => {
417
428
  {
418
429
  content: [
419
430
  {
420
- text: 'Hello',
431
+ text: `Hello
432
+
433
+ <!-- SYSTEM CONTEXT (NOT PART OF USER QUERY) -->
434
+ <context.instruction>following part contains context information injected by the system. Please follow these instructions:
435
+
436
+ 1. Always prioritize handling user-visible content.
437
+ 2. the context is only required when user's queries rely on it.
438
+ </context.instruction>
439
+ <files_info>
440
+ <images>
441
+ <images_docstring>here are user upload images you can refer to</images_docstring>
442
+ <image name="local-image.png" url="http://127.0.0.1:3000/uploads/image.png"></image>
443
+ </images>
444
+ </files_info>
445
+ <!-- END SYSTEM CONTEXT -->`,
421
446
  type: 'text',
422
447
  },
423
448
  {
@@ -432,6 +457,8 @@ describe('ChatService', () => {
432
457
  },
433
458
  ],
434
459
  model: 'gpt-4-vision-preview',
460
+ enabledSearch: undefined,
461
+ tools: undefined,
435
462
  },
436
463
  undefined,
437
464
  );
@@ -491,7 +518,21 @@ describe('ChatService', () => {
491
518
  {
492
519
  content: [
493
520
  {
494
- text: 'Hello',
521
+ text: `Hello
522
+
523
+ <!-- SYSTEM CONTEXT (NOT PART OF USER QUERY) -->
524
+ <context.instruction>following part contains context information injected by the system. Please follow these instructions:
525
+
526
+ 1. Always prioritize handling user-visible content.
527
+ 2. the context is only required when user's queries rely on it.
528
+ </context.instruction>
529
+ <files_info>
530
+ <images>
531
+ <images_docstring>here are user upload images you can refer to</images_docstring>
532
+ <image name="remote-image.jpg" url="https://example.com/remote-image.jpg"></image>
533
+ </images>
534
+ </files_info>
535
+ <!-- END SYSTEM CONTEXT -->`,
495
536
  type: 'text',
496
537
  },
497
538
  {
@@ -503,6 +544,8 @@ describe('ChatService', () => {
503
544
  },
504
545
  ],
505
546
  model: 'gpt-4-vision-preview',
547
+ enabledSearch: undefined,
548
+ tools: undefined,
506
549
  },
507
550
  undefined,
508
551
  );
@@ -18,14 +18,10 @@ import {
18
18
  LobeZhipuAI,
19
19
  ModelRuntime,
20
20
  } from '@lobechat/model-runtime';
21
- import { merge } from 'lodash-es';
22
21
  import { ModelProvider } from 'model-bank';
23
22
  import OpenAI from 'openai';
24
23
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
25
24
 
26
- import { UserStore } from '@/store/user';
27
- import { UserSettingsState, initialSettingsState } from '@/store/user/slices/settings/initialState';
28
-
29
25
  import { initializeWithClientStore } from './clientModelRuntime';
30
26
 
31
27
  // Mocking external dependencies
@@ -62,21 +58,35 @@ vi.mock('@lobechat/model-runtime', async (importOriginal) => {
62
58
  };
63
59
  });
64
60
 
65
- afterEach(() => {
61
+ // Mock version constants
62
+ vi.mock('@/const/version', () => ({
63
+ isServerMode: false,
64
+ isDeprecatedEdition: true,
65
+ isDesktop: false,
66
+ }));
67
+
68
+ // Helper function to mock aiInfra store with provider keyVaults
69
+ const mockProviderKeyVaults = async (provider: string, keyVaults: any) => {
70
+ const { useAiInfraStore } = await import('@/store/aiInfra');
71
+ // @ts-ignore
72
+ useAiInfraStore.setState((state) => ({
73
+ aiProviderRuntimeConfig: {
74
+ ...state.aiProviderRuntimeConfig,
75
+ [provider]: {
76
+ keyVaults,
77
+ },
78
+ },
79
+ }));
80
+ };
81
+
82
+ afterEach(async () => {
66
83
  vi.restoreAllMocks();
84
+ // Clean up store state
85
+ const { useAiInfraStore } = await import('@/store/aiInfra');
86
+ useAiInfraStore.setState({ aiProviderRuntimeConfig: {} } as any);
67
87
  });
68
88
 
69
89
  beforeEach(async () => {
70
- // 清除所有模块的缓存
71
- vi.resetModules();
72
-
73
- // 默认设置 isServerMode 为 false
74
- vi.mock('@/const/version', () => ({
75
- isServerMode: false,
76
- isDeprecatedEdition: true,
77
- isDesktop: false,
78
- }));
79
-
80
90
  // Reset all mocks
81
91
  vi.clearAllMocks();
82
92
 
@@ -97,17 +107,11 @@ describe('ModelRuntimeOnClient', () => {
97
107
  describe('initializeWithClientStore', () => {
98
108
  describe('should initialize with options correctly', () => {
99
109
  it('OpenAI provider: with apikey and endpoint', async () => {
100
- // Mock the global store to return the user's OpenAI API key and endpoint
101
- merge(initialSettingsState, {
102
- settings: {
103
- keyVaults: {
104
- openai: {
105
- apiKey: 'user-openai-key',
106
- baseURL: 'user-openai-endpoint',
107
- },
108
- },
109
- },
110
- } as UserSettingsState) as unknown as UserStore;
110
+ await mockProviderKeyVaults(ModelProvider.OpenAI, {
111
+ apiKey: 'user-openai-key',
112
+ baseURL: 'user-openai-endpoint',
113
+ });
114
+
111
115
  const runtime = await initializeWithClientStore({
112
116
  payload: {},
113
117
  provider: ModelProvider.OpenAI,
@@ -118,17 +122,11 @@ describe('ModelRuntimeOnClient', () => {
118
122
  });
119
123
 
120
124
  it('Azure provider: with apiKey, apiVersion, endpoint', async () => {
121
- merge(initialSettingsState, {
122
- settings: {
123
- keyVaults: {
124
- azure: {
125
- apiKey: 'user-azure-key',
126
- endpoint: 'user-azure-endpoint',
127
- apiVersion: '2024-06-01',
128
- },
129
- },
130
- },
131
- } as UserSettingsState) as unknown as UserStore;
125
+ await mockProviderKeyVaults(ModelProvider.Azure, {
126
+ apiKey: 'user-azure-key',
127
+ endpoint: 'user-azure-endpoint',
128
+ apiVersion: '2024-06-01',
129
+ });
132
130
 
133
131
  const runtime = await initializeWithClientStore({
134
132
  payload: {},
@@ -139,15 +137,10 @@ describe('ModelRuntimeOnClient', () => {
139
137
  });
140
138
 
141
139
  it('Google provider: with apiKey', async () => {
142
- merge(initialSettingsState, {
143
- settings: {
144
- keyVaults: {
145
- google: {
146
- apiKey: 'user-google-key',
147
- },
148
- },
149
- },
150
- } as UserSettingsState) as unknown as UserStore;
140
+ await mockProviderKeyVaults(ModelProvider.Google, {
141
+ apiKey: 'user-google-key',
142
+ });
143
+
151
144
  const runtime = await initializeWithClientStore({
152
145
  payload: {},
153
146
  provider: ModelProvider.Google,
@@ -157,15 +150,10 @@ describe('ModelRuntimeOnClient', () => {
157
150
  });
158
151
 
159
152
  it('Moonshot AI provider: with apiKey', async () => {
160
- merge(initialSettingsState, {
161
- settings: {
162
- keyVaults: {
163
- moonshot: {
164
- apiKey: 'user-moonshot-key',
165
- },
166
- },
167
- },
168
- } as UserSettingsState) as unknown as UserStore;
153
+ await mockProviderKeyVaults(ModelProvider.Moonshot, {
154
+ apiKey: 'user-moonshot-key',
155
+ });
156
+
169
157
  const runtime = await initializeWithClientStore({
170
158
  payload: {},
171
159
  provider: ModelProvider.Moonshot,
@@ -175,17 +163,12 @@ describe('ModelRuntimeOnClient', () => {
175
163
  });
176
164
 
177
165
  it('Bedrock provider: with accessKeyId, region, secretAccessKey', async () => {
178
- merge(initialSettingsState, {
179
- settings: {
180
- keyVaults: {
181
- bedrock: {
182
- accessKeyId: 'user-bedrock-access-key',
183
- region: 'user-bedrock-region',
184
- secretAccessKey: 'user-bedrock-secret',
185
- },
186
- },
187
- },
188
- } as UserSettingsState) as unknown as UserStore;
166
+ await mockProviderKeyVaults(ModelProvider.Bedrock, {
167
+ accessKeyId: 'user-bedrock-access-key',
168
+ region: 'user-bedrock-region',
169
+ secretAccessKey: 'user-bedrock-secret',
170
+ });
171
+
189
172
  const runtime = await initializeWithClientStore({
190
173
  payload: {},
191
174
  provider: ModelProvider.Bedrock,
@@ -195,15 +178,10 @@ describe('ModelRuntimeOnClient', () => {
195
178
  });
196
179
 
197
180
  it('Ollama provider: with endpoint', async () => {
198
- merge(initialSettingsState, {
199
- settings: {
200
- keyVaults: {
201
- ollama: {
202
- baseURL: 'http://127.0.0.1:1234',
203
- },
204
- },
205
- },
206
- } as UserSettingsState) as unknown as UserStore;
181
+ await mockProviderKeyVaults(ModelProvider.Ollama, {
182
+ baseURL: 'http://127.0.0.1:1234',
183
+ });
184
+
207
185
  const runtime = await initializeWithClientStore({
208
186
  payload: {},
209
187
  provider: ModelProvider.Ollama,
@@ -213,15 +191,10 @@ describe('ModelRuntimeOnClient', () => {
213
191
  });
214
192
 
215
193
  it('Perplexity provider: with apiKey', async () => {
216
- merge(initialSettingsState, {
217
- settings: {
218
- keyVaults: {
219
- perplexity: {
220
- apiKey: 'user-perplexity-key',
221
- },
222
- },
223
- },
224
- } as UserSettingsState) as unknown as UserStore;
194
+ await mockProviderKeyVaults(ModelProvider.Perplexity, {
195
+ apiKey: 'user-perplexity-key',
196
+ });
197
+
225
198
  const runtime = await initializeWithClientStore({
226
199
  payload: {},
227
200
  provider: ModelProvider.Perplexity,
@@ -231,15 +204,10 @@ describe('ModelRuntimeOnClient', () => {
231
204
  });
232
205
 
233
206
  it('Anthropic provider: with apiKey', async () => {
234
- merge(initialSettingsState, {
235
- settings: {
236
- keyVaults: {
237
- anthropic: {
238
- apiKey: 'user-anthropic-key',
239
- },
240
- },
241
- },
242
- } as UserSettingsState) as unknown as UserStore;
207
+ await mockProviderKeyVaults(ModelProvider.Anthropic, {
208
+ apiKey: 'user-anthropic-key',
209
+ });
210
+
243
211
  const runtime = await initializeWithClientStore({
244
212
  payload: {},
245
213
  provider: ModelProvider.Anthropic,
@@ -249,15 +217,10 @@ describe('ModelRuntimeOnClient', () => {
249
217
  });
250
218
 
251
219
  it('Mistral provider: with apiKey', async () => {
252
- merge(initialSettingsState, {
253
- settings: {
254
- keyVaults: {
255
- mistral: {
256
- apiKey: 'user-mistral-key',
257
- },
258
- },
259
- },
260
- } as UserSettingsState) as unknown as UserStore;
220
+ await mockProviderKeyVaults(ModelProvider.Mistral, {
221
+ apiKey: 'user-mistral-key',
222
+ });
223
+
261
224
  const runtime = await initializeWithClientStore({
262
225
  payload: {},
263
226
  provider: ModelProvider.Mistral,
@@ -267,15 +230,10 @@ describe('ModelRuntimeOnClient', () => {
267
230
  });
268
231
 
269
232
  it('OpenRouter provider: with apiKey', async () => {
270
- merge(initialSettingsState, {
271
- settings: {
272
- keyVaults: {
273
- openrouter: {
274
- apiKey: 'user-openrouter-key',
275
- },
276
- },
277
- },
278
- } as UserSettingsState) as unknown as UserStore;
233
+ await mockProviderKeyVaults(ModelProvider.OpenRouter, {
234
+ apiKey: 'user-openrouter-key',
235
+ });
236
+
279
237
  const runtime = await initializeWithClientStore({
280
238
  payload: {},
281
239
  provider: ModelProvider.OpenRouter,
@@ -285,15 +243,10 @@ describe('ModelRuntimeOnClient', () => {
285
243
  });
286
244
 
287
245
  it('TogetherAI provider: with apiKey', async () => {
288
- merge(initialSettingsState, {
289
- settings: {
290
- keyVaults: {
291
- togetherai: {
292
- apiKey: 'user-togetherai-key',
293
- },
294
- },
295
- },
296
- } as UserSettingsState) as unknown as UserStore;
246
+ await mockProviderKeyVaults(ModelProvider.TogetherAI, {
247
+ apiKey: 'user-togetherai-key',
248
+ });
249
+
297
250
  const runtime = await initializeWithClientStore({
298
251
  payload: {},
299
252
  provider: ModelProvider.TogetherAI,
@@ -303,15 +256,10 @@ describe('ModelRuntimeOnClient', () => {
303
256
  });
304
257
 
305
258
  it('ZeroOneAI provider: with apiKey', async () => {
306
- merge(initialSettingsState, {
307
- settings: {
308
- keyVaults: {
309
- zeroone: {
310
- apiKey: 'user-zeroone-key',
311
- },
312
- },
313
- },
314
- } as UserSettingsState) as unknown as UserStore;
259
+ await mockProviderKeyVaults(ModelProvider.ZeroOne, {
260
+ apiKey: 'user-zeroone-key',
261
+ });
262
+
315
263
  const runtime = await initializeWithClientStore({
316
264
  payload: {},
317
265
  provider: ModelProvider.ZeroOne,
@@ -321,16 +269,11 @@ describe('ModelRuntimeOnClient', () => {
321
269
  });
322
270
 
323
271
  it('Groq provider: with apiKey,endpoint', async () => {
324
- merge(initialSettingsState, {
325
- settings: {
326
- keyVaults: {
327
- groq: {
328
- apiKey: 'user-groq-key',
329
- baseURL: 'user-groq-endpoint',
330
- },
331
- },
332
- },
333
- } as UserSettingsState) as unknown as UserStore;
272
+ await mockProviderKeyVaults(ModelProvider.Groq, {
273
+ apiKey: 'user-groq-key',
274
+ baseURL: 'user-groq-endpoint',
275
+ });
276
+
334
277
  const runtime = await initializeWithClientStore({
335
278
  payload: {},
336
279
  provider: ModelProvider.Groq,
@@ -344,15 +287,10 @@ describe('ModelRuntimeOnClient', () => {
344
287
  });
345
288
 
346
289
  it('DeepSeek provider: with apiKey', async () => {
347
- merge(initialSettingsState, {
348
- settings: {
349
- keyVaults: {
350
- deepseek: {
351
- apiKey: 'user-deepseek-key',
352
- },
353
- },
354
- },
355
- } as UserSettingsState) as unknown as UserStore;
290
+ await mockProviderKeyVaults(ModelProvider.DeepSeek, {
291
+ apiKey: 'user-deepseek-key',
292
+ });
293
+
356
294
  const runtime = await initializeWithClientStore({
357
295
  payload: {},
358
296
  provider: ModelProvider.DeepSeek,
@@ -362,15 +300,10 @@ describe('ModelRuntimeOnClient', () => {
362
300
  });
363
301
 
364
302
  it('Qwen provider: with apiKey', async () => {
365
- merge(initialSettingsState, {
366
- settings: {
367
- keyVaults: {
368
- qwen: {
369
- apiKey: 'user-qwen-key',
370
- },
371
- },
372
- },
373
- } as UserSettingsState) as unknown as UserStore;
303
+ await mockProviderKeyVaults(ModelProvider.Qwen, {
304
+ apiKey: 'user-qwen-key',
305
+ });
306
+
374
307
  const runtime = await initializeWithClientStore({
375
308
  payload: {},
376
309
  provider: ModelProvider.Qwen,
@@ -384,16 +317,23 @@ describe('ModelRuntimeOnClient', () => {
384
317
  * similar cases in server side
385
318
  */
386
319
  it('Unknown provider: with apiKey', async () => {
387
- merge(initialSettingsState, {
388
- settings: {
389
- keyVaults: {
390
- unknown: {
320
+ const { useAiInfraStore } = await import('@/store/aiInfra');
321
+ // @ts-ignore
322
+ useAiInfraStore.setState((state) => ({
323
+ aiProviderRuntimeConfig: {
324
+ ...state.aiProviderRuntimeConfig,
325
+ unknown: {
326
+ keyVaults: {
391
327
  apiKey: 'user-unknown-key',
392
- endpoint: 'user-unknown-endpoint',
328
+ baseURL: 'user-unknown-endpoint',
329
+ },
330
+ settings: {
331
+ sdkType: 'openai',
393
332
  },
394
333
  },
395
334
  },
396
- } as any as UserSettingsState) as unknown as UserStore;
335
+ }));
336
+
397
337
  const runtime = await initializeWithClientStore({
398
338
  payload: {},
399
339
  provider: 'unknown' as ModelProvider,
@@ -415,15 +355,11 @@ describe('ModelRuntimeOnClient', () => {
415
355
  'eyJhbGciOiJIUzI1NiIsInNpZ25fdHlwZSI6IlNJR04iLCJ0eXAiOiJKV1QifQ.eyJhcGlfa2V5IjoiemhpcHUiLCJleHAiOjE3MTU5MTc2NzMsImlhdCI6MTcxMzMyNTY3M30.gt8o-hUDvJFPJLYcH4EhrT1LAmTXI8YnybHeQjpD9oM',
416
356
  ),
417
357
  }));
418
- merge(initialSettingsState, {
419
- settings: {
420
- keyVaults: {
421
- zhipu: {
422
- apiKey: 'zhipu.user-key',
423
- },
424
- },
425
- },
426
- } as UserSettingsState) as unknown as UserStore;
358
+
359
+ await mockProviderKeyVaults(ModelProvider.ZhiPu, {
360
+ apiKey: 'zhipu.user-key',
361
+ });
362
+
427
363
  const runtime = await initializeWithClientStore({
428
364
  payload: {},
429
365
  provider: ModelProvider.ZhiPu,
@@ -1,4 +1,4 @@
1
- import { isDesktop, isServerMode } from '@lobechat/const';
1
+ import { isDesktop } from '@lobechat/const';
2
2
  import {
3
3
  ContextEngine,
4
4
  GroupMessageFlattenProcessor,
@@ -88,7 +88,7 @@ export const contextEngineering = async ({
88
88
 
89
89
  // 8.5 Message content processing
90
90
  new MessageContentProcessor({
91
- fileContext: { enabled: isServerMode, includeFileUrl: !isDesktop },
91
+ fileContext: { enabled: true, includeFileUrl: !isDesktop },
92
92
  isCanUseVideo,
93
93
  isCanUseVision,
94
94
  model,
@@ -1,4 +1,4 @@
1
- import { BRANDING_NAME, isServerMode } from '@lobechat/const';
1
+ import { BRANDING_NAME } from '@lobechat/const';
2
2
  import { downloadFile, exportJSONFile } from '@lobechat/utils/client';
3
3
  import dayjs from 'dayjs';
4
4
 
@@ -19,7 +19,7 @@ class ConfigService {
19
19
  }
20
20
 
21
21
  // or export to file with the data
22
- const result = await this.createDataStructure(data, isServerMode ? 'postgres' : 'pglite');
22
+ const result = await this.createDataStructure(data, 'postgres');
23
23
 
24
24
  exportJSONFile(result, filename);
25
25
  };