@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.
- package/CHANGELOG.md +50 -0
- package/README.md +2 -45
- package/README.zh-CN.md +2 -45
- package/changelog/v1.json +18 -0
- package/docs/self-hosting/advanced/feature-flags.mdx +0 -1
- package/docs/self-hosting/advanced/feature-flags.zh-CN.mdx +0 -1
- package/e2e/src/features/discover/smoke.feature +34 -1
- package/e2e/src/steps/discover/smoke.steps.ts +116 -4
- package/package.json +1 -1
- package/packages/model-runtime/src/utils/googleErrorParser.test.ts +125 -0
- package/packages/model-runtime/src/utils/googleErrorParser.ts +103 -77
- package/packages/types/src/serverConfig.ts +2 -6
- package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -8
- package/src/app/[variants]/(main)/(mobile)/me/(home)/features/UserBanner.tsx +3 -6
- package/src/app/[variants]/(main)/discover/(list)/features/Pagination.tsx +1 -0
- package/src/app/[variants]/(main)/discover/(list)/features/SortButton/index.tsx +1 -1
- package/src/app/[variants]/(main)/discover/(list)/mcp/features/List/Item.tsx +1 -0
- package/src/app/[variants]/(main)/discover/(list)/model/features/List/Item.tsx +1 -0
- package/src/app/[variants]/(main)/discover/(list)/provider/features/List/Item.tsx +1 -0
- package/src/app/[variants]/(main)/discover/components/CategoryMenu.tsx +9 -1
- package/src/app/[variants]/(main)/labs/components/LabCard.tsx +3 -1
- package/src/app/[variants]/(main)/settings/provider/detail/azure/index.tsx +5 -7
- package/src/components/InvalidAPIKey/APIKeyForm/Bedrock.tsx +8 -13
- package/src/config/featureFlags/schema.test.ts +0 -2
- package/src/config/featureFlags/schema.ts +0 -6
- package/src/config/modelProviders/ai21.ts +1 -16
- package/src/config/modelProviders/ai302.ts +1 -128
- package/src/config/modelProviders/ai360.ts +1 -32
- package/src/config/modelProviders/anthropic.ts +1 -71
- package/src/config/modelProviders/azure.ts +1 -51
- package/src/config/modelProviders/baichuan.ts +1 -57
- package/src/config/modelProviders/bedrock.ts +1 -276
- package/src/config/modelProviders/cloudflare.ts +1 -64
- package/src/config/modelProviders/deepseek.ts +1 -19
- package/src/config/modelProviders/fireworksai.ts +1 -174
- package/src/config/modelProviders/giteeai.ts +1 -135
- package/src/config/modelProviders/github.ts +1 -254
- package/src/config/modelProviders/google.ts +1 -130
- package/src/config/modelProviders/groq.ts +1 -119
- package/src/config/modelProviders/higress.ts +1 -1713
- package/src/config/modelProviders/huggingface.ts +1 -54
- package/src/config/modelProviders/hunyuan.ts +1 -83
- package/src/config/modelProviders/infiniai.ts +1 -74
- package/src/config/modelProviders/internlm.ts +1 -20
- package/src/config/modelProviders/mistral.ts +1 -95
- package/src/config/modelProviders/modelscope.ts +1 -27
- package/src/config/modelProviders/moonshot.ts +1 -29
- package/src/config/modelProviders/novita.ts +1 -105
- package/src/config/modelProviders/ollama.ts +1 -325
- package/src/config/modelProviders/openai.ts +1 -242
- package/src/config/modelProviders/openrouter.ts +1 -240
- package/src/config/modelProviders/perplexity.ts +1 -45
- package/src/config/modelProviders/ppio.ts +1 -152
- package/src/config/modelProviders/qiniu.ts +1 -18
- package/src/config/modelProviders/qwen.ts +1 -245
- package/src/config/modelProviders/search1api.ts +1 -34
- package/src/config/modelProviders/sensenova.ts +1 -69
- package/src/config/modelProviders/siliconcloud.ts +1 -417
- package/src/config/modelProviders/spark.ts +1 -59
- package/src/config/modelProviders/stepfun.ts +1 -98
- package/src/config/modelProviders/taichu.ts +1 -18
- package/src/config/modelProviders/togetherai.ts +1 -274
- package/src/config/modelProviders/upstage.ts +1 -28
- package/src/config/modelProviders/wenxin.ts +1 -140
- package/src/config/modelProviders/xai.ts +1 -38
- package/src/config/modelProviders/zeroone.ts +1 -81
- package/src/config/modelProviders/zhipu.ts +1 -108
- package/src/helpers/isCanUseFC.ts +0 -8
- package/src/hooks/useEnabledChatModels.ts +0 -8
- package/src/hooks/useModelContextWindowTokens.ts +0 -8
- package/src/hooks/useModelHasContextWindowToken.ts +1 -10
- package/src/hooks/useModelSupportFiles.ts +1 -11
- package/src/hooks/useModelSupportReasoning.ts +1 -11
- package/src/hooks/useModelSupportToolUse.ts +1 -11
- package/src/hooks/useModelSupportVision.ts +1 -11
- package/src/layout/AuthProvider/Clerk/index.tsx +2 -16
- package/src/server/globalConfig/index.ts +0 -23
- package/src/server/routers/lambda/config/__snapshots__/index.test.ts.snap +175 -12
- package/src/server/routers/lambda/config/index.test.ts +36 -28
- package/src/services/chat/chat.test.ts +12 -0
- package/src/services/chat/helper.ts +7 -31
- package/src/services/models.ts +2 -11
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +41 -14
- package/src/store/global/store.ts +1 -7
- package/src/store/user/initialState.ts +1 -7
- package/src/store/user/selectors.ts +1 -5
- package/src/store/user/slices/common/action.ts +5 -4
- package/src/store/user/slices/settings/selectors/index.ts +1 -0
- package/src/store/user/slices/settings/selectors/keyVaults.ts +21 -0
- package/src/store/user/store.ts +0 -3
- package/src/tools/web-browsing/Render/Search/ConfigForm/Form.tsx +1 -1
- package/packages/utils/src/_deprecated/__snapshots__/parseModels.test.ts.snap +0 -104
- package/packages/utils/src/_deprecated/parseModels.test.ts +0 -287
- package/packages/utils/src/_deprecated/parseModels.ts +0 -165
- package/src/hooks/_header.ts +0 -23
- package/src/server/globalConfig/_deprecated.test.ts +0 -92
- package/src/server/globalConfig/_deprecated.ts +0 -41
- package/src/store/global/actions/clientDb.ts +0 -67
- package/src/store/user/slices/modelList/__snapshots__/action.test.ts.snap +0 -12
- package/src/store/user/slices/modelList/action.test.ts +0 -359
- package/src/store/user/slices/modelList/action.ts +0 -223
- package/src/store/user/slices/modelList/initialState.ts +0 -15
- package/src/store/user/slices/modelList/reducers/customModelCard.test.ts +0 -204
- package/src/store/user/slices/modelList/reducers/customModelCard.ts +0 -64
- package/src/store/user/slices/modelList/selectors/index.ts +0 -3
- package/src/store/user/slices/modelList/selectors/keyVaults.test.ts +0 -201
- package/src/store/user/slices/modelList/selectors/keyVaults.ts +0 -50
- package/src/store/user/slices/modelList/selectors/modelConfig.test.ts +0 -219
- package/src/store/user/slices/modelList/selectors/modelConfig.ts +0 -95
- package/src/store/user/slices/modelList/selectors/modelProvider.test.ts +0 -138
- package/src/store/user/slices/modelList/selectors/modelProvider.ts +0 -170
|
@@ -36,7 +36,7 @@ describe('configRouter', () => {
|
|
|
36
36
|
const response = await router.getGlobalConfig();
|
|
37
37
|
|
|
38
38
|
// Assert
|
|
39
|
-
const result = response.serverConfig.
|
|
39
|
+
const result = response.serverConfig.aiProvider?.openai;
|
|
40
40
|
|
|
41
41
|
expect(result).toMatchSnapshot();
|
|
42
42
|
process.env.OPENAI_MODEL_LIST = '';
|
|
@@ -48,7 +48,7 @@ describe('configRouter', () => {
|
|
|
48
48
|
|
|
49
49
|
const response = await router.getGlobalConfig();
|
|
50
50
|
|
|
51
|
-
const result = response.serverConfig.
|
|
51
|
+
const result = response.serverConfig.aiProvider?.openai?.serverModelLists;
|
|
52
52
|
|
|
53
53
|
expect(result).toMatchSnapshot();
|
|
54
54
|
|
|
@@ -61,7 +61,7 @@ describe('configRouter', () => {
|
|
|
61
61
|
|
|
62
62
|
const response = await router.getGlobalConfig();
|
|
63
63
|
|
|
64
|
-
const result = response.serverConfig.
|
|
64
|
+
const result = response.serverConfig.aiProvider?.openai?.serverModelLists;
|
|
65
65
|
|
|
66
66
|
expect(result?.find((s) => s.id === 'gpt-4-0125-preview')?.displayName).toEqual(
|
|
67
67
|
'gpt-4-32k',
|
|
@@ -75,7 +75,7 @@ describe('configRouter', () => {
|
|
|
75
75
|
|
|
76
76
|
const response = await router.getGlobalConfig();
|
|
77
77
|
|
|
78
|
-
const result = response.serverConfig.
|
|
78
|
+
const result = response.serverConfig.aiProvider?.openai?.serverModelLists;
|
|
79
79
|
|
|
80
80
|
expect(result?.find((r) => r.id === 'gpt-4')).toBeUndefined();
|
|
81
81
|
|
|
@@ -87,7 +87,7 @@ describe('configRouter', () => {
|
|
|
87
87
|
|
|
88
88
|
const response = await router.getGlobalConfig();
|
|
89
89
|
|
|
90
|
-
const result = response.serverConfig.
|
|
90
|
+
const result = response.serverConfig.aiProvider?.openai?.serverModelLists;
|
|
91
91
|
|
|
92
92
|
const model = result?.find((o) => o.id === 'gpt-4-1106-preview');
|
|
93
93
|
|
|
@@ -101,28 +101,36 @@ describe('configRouter', () => {
|
|
|
101
101
|
|
|
102
102
|
const response = await router.getGlobalConfig();
|
|
103
103
|
|
|
104
|
-
const result = response.serverConfig.
|
|
105
|
-
|
|
106
|
-
expect(result).toContainEqual(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
104
|
+
const result = response.serverConfig.aiProvider?.openai?.serverModelLists;
|
|
105
|
+
|
|
106
|
+
expect(result).toContainEqual(
|
|
107
|
+
expect.objectContaining({
|
|
108
|
+
displayName: 'model1',
|
|
109
|
+
id: 'model1',
|
|
110
|
+
enabled: true,
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
113
|
+
expect(result).toContainEqual(
|
|
114
|
+
expect.objectContaining({
|
|
115
|
+
displayName: 'model2',
|
|
116
|
+
enabled: true,
|
|
117
|
+
id: 'model2',
|
|
118
|
+
}),
|
|
119
|
+
);
|
|
120
|
+
expect(result).toContainEqual(
|
|
121
|
+
expect.objectContaining({
|
|
122
|
+
displayName: 'model3',
|
|
123
|
+
enabled: true,
|
|
124
|
+
id: 'model3',
|
|
125
|
+
}),
|
|
126
|
+
);
|
|
127
|
+
expect(result).toContainEqual(
|
|
128
|
+
expect.objectContaining({
|
|
129
|
+
displayName: 'model4',
|
|
130
|
+
enabled: true,
|
|
131
|
+
id: 'model4',
|
|
132
|
+
}),
|
|
133
|
+
);
|
|
126
134
|
|
|
127
135
|
process.env.OPENAI_MODEL_LIST = '';
|
|
128
136
|
});
|
|
@@ -136,7 +144,7 @@ describe('configRouter', () => {
|
|
|
136
144
|
const response = await router.getGlobalConfig();
|
|
137
145
|
|
|
138
146
|
// Assert
|
|
139
|
-
const result = response.serverConfig.
|
|
147
|
+
const result = response.serverConfig.aiProvider?.openrouter;
|
|
140
148
|
|
|
141
149
|
expect(result).toMatchSnapshot();
|
|
142
150
|
|
|
@@ -284,6 +284,9 @@ describe('ChatService', () => {
|
|
|
284
284
|
vi.mocked(parseDataUri).mockReturnValue({ type: 'url', base64: null, mimeType: null });
|
|
285
285
|
vi.mocked(isDesktopLocalStaticServerUrl).mockReturnValue(false); // Not a local URL
|
|
286
286
|
|
|
287
|
+
// Mock aiModelSelectors to return true for vision support
|
|
288
|
+
vi.spyOn(aiModelSelectors, 'isModelSupportVision').mockReturnValue(() => true);
|
|
289
|
+
|
|
287
290
|
const messages = [
|
|
288
291
|
{
|
|
289
292
|
content: 'Hello',
|
|
@@ -369,6 +372,9 @@ describe('ChatService', () => {
|
|
|
369
372
|
mimeType: 'image/png',
|
|
370
373
|
});
|
|
371
374
|
|
|
375
|
+
// Mock aiModelSelectors to return true for vision support
|
|
376
|
+
vi.spyOn(aiModelSelectors, 'isModelSupportVision').mockReturnValue(() => true);
|
|
377
|
+
|
|
372
378
|
const messages = [
|
|
373
379
|
{
|
|
374
380
|
content: 'Hello',
|
|
@@ -441,6 +447,9 @@ describe('ChatService', () => {
|
|
|
441
447
|
vi.mocked(isDesktopLocalStaticServerUrl).mockReturnValue(false); // This is NOT a local URL
|
|
442
448
|
vi.mocked(imageUrlToBase64).mockClear(); // Clear to ensure it's not called
|
|
443
449
|
|
|
450
|
+
// Mock aiModelSelectors to return true for vision support
|
|
451
|
+
vi.spyOn(aiModelSelectors, 'isModelSupportVision').mockReturnValue(() => true);
|
|
452
|
+
|
|
444
453
|
const messages = [
|
|
445
454
|
{
|
|
446
455
|
content: 'Hello',
|
|
@@ -518,6 +527,9 @@ describe('ChatService', () => {
|
|
|
518
527
|
mimeType: 'image/jpeg',
|
|
519
528
|
});
|
|
520
529
|
|
|
530
|
+
// Mock aiModelSelectors to return true for vision support
|
|
531
|
+
vi.spyOn(aiModelSelectors, 'isModelSupportVision').mockReturnValue(() => true);
|
|
532
|
+
|
|
521
533
|
const messages = [
|
|
522
534
|
{
|
|
523
535
|
content: 'Multiple images',
|
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
import { isDeprecatedEdition } from '@lobechat/const';
|
|
2
1
|
import { ModelProvider } from 'model-bank';
|
|
3
2
|
|
|
4
3
|
import { getAiInfraStoreState } from '@/store/aiInfra';
|
|
5
4
|
import { aiModelSelectors, aiProviderSelectors } from '@/store/aiInfra/selectors';
|
|
6
|
-
import { getUserStoreState, useUserStore } from '@/store/user';
|
|
7
|
-
import { modelConfigSelectors, modelProviderSelectors } from '@/store/user/selectors';
|
|
8
5
|
|
|
9
6
|
export const isCanUseVision = (model: string, provider: string): boolean => {
|
|
10
|
-
// TODO: remove isDeprecatedEdition condition in V2.0
|
|
11
|
-
if (isDeprecatedEdition) {
|
|
12
|
-
return modelProviderSelectors.isModelEnabledVision(model)(getUserStoreState());
|
|
13
|
-
}
|
|
14
7
|
return aiModelSelectors.isModelSupportVision(model, provider)(getAiInfraStoreState());
|
|
15
8
|
};
|
|
16
9
|
|
|
@@ -24,40 +17,23 @@ export const isCanUseVideo = (model: string, provider: string): boolean => {
|
|
|
24
17
|
export const findDeploymentName = (model: string, provider: string) => {
|
|
25
18
|
let deploymentId = model;
|
|
26
19
|
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
const deploymentName = chatModelCards.find((i) => i.id === model)?.deploymentName;
|
|
34
|
-
if (deploymentName) deploymentId = deploymentName;
|
|
35
|
-
} else {
|
|
36
|
-
// find the model by id
|
|
37
|
-
const modelItem = getAiInfraStoreState().enabledAiModels?.find(
|
|
38
|
-
(i) => i.id === model && i.providerId === provider,
|
|
39
|
-
);
|
|
20
|
+
// find the model by id
|
|
21
|
+
const modelItem = getAiInfraStoreState().enabledAiModels?.find(
|
|
22
|
+
(i) => i.id === model && i.providerId === provider,
|
|
23
|
+
);
|
|
40
24
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
25
|
+
if (modelItem && modelItem.config?.deploymentName) {
|
|
26
|
+
deploymentId = modelItem.config?.deploymentName;
|
|
44
27
|
}
|
|
45
28
|
|
|
46
29
|
return deploymentId;
|
|
47
30
|
};
|
|
48
31
|
|
|
49
32
|
export const isEnableFetchOnClient = (provider: string) => {
|
|
50
|
-
|
|
51
|
-
if (isDeprecatedEdition) {
|
|
52
|
-
return modelConfigSelectors.isProviderFetchOnClient(provider)(useUserStore.getState());
|
|
53
|
-
} else {
|
|
54
|
-
return aiProviderSelectors.isProviderFetchOnClient(provider)(getAiInfraStoreState());
|
|
55
|
-
}
|
|
33
|
+
return aiProviderSelectors.isProviderFetchOnClient(provider)(getAiInfraStoreState());
|
|
56
34
|
};
|
|
57
35
|
|
|
58
36
|
export const resolveRuntimeProvider = (provider: string) => {
|
|
59
|
-
if (isDeprecatedEdition) return provider;
|
|
60
|
-
|
|
61
37
|
const isBuiltin = Object.values(ModelProvider).includes(provider as any);
|
|
62
38
|
if (isBuiltin) return provider;
|
|
63
39
|
|
package/src/services/models.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { isDeprecatedEdition } from '@/const/version';
|
|
2
1
|
import { createHeaderWithAuth } from '@/services/_auth';
|
|
3
2
|
import { aiProviderSelectors, getAiInfraStoreState } from '@/store/aiInfra';
|
|
4
|
-
import { useUserStore } from '@/store/user';
|
|
5
|
-
import { modelConfigSelectors } from '@/store/user/selectors';
|
|
6
3
|
import { ChatModelCard } from '@/types/llm';
|
|
7
4
|
import { getMessageError } from '@/utils/fetch';
|
|
8
5
|
|
|
@@ -10,14 +7,8 @@ import { API_ENDPOINTS } from './_url';
|
|
|
10
7
|
import { initializeWithClientStore } from './chat/clientModelRuntime';
|
|
11
8
|
import { resolveRuntimeProvider } from './chat/helper';
|
|
12
9
|
|
|
13
|
-
const isEnableFetchOnClient = (provider: string) =>
|
|
14
|
-
|
|
15
|
-
if (isDeprecatedEdition) {
|
|
16
|
-
return modelConfigSelectors.isProviderFetchOnClient(provider)(useUserStore.getState());
|
|
17
|
-
} else {
|
|
18
|
-
return aiProviderSelectors.isProviderFetchOnClient(provider)(getAiInfraStoreState());
|
|
19
|
-
}
|
|
20
|
-
};
|
|
10
|
+
const isEnableFetchOnClient = (provider: string) =>
|
|
11
|
+
aiProviderSelectors.isProviderFetchOnClient(provider)(getAiInfraStoreState());
|
|
21
12
|
|
|
22
13
|
// 进度信息接口
|
|
23
14
|
export interface ModelProgressInfo {
|
|
@@ -11,8 +11,10 @@ import {
|
|
|
11
11
|
TraceNameMap,
|
|
12
12
|
UIChatMessage,
|
|
13
13
|
} from '@lobechat/types';
|
|
14
|
+
import isEqual from 'fast-deep-equal';
|
|
14
15
|
import { t } from 'i18next';
|
|
15
16
|
import { produce } from 'immer';
|
|
17
|
+
import { throttle } from 'lodash-es';
|
|
16
18
|
import { StateCreator } from 'zustand/vanilla';
|
|
17
19
|
|
|
18
20
|
import { chatService } from '@/services/chat';
|
|
@@ -442,6 +444,19 @@ export const generateAIChat: StateCreator<
|
|
|
442
444
|
// to upload image
|
|
443
445
|
const uploadTasks: Map<string, Promise<{ id?: string; url?: string }>> = new Map();
|
|
444
446
|
|
|
447
|
+
// Throttle tool_calls updates to prevent excessive re-renders (max once per 300ms)
|
|
448
|
+
const throttledUpdateToolCalls = throttle(
|
|
449
|
+
(toolCalls: any[]) => {
|
|
450
|
+
internal_dispatchMessage({
|
|
451
|
+
id: messageId,
|
|
452
|
+
type: 'updateMessage',
|
|
453
|
+
value: { tools: get().internal_transformToolCalls(toolCalls) },
|
|
454
|
+
});
|
|
455
|
+
},
|
|
456
|
+
300,
|
|
457
|
+
{ leading: true, trailing: true },
|
|
458
|
+
);
|
|
459
|
+
|
|
445
460
|
const historySummary = chatConfig.enableCompressHistory
|
|
446
461
|
? topicSelectors.currentActiveTopicSummary(get())
|
|
447
462
|
: undefined;
|
|
@@ -495,6 +510,8 @@ export const generateAIChat: StateCreator<
|
|
|
495
510
|
|
|
496
511
|
let parsedToolCalls = toolCalls;
|
|
497
512
|
if (parsedToolCalls && parsedToolCalls.length > 0) {
|
|
513
|
+
// Flush any pending throttled updates before finalizing
|
|
514
|
+
throttledUpdateToolCalls.flush();
|
|
498
515
|
internal_toggleToolCallingStreaming(messageId, undefined);
|
|
499
516
|
parsedToolCalls = parsedToolCalls.map((item) => ({
|
|
500
517
|
...item,
|
|
@@ -506,6 +523,8 @@ export const generateAIChat: StateCreator<
|
|
|
506
523
|
isFunctionCall = true;
|
|
507
524
|
}
|
|
508
525
|
|
|
526
|
+
internal_toggleChatReasoning(false, messageId, n('toggleChatReasoning/false') as string);
|
|
527
|
+
|
|
509
528
|
// update the content after fetch result
|
|
510
529
|
await internal_updateMessageContent(messageId, content, {
|
|
511
530
|
toolCalls: parsedToolCalls,
|
|
@@ -615,12 +634,17 @@ export const generateAIChat: StateCreator<
|
|
|
615
634
|
// is this message is just a tool call
|
|
616
635
|
case 'tool_calls': {
|
|
617
636
|
internal_toggleToolCallingStreaming(messageId, chunk.isAnimationActives);
|
|
618
|
-
|
|
619
|
-
id: messageId,
|
|
620
|
-
type: 'updateMessage',
|
|
621
|
-
value: { tools: get().internal_transformToolCalls(chunk.tool_calls) },
|
|
622
|
-
});
|
|
637
|
+
throttledUpdateToolCalls(chunk.tool_calls);
|
|
623
638
|
isFunctionCall = true;
|
|
639
|
+
const isInChatReasoning =
|
|
640
|
+
messageStateSelectors.isMessageInChatReasoning(messageId)(get());
|
|
641
|
+
if (isInChatReasoning) {
|
|
642
|
+
internal_toggleChatReasoning(
|
|
643
|
+
false,
|
|
644
|
+
messageId,
|
|
645
|
+
n('toggleChatReasoning/false') as string,
|
|
646
|
+
);
|
|
647
|
+
}
|
|
624
648
|
}
|
|
625
649
|
}
|
|
626
650
|
},
|
|
@@ -690,16 +714,19 @@ export const generateAIChat: StateCreator<
|
|
|
690
714
|
return get().internal_toggleLoadingArrays('reasoningLoadingIds', loading, id, action);
|
|
691
715
|
},
|
|
692
716
|
internal_toggleToolCallingStreaming: (id, streaming) => {
|
|
717
|
+
const previous = get().toolCallingStreamIds;
|
|
718
|
+
const next = produce(previous, (draft) => {
|
|
719
|
+
if (!!streaming) {
|
|
720
|
+
draft[id] = streaming;
|
|
721
|
+
} else {
|
|
722
|
+
delete draft[id];
|
|
723
|
+
}
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
if (isEqual(previous, next)) return;
|
|
727
|
+
|
|
693
728
|
set(
|
|
694
|
-
{
|
|
695
|
-
toolCallingStreamIds: produce(get().toolCallingStreamIds, (draft) => {
|
|
696
|
-
if (!!streaming) {
|
|
697
|
-
draft[id] = streaming;
|
|
698
|
-
} else {
|
|
699
|
-
delete draft[id];
|
|
700
|
-
}
|
|
701
|
-
}),
|
|
702
|
-
},
|
|
729
|
+
{ toolCallingStreamIds: next },
|
|
703
730
|
|
|
704
731
|
false,
|
|
705
732
|
`toggleToolCallingStreaming/${!!streaming ? 'start' : 'end'}`,
|
|
@@ -4,25 +4,19 @@ import { createWithEqualityFn } from 'zustand/traditional';
|
|
|
4
4
|
import { StateCreator } from 'zustand/vanilla';
|
|
5
5
|
|
|
6
6
|
import { createDevtools } from '../middleware/createDevtools';
|
|
7
|
-
import { type GlobalClientDBAction, clientDBSlice } from './actions/clientDb';
|
|
8
7
|
import { type GlobalGeneralAction, generalActionSlice } from './actions/general';
|
|
9
8
|
import { type GlobalWorkspacePaneAction, globalWorkspaceSlice } from './actions/workspacePane';
|
|
10
9
|
import { type GlobalState, initialState } from './initialState';
|
|
11
10
|
|
|
12
11
|
// =============== 聚合 createStoreFn ============ //
|
|
13
12
|
|
|
14
|
-
export interface GlobalStore
|
|
15
|
-
extends GlobalState,
|
|
16
|
-
GlobalWorkspacePaneAction,
|
|
17
|
-
GlobalClientDBAction,
|
|
18
|
-
GlobalGeneralAction {
|
|
13
|
+
export interface GlobalStore extends GlobalState, GlobalWorkspacePaneAction, GlobalGeneralAction {
|
|
19
14
|
/* empty */
|
|
20
15
|
}
|
|
21
16
|
|
|
22
17
|
const createStore: StateCreator<GlobalStore, [['zustand/devtools', never]]> = (...parameters) => ({
|
|
23
18
|
...initialState,
|
|
24
19
|
...globalWorkspaceSlice(...parameters),
|
|
25
|
-
...clientDBSlice(...parameters),
|
|
26
20
|
...generalActionSlice(...parameters),
|
|
27
21
|
});
|
|
28
22
|
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
import { UserAuthState, initialAuthState } from './slices/auth/initialState';
|
|
2
2
|
import { CommonState, initialCommonState } from './slices/common/initialState';
|
|
3
|
-
import { ModelListState, initialModelListState } from './slices/modelList/initialState';
|
|
4
3
|
import { UserPreferenceState, initialPreferenceState } from './slices/preference/initialState';
|
|
5
4
|
import { UserSettingsState, initialSettingsState } from './slices/settings/initialState';
|
|
6
5
|
|
|
7
|
-
export type UserState = UserSettingsState &
|
|
8
|
-
UserPreferenceState &
|
|
9
|
-
UserAuthState &
|
|
10
|
-
ModelListState &
|
|
11
|
-
CommonState;
|
|
6
|
+
export type UserState = UserSettingsState & UserPreferenceState & UserAuthState & CommonState;
|
|
12
7
|
|
|
13
8
|
export const initialState: UserState = {
|
|
14
9
|
...initialSettingsState,
|
|
15
10
|
...initialPreferenceState,
|
|
16
11
|
...initialAuthState,
|
|
17
12
|
...initialCommonState,
|
|
18
|
-
...initialModelListState,
|
|
19
13
|
};
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
export { authSelectors, userProfileSelectors } from './slices/auth/selectors';
|
|
2
|
-
export {
|
|
3
|
-
keyVaultsConfigSelectors,
|
|
4
|
-
modelConfigSelectors,
|
|
5
|
-
modelProviderSelectors,
|
|
6
|
-
} from './slices/modelList/selectors';
|
|
7
2
|
export { preferenceSelectors } from './slices/preference/selectors';
|
|
8
3
|
export {
|
|
4
|
+
keyVaultsConfigSelectors,
|
|
9
5
|
settingsSelectors,
|
|
10
6
|
systemAgentSelectors,
|
|
11
7
|
userGeneralSettingsSelectors,
|
|
@@ -24,6 +24,7 @@ const GET_USER_STATE_KEY = 'initUserState';
|
|
|
24
24
|
export interface CommonAction {
|
|
25
25
|
refreshUserState: () => Promise<void>;
|
|
26
26
|
updateAvatar: (avatar: string) => Promise<void>;
|
|
27
|
+
updateKeyVaultConfig: (provider: string, config: any) => Promise<void>;
|
|
27
28
|
useCheckTrace: (shouldFetch: boolean) => SWRResponse;
|
|
28
29
|
useInitUserState: (
|
|
29
30
|
isLogin: boolean | undefined,
|
|
@@ -50,6 +51,10 @@ export const createCommonSlice: StateCreator<
|
|
|
50
51
|
await get().refreshUserState();
|
|
51
52
|
},
|
|
52
53
|
|
|
54
|
+
updateKeyVaultConfig: async (provider, config) => {
|
|
55
|
+
await get().setSettings({ keyVaults: { [provider]: config } });
|
|
56
|
+
},
|
|
57
|
+
|
|
53
58
|
useCheckTrace: (shouldFetch) =>
|
|
54
59
|
useSWR<boolean>(
|
|
55
60
|
shouldFetch ? 'checkTrace' : null,
|
|
@@ -65,7 +70,6 @@ export const createCommonSlice: StateCreator<
|
|
|
65
70
|
revalidateOnFocus: false,
|
|
66
71
|
},
|
|
67
72
|
),
|
|
68
|
-
|
|
69
73
|
useInitUserState: (isLogin, serverConfig, options) =>
|
|
70
74
|
useOnlyFetchOnceSWR<UserInitializationState>(
|
|
71
75
|
!!isLogin ? GET_USER_STATE_KEY : null,
|
|
@@ -79,7 +83,6 @@ export const createCommonSlice: StateCreator<
|
|
|
79
83
|
const serverSettings: PartialDeep<UserSettings> = {
|
|
80
84
|
defaultAgent: serverConfig.defaultAgent,
|
|
81
85
|
image: serverConfig.image,
|
|
82
|
-
languageModel: serverConfig.languageModel,
|
|
83
86
|
systemAgent: serverConfig.systemAgent,
|
|
84
87
|
};
|
|
85
88
|
|
|
@@ -112,7 +115,6 @@ export const createCommonSlice: StateCreator<
|
|
|
112
115
|
isUserHasConversation: data.hasConversation,
|
|
113
116
|
isUserStateInit: true,
|
|
114
117
|
preference,
|
|
115
|
-
serverLanguageModel: serverConfig.languageModel,
|
|
116
118
|
settings: data.settings || {},
|
|
117
119
|
subscriptionPlan: data.subscriptionPlan,
|
|
118
120
|
user,
|
|
@@ -128,7 +130,6 @@ export const createCommonSlice: StateCreator<
|
|
|
128
130
|
lastName: data.lastName,
|
|
129
131
|
username: data.username,
|
|
130
132
|
});
|
|
131
|
-
get().refreshDefaultModelProviderList({ trigger: 'fetchUserState' });
|
|
132
133
|
}
|
|
133
134
|
},
|
|
134
135
|
},
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { UserStore } from '@/store/user';
|
|
2
|
+
import { UserKeyVaults } from '@/types/user/settings';
|
|
3
|
+
|
|
4
|
+
import { currentSettings } from './settings';
|
|
5
|
+
|
|
6
|
+
export const keyVaultsSettings = (s: UserStore): UserKeyVaults =>
|
|
7
|
+
currentSettings(s).keyVaults || {};
|
|
8
|
+
|
|
9
|
+
const getVaultByProvider = (provider: string) => (s: UserStore) =>
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
(keyVaultsSettings(s)[provider] || {}) as any;
|
|
12
|
+
|
|
13
|
+
const password = (s: UserStore) => keyVaultsSettings(s).password || '';
|
|
14
|
+
|
|
15
|
+
export const keyVaultsConfigSelectors = {
|
|
16
|
+
getVaultByProvider,
|
|
17
|
+
|
|
18
|
+
keyVaultsSettings,
|
|
19
|
+
|
|
20
|
+
password,
|
|
21
|
+
};
|
package/src/store/user/store.ts
CHANGED
|
@@ -7,7 +7,6 @@ import { createDevtools } from '../middleware/createDevtools';
|
|
|
7
7
|
import { type UserState, initialState } from './initialState';
|
|
8
8
|
import { type UserAuthAction, createAuthSlice } from './slices/auth/action';
|
|
9
9
|
import { type CommonAction, createCommonSlice } from './slices/common/action';
|
|
10
|
-
import { type ModelListAction, createModelListSlice } from './slices/modelList/action';
|
|
11
10
|
import { type PreferenceAction, createPreferenceSlice } from './slices/preference/action';
|
|
12
11
|
import { type UserSettingsAction, createSettingsSlice } from './slices/settings/action';
|
|
13
12
|
|
|
@@ -16,7 +15,6 @@ import { type UserSettingsAction, createSettingsSlice } from './slices/settings/
|
|
|
16
15
|
export type UserStore = UserState &
|
|
17
16
|
UserSettingsAction &
|
|
18
17
|
PreferenceAction &
|
|
19
|
-
ModelListAction &
|
|
20
18
|
UserAuthAction &
|
|
21
19
|
CommonAction;
|
|
22
20
|
|
|
@@ -26,7 +24,6 @@ const createStore: StateCreator<UserStore, [['zustand/devtools', never]]> = (...
|
|
|
26
24
|
...createPreferenceSlice(...parameters),
|
|
27
25
|
...createAuthSlice(...parameters),
|
|
28
26
|
...createCommonSlice(...parameters),
|
|
29
|
-
...createModelListSlice(...parameters),
|
|
30
27
|
});
|
|
31
28
|
|
|
32
29
|
// =============== 实装 useStore ============ //
|
|
@@ -23,7 +23,7 @@ const Form = memo<ProviderApiKeyFormProps>(({ provider, id }) => {
|
|
|
23
23
|
const [apiKey, baseURL, setConfig] = useUserStore((s) => [
|
|
24
24
|
keyVaultsConfigSelectors.getVaultByProvider(provider as any)(s)?.apiKey,
|
|
25
25
|
keyVaultsConfigSelectors.getVaultByProvider(provider as any)(s)?.baseURL,
|
|
26
|
-
s.
|
|
26
|
+
s.updateKeyVaultConfig,
|
|
27
27
|
]);
|
|
28
28
|
|
|
29
29
|
const [showKey, setShow] = useState(false);
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
-
|
|
3
|
-
exports[`parseModelString > custom deletion, addition, and renaming of models 1`] = `
|
|
4
|
-
{
|
|
5
|
-
"add": [
|
|
6
|
-
{
|
|
7
|
-
"displayName": undefined,
|
|
8
|
-
"id": "llama",
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
"displayName": undefined,
|
|
12
|
-
"id": "claude-2",
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"displayName": "gpt-4-32k",
|
|
16
|
-
"id": "gpt-4-1106-preview",
|
|
17
|
-
},
|
|
18
|
-
],
|
|
19
|
-
"removeAll": true,
|
|
20
|
-
"removed": [
|
|
21
|
-
"all",
|
|
22
|
-
"gpt-3.5-turbo",
|
|
23
|
-
],
|
|
24
|
-
}
|
|
25
|
-
`;
|
|
26
|
-
|
|
27
|
-
exports[`parseModelString > duplicate naming model 1`] = `
|
|
28
|
-
{
|
|
29
|
-
"add": [
|
|
30
|
-
{
|
|
31
|
-
"displayName": "gpt-4-32k",
|
|
32
|
-
"id": "gpt-4-1106-preview",
|
|
33
|
-
},
|
|
34
|
-
],
|
|
35
|
-
"removeAll": false,
|
|
36
|
-
"removed": [],
|
|
37
|
-
}
|
|
38
|
-
`;
|
|
39
|
-
|
|
40
|
-
exports[`parseModelString > empty string model 1`] = `
|
|
41
|
-
{
|
|
42
|
-
"add": [
|
|
43
|
-
{
|
|
44
|
-
"displayName": "gpt-4-turbo",
|
|
45
|
-
"id": "gpt-4-1106-preview",
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
"displayName": undefined,
|
|
49
|
-
"id": "claude-2",
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
"removeAll": false,
|
|
53
|
-
"removed": [],
|
|
54
|
-
}
|
|
55
|
-
`;
|
|
56
|
-
|
|
57
|
-
exports[`parseModelString > only add the model 1`] = `
|
|
58
|
-
{
|
|
59
|
-
"add": [
|
|
60
|
-
{
|
|
61
|
-
"displayName": undefined,
|
|
62
|
-
"id": "model1",
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
"displayName": undefined,
|
|
66
|
-
"id": "model2",
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
"displayName": undefined,
|
|
70
|
-
"id": "model3",
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
"displayName": undefined,
|
|
74
|
-
"id": "model4",
|
|
75
|
-
},
|
|
76
|
-
],
|
|
77
|
-
"removeAll": false,
|
|
78
|
-
"removed": [],
|
|
79
|
-
}
|
|
80
|
-
`;
|
|
81
|
-
|
|
82
|
-
exports[`transformToChatModelCards > should have file with builtin models like gpt-4-0125-preview 1`] = `
|
|
83
|
-
[
|
|
84
|
-
{
|
|
85
|
-
"contextWindowTokens": 128000,
|
|
86
|
-
"description": "最新的 GPT-4 Turbo 模型具备视觉功能。现在,视觉请求可以使用 JSON 模式和函数调用。 GPT-4 Turbo 是一个增强版本,为多模态任务提供成本效益高的支持。它在准确性和效率之间找到平衡,适合需要进行实时交互的应用程序场景。",
|
|
87
|
-
"displayName": "ChatGPT-4",
|
|
88
|
-
"enabled": true,
|
|
89
|
-
"files": true,
|
|
90
|
-
"functionCall": true,
|
|
91
|
-
"id": "gpt-4-0125-preview",
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
"contextWindowTokens": 128000,
|
|
95
|
-
"description": "最新的 GPT-4 Turbo 模型具备视觉功能。现在,视觉请求可以使用 JSON 模式和函数调用。 GPT-4 Turbo 是一个增强版本,为多模态任务提供成本效益高的支持。它在准确性和效率之间找到平衡,适合需要进行实时交互的应用程序场景。",
|
|
96
|
-
"displayName": "ChatGPT-4 Vision",
|
|
97
|
-
"enabled": true,
|
|
98
|
-
"files": true,
|
|
99
|
-
"functionCall": true,
|
|
100
|
-
"id": "gpt-4-turbo-2024-04-09",
|
|
101
|
-
"vision": true,
|
|
102
|
-
},
|
|
103
|
-
]
|
|
104
|
-
`;
|