@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
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { ChatModelCard } from '@/types/llm';
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
AddCustomModelCard,
|
|
7
|
-
DeleteCustomModelCard,
|
|
8
|
-
UpdateCustomModelCard,
|
|
9
|
-
customModelCardsReducer,
|
|
10
|
-
} from './customModelCard';
|
|
11
|
-
|
|
12
|
-
describe('customModelCardsReducer', () => {
|
|
13
|
-
const initialState: ChatModelCard[] = [
|
|
14
|
-
{
|
|
15
|
-
id: 'model1',
|
|
16
|
-
displayName: 'Model 1',
|
|
17
|
-
description: 'A helpful assistant',
|
|
18
|
-
files: true,
|
|
19
|
-
functionCall: false,
|
|
20
|
-
enabled: true,
|
|
21
|
-
isCustom: true,
|
|
22
|
-
legacy: false,
|
|
23
|
-
maxOutput: 1000,
|
|
24
|
-
contextWindowTokens: 2048,
|
|
25
|
-
vision: false,
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
id: 'model2',
|
|
29
|
-
displayName: 'Model 2',
|
|
30
|
-
description: 'A friendly chatbot',
|
|
31
|
-
files: false,
|
|
32
|
-
functionCall: true,
|
|
33
|
-
isCustom: true,
|
|
34
|
-
legacy: true,
|
|
35
|
-
maxOutput: 500,
|
|
36
|
-
contextWindowTokens: 1024,
|
|
37
|
-
vision: true,
|
|
38
|
-
},
|
|
39
|
-
];
|
|
40
|
-
|
|
41
|
-
it('should add a new custom model card', () => {
|
|
42
|
-
const newModelCard: ChatModelCard = {
|
|
43
|
-
id: 'model3',
|
|
44
|
-
displayName: 'Model 3',
|
|
45
|
-
description: 'A versatile assistant',
|
|
46
|
-
files: true,
|
|
47
|
-
functionCall: true,
|
|
48
|
-
enabled: true,
|
|
49
|
-
isCustom: true,
|
|
50
|
-
legacy: false,
|
|
51
|
-
maxOutput: 2000,
|
|
52
|
-
contextWindowTokens: 4096,
|
|
53
|
-
vision: false,
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const action: AddCustomModelCard = {
|
|
57
|
-
type: 'add',
|
|
58
|
-
modelCard: newModelCard,
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const newState = customModelCardsReducer(initialState, action);
|
|
62
|
-
|
|
63
|
-
expect(newState).toContainEqual(newModelCard);
|
|
64
|
-
expect(newState.length).toBe(initialState.length + 1);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should not add a duplicate custom model card', () => {
|
|
68
|
-
const duplicateModelCard: ChatModelCard = {
|
|
69
|
-
id: 'model1',
|
|
70
|
-
displayName: 'Duplicate Model 1',
|
|
71
|
-
description: 'A duplicate model',
|
|
72
|
-
files: true,
|
|
73
|
-
functionCall: false,
|
|
74
|
-
enabled: true,
|
|
75
|
-
isCustom: true,
|
|
76
|
-
legacy: false,
|
|
77
|
-
maxOutput: 1000,
|
|
78
|
-
contextWindowTokens: 2048,
|
|
79
|
-
vision: false,
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const action: AddCustomModelCard = {
|
|
83
|
-
type: 'add',
|
|
84
|
-
modelCard: duplicateModelCard,
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const newState = customModelCardsReducer(initialState, action);
|
|
88
|
-
|
|
89
|
-
expect(newState).toEqual(initialState);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('should delete a custom model card', () => {
|
|
93
|
-
const action: DeleteCustomModelCard = {
|
|
94
|
-
type: 'delete',
|
|
95
|
-
id: 'model1',
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const newState = customModelCardsReducer(initialState, action);
|
|
99
|
-
|
|
100
|
-
expect(newState).not.toContainEqual(initialState[0]);
|
|
101
|
-
expect(newState.length).toBe(initialState.length - 1);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('should update a custom model card', () => {
|
|
105
|
-
const action: UpdateCustomModelCard = {
|
|
106
|
-
type: 'update',
|
|
107
|
-
id: 'model1',
|
|
108
|
-
value: { displayName: 'Updated Model 1' },
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
const newState = customModelCardsReducer(initialState, action);
|
|
112
|
-
|
|
113
|
-
expect(newState.find((card) => card.id === 'model1')?.displayName).toBe('Updated Model 1');
|
|
114
|
-
expect(newState.length).toBe(initialState.length);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('should throw an error for unhandled action type', () => {
|
|
118
|
-
const invalidAction = {
|
|
119
|
-
type: 'invalid',
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
expect(() => customModelCardsReducer(initialState, invalidAction as any)).toThrowError(
|
|
123
|
-
'Unhandled action type in customModelCardsReducer',
|
|
124
|
-
);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('should return the original state if the model card is not found during update', () => {
|
|
128
|
-
const action: UpdateCustomModelCard = {
|
|
129
|
-
type: 'update',
|
|
130
|
-
id: 'nonexistent',
|
|
131
|
-
value: { displayName: 'Updated Nonexistent Model' },
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const newState = customModelCardsReducer(initialState, action);
|
|
135
|
-
|
|
136
|
-
expect(newState).toEqual(initialState);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('should return the original state if the model card ID is missing during add', () => {
|
|
140
|
-
const newModelCard: ChatModelCard = {
|
|
141
|
-
id: '',
|
|
142
|
-
displayName: 'Model 4',
|
|
143
|
-
description: 'A new model',
|
|
144
|
-
files: false,
|
|
145
|
-
functionCall: false,
|
|
146
|
-
enabled: true,
|
|
147
|
-
isCustom: true,
|
|
148
|
-
legacy: false,
|
|
149
|
-
maxOutput: 1500,
|
|
150
|
-
contextWindowTokens: 2048,
|
|
151
|
-
vision: false,
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
const action: AddCustomModelCard = {
|
|
155
|
-
type: 'add',
|
|
156
|
-
modelCard: newModelCard,
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
const newState = customModelCardsReducer(initialState, action);
|
|
160
|
-
|
|
161
|
-
expect(newState).toEqual(initialState);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('should handle optional properties correctly', () => {
|
|
165
|
-
const newModelCard: ChatModelCard = {
|
|
166
|
-
id: 'model4',
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
const action: AddCustomModelCard = {
|
|
170
|
-
type: 'add',
|
|
171
|
-
modelCard: newModelCard,
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
const newState = customModelCardsReducer(initialState, action);
|
|
175
|
-
|
|
176
|
-
expect(newState).toContainEqual(newModelCard);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it('should handle an undefined initial state', () => {
|
|
180
|
-
const newModelCard: ChatModelCard = {
|
|
181
|
-
id: 'model4',
|
|
182
|
-
displayName: 'Model 4',
|
|
183
|
-
description: 'A new model',
|
|
184
|
-
files: false,
|
|
185
|
-
functionCall: false,
|
|
186
|
-
enabled: true,
|
|
187
|
-
isCustom: true,
|
|
188
|
-
legacy: false,
|
|
189
|
-
maxOutput: 1500,
|
|
190
|
-
contextWindowTokens: 2048,
|
|
191
|
-
vision: false,
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
const action: AddCustomModelCard = {
|
|
195
|
-
type: 'add',
|
|
196
|
-
modelCard: newModelCard,
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
const newState = customModelCardsReducer(undefined, action);
|
|
200
|
-
|
|
201
|
-
expect(newState).toContainEqual(newModelCard);
|
|
202
|
-
expect(newState.length).toBe(1);
|
|
203
|
-
});
|
|
204
|
-
});
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { produce } from 'immer';
|
|
2
|
-
|
|
3
|
-
import { ChatModelCard } from '@/types/llm';
|
|
4
|
-
|
|
5
|
-
export interface AddCustomModelCard {
|
|
6
|
-
modelCard: ChatModelCard;
|
|
7
|
-
type: 'add';
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface DeleteCustomModelCard {
|
|
11
|
-
id: string;
|
|
12
|
-
type: 'delete';
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface UpdateCustomModelCard {
|
|
16
|
-
id: string;
|
|
17
|
-
type: 'update';
|
|
18
|
-
value: Partial<ChatModelCard>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type CustomModelCardDispatch =
|
|
22
|
-
| AddCustomModelCard
|
|
23
|
-
| DeleteCustomModelCard
|
|
24
|
-
| UpdateCustomModelCard;
|
|
25
|
-
|
|
26
|
-
export const customModelCardsReducer = (
|
|
27
|
-
state: ChatModelCard[] | undefined,
|
|
28
|
-
payload: CustomModelCardDispatch,
|
|
29
|
-
): ChatModelCard[] => {
|
|
30
|
-
switch (payload.type) {
|
|
31
|
-
case 'add': {
|
|
32
|
-
return produce(state || [], (draftState) => {
|
|
33
|
-
const { id } = payload.modelCard;
|
|
34
|
-
if (!id) return;
|
|
35
|
-
if (draftState.some((card) => card.id === id)) return;
|
|
36
|
-
|
|
37
|
-
draftState.push(payload.modelCard);
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
case 'delete': {
|
|
42
|
-
return produce(state || [], (draftState) => {
|
|
43
|
-
const index = draftState.findIndex((card) => card.id === payload.id);
|
|
44
|
-
if (index !== -1) {
|
|
45
|
-
draftState.splice(index, 1);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
case 'update': {
|
|
51
|
-
return produce(state || [], (draftState) => {
|
|
52
|
-
const index = draftState.findIndex((card) => card.id === payload.id);
|
|
53
|
-
if (index !== -1) {
|
|
54
|
-
const card = draftState[index];
|
|
55
|
-
Object.assign(card, payload.value);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
default: {
|
|
61
|
-
throw new Error('Unhandled action type in customModelCardsReducer');
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
};
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { UserStore } from '@/store/user';
|
|
4
|
-
import {
|
|
5
|
-
AWSBedrockKeyVault,
|
|
6
|
-
AzureOpenAIKeyVault,
|
|
7
|
-
OpenAICompatibleKeyVault,
|
|
8
|
-
} from '@/types/user/settings';
|
|
9
|
-
import { merge } from '@/utils/merge';
|
|
10
|
-
|
|
11
|
-
import { initialSettingsState } from '../../settings/initialState';
|
|
12
|
-
import { keyVaultsConfigSelectors } from './keyVaults';
|
|
13
|
-
|
|
14
|
-
describe('keyVaultsConfigSelectors', () => {
|
|
15
|
-
describe('isProviderEndpointNotEmpty', () => {
|
|
16
|
-
describe('OpenAICompatibleKeyVault', () => {
|
|
17
|
-
it('should return true if provider endpoint is not empty', () => {
|
|
18
|
-
const s = merge(initialSettingsState, {
|
|
19
|
-
settings: {
|
|
20
|
-
keyVaults: {
|
|
21
|
-
openai: {
|
|
22
|
-
endpoint: 'endpoint',
|
|
23
|
-
} as OpenAICompatibleKeyVault,
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
}) as unknown as UserStore;
|
|
27
|
-
expect(keyVaultsConfigSelectors.isProviderEndpointNotEmpty('openai')(s)).toBe(true);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should return false if provider endpoint is empty', () => {
|
|
31
|
-
const s = merge(initialSettingsState, {
|
|
32
|
-
settings: {
|
|
33
|
-
keyVaults: {
|
|
34
|
-
openai: {
|
|
35
|
-
endpoint: undefined,
|
|
36
|
-
} as OpenAICompatibleKeyVault,
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
}) as unknown as UserStore;
|
|
40
|
-
expect(keyVaultsConfigSelectors.isProviderEndpointNotEmpty('openai')(s)).toBe(false);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('AzureOpenAIKeyVault', () => {
|
|
45
|
-
it('should return true if provider endpoint is not empty', () => {
|
|
46
|
-
const s = merge(initialSettingsState, {
|
|
47
|
-
settings: {
|
|
48
|
-
keyVaults: {
|
|
49
|
-
azure: {
|
|
50
|
-
baseURL: 'baseURL',
|
|
51
|
-
} as AzureOpenAIKeyVault,
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
}) as unknown as UserStore;
|
|
55
|
-
expect(keyVaultsConfigSelectors.isProviderEndpointNotEmpty('azure')(s)).toBe(true);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should return false if provider endpoint is empty', () => {
|
|
59
|
-
const s = merge(initialSettingsState, {
|
|
60
|
-
settings: {
|
|
61
|
-
keyVaults: {
|
|
62
|
-
azure: {
|
|
63
|
-
baseURL: undefined,
|
|
64
|
-
} as AzureOpenAIKeyVault,
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
}) as unknown as UserStore;
|
|
68
|
-
expect(keyVaultsConfigSelectors.isProviderEndpointNotEmpty('azure')(s)).toBe(false);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
// Always return false for AWSBedrockKeyVault
|
|
73
|
-
describe('AWSBedrockKeyVault', () => {
|
|
74
|
-
it('should return false if provider region is not empty for AWSBedrockKeyVault', () => {
|
|
75
|
-
const s = merge(initialSettingsState, {
|
|
76
|
-
settings: {
|
|
77
|
-
keyVaults: {
|
|
78
|
-
bedrock: {
|
|
79
|
-
region: 'region',
|
|
80
|
-
} as AWSBedrockKeyVault,
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
}) as unknown as UserStore;
|
|
84
|
-
expect(keyVaultsConfigSelectors.isProviderEndpointNotEmpty('bedrock')(s)).toBe(false);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should return false if provider region is empty for AWSBedrockKeyVault', () => {
|
|
88
|
-
const s = merge(initialSettingsState, {
|
|
89
|
-
settings: {
|
|
90
|
-
keyVaults: {
|
|
91
|
-
bedrock: {
|
|
92
|
-
region: undefined,
|
|
93
|
-
} as AWSBedrockKeyVault,
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
}) as unknown as UserStore;
|
|
97
|
-
expect(keyVaultsConfigSelectors.isProviderEndpointNotEmpty('bedrock')(s)).toBe(false);
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
describe('isProviderApiKeyNotEmpty', () => {
|
|
103
|
-
describe('OpenAICompatibleKeyVault', () => {
|
|
104
|
-
it('should return true if provider apikey is not empty', () => {
|
|
105
|
-
const s = merge(initialSettingsState, {
|
|
106
|
-
settings: {
|
|
107
|
-
keyVaults: {
|
|
108
|
-
openai: {
|
|
109
|
-
apiKey: 'apikey',
|
|
110
|
-
} as OpenAICompatibleKeyVault,
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
}) as unknown as UserStore;
|
|
114
|
-
expect(keyVaultsConfigSelectors.isProviderApiKeyNotEmpty('openai')(s)).toBe(true);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('should return false if provider apikey is empty', () => {
|
|
118
|
-
const s = merge(initialSettingsState, {
|
|
119
|
-
settings: {
|
|
120
|
-
keyVaults: {
|
|
121
|
-
openai: {
|
|
122
|
-
apiKey: undefined,
|
|
123
|
-
} as OpenAICompatibleKeyVault,
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
}) as unknown as UserStore;
|
|
127
|
-
expect(keyVaultsConfigSelectors.isProviderApiKeyNotEmpty('openai')(s)).toBe(false);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe('AzureOpenAIKeyVault', () => {
|
|
132
|
-
it('should return true if provider apikey is not empty', () => {
|
|
133
|
-
const s = merge(initialSettingsState, {
|
|
134
|
-
settings: {
|
|
135
|
-
keyVaults: {
|
|
136
|
-
azure: {
|
|
137
|
-
apiKey: 'apikey',
|
|
138
|
-
} as AzureOpenAIKeyVault,
|
|
139
|
-
},
|
|
140
|
-
},
|
|
141
|
-
}) as unknown as UserStore;
|
|
142
|
-
expect(keyVaultsConfigSelectors.isProviderApiKeyNotEmpty('azure')(s)).toBe(true);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('should return false if provider apikey is empty', () => {
|
|
146
|
-
const s = merge(initialSettingsState, {
|
|
147
|
-
settings: {
|
|
148
|
-
keyVaults: {
|
|
149
|
-
azure: {
|
|
150
|
-
apiKey: undefined,
|
|
151
|
-
} as AzureOpenAIKeyVault,
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
}) as unknown as UserStore;
|
|
155
|
-
expect(keyVaultsConfigSelectors.isProviderApiKeyNotEmpty('azure')(s)).toBe(false);
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
describe('AWSBedrockKeyVault', () => {
|
|
160
|
-
it('should return true if provider accessKeyId is not empty for AWSBedrockKeyVault', () => {
|
|
161
|
-
const s = merge(initialSettingsState, {
|
|
162
|
-
settings: {
|
|
163
|
-
keyVaults: {
|
|
164
|
-
bedrock: {
|
|
165
|
-
accessKeyId: 'accessKeyId',
|
|
166
|
-
} as AWSBedrockKeyVault,
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
}) as unknown as UserStore;
|
|
170
|
-
expect(keyVaultsConfigSelectors.isProviderApiKeyNotEmpty('bedrock')(s)).toBe(true);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
it('should return true if provider secretAccessKey is not empty for AWSBedrockKeyVault', () => {
|
|
174
|
-
const s = merge(initialSettingsState, {
|
|
175
|
-
settings: {
|
|
176
|
-
keyVaults: {
|
|
177
|
-
bedrock: {
|
|
178
|
-
secretAccessKey: 'secretAccessKey',
|
|
179
|
-
} as AWSBedrockKeyVault,
|
|
180
|
-
},
|
|
181
|
-
},
|
|
182
|
-
}) as unknown as UserStore;
|
|
183
|
-
expect(keyVaultsConfigSelectors.isProviderApiKeyNotEmpty('bedrock')(s)).toBe(true);
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('should return false if provider accessKeyId and secretAccessKey are both empty for AWSBedrockKeyVault', () => {
|
|
187
|
-
const s = merge(initialSettingsState, {
|
|
188
|
-
settings: {
|
|
189
|
-
keyVaults: {
|
|
190
|
-
bedrock: {
|
|
191
|
-
accessKeyId: undefined,
|
|
192
|
-
secretAccessKey: undefined,
|
|
193
|
-
} as AWSBedrockKeyVault,
|
|
194
|
-
},
|
|
195
|
-
},
|
|
196
|
-
}) as unknown as UserStore;
|
|
197
|
-
expect(keyVaultsConfigSelectors.isProviderApiKeyNotEmpty('bedrock')(s)).toBe(false);
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
});
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { UserStore } from '@/store/user';
|
|
2
|
-
import {
|
|
3
|
-
AWSBedrockKeyVault,
|
|
4
|
-
AzureOpenAIKeyVault,
|
|
5
|
-
ComfyUIKeyVault,
|
|
6
|
-
GlobalLLMProviderKey,
|
|
7
|
-
OpenAICompatibleKeyVault,
|
|
8
|
-
UserKeyVaults,
|
|
9
|
-
} from '@/types/user/settings';
|
|
10
|
-
|
|
11
|
-
import { currentSettings } from '../../settings/selectors/settings';
|
|
12
|
-
|
|
13
|
-
export const keyVaultsSettings = (s: UserStore): UserKeyVaults =>
|
|
14
|
-
currentSettings(s).keyVaults || {};
|
|
15
|
-
|
|
16
|
-
const openAIConfig = (s: UserStore) => keyVaultsSettings(s).openai || {};
|
|
17
|
-
const bedrockConfig = (s: UserStore) => keyVaultsSettings(s).bedrock || {};
|
|
18
|
-
const ollamaConfig = (s: UserStore) => keyVaultsSettings(s).ollama || {};
|
|
19
|
-
const azureConfig = (s: UserStore) => keyVaultsSettings(s).azure || {};
|
|
20
|
-
const cloudflareConfig = (s: UserStore) => keyVaultsSettings(s).cloudflare || {};
|
|
21
|
-
const getVaultByProvider = (provider: GlobalLLMProviderKey) => (s: UserStore) =>
|
|
22
|
-
(keyVaultsSettings(s)[provider] || {}) as OpenAICompatibleKeyVault &
|
|
23
|
-
AzureOpenAIKeyVault &
|
|
24
|
-
AWSBedrockKeyVault &
|
|
25
|
-
ComfyUIKeyVault;
|
|
26
|
-
|
|
27
|
-
const isProviderEndpointNotEmpty = (provider: string) => (s: UserStore) => {
|
|
28
|
-
const vault = getVaultByProvider(provider as GlobalLLMProviderKey)(s);
|
|
29
|
-
return !!vault?.baseURL || !!vault?.endpoint;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const isProviderApiKeyNotEmpty = (provider: string) => (s: UserStore) => {
|
|
33
|
-
const vault = getVaultByProvider(provider as GlobalLLMProviderKey)(s);
|
|
34
|
-
return !!vault?.apiKey || !!vault?.accessKeyId || !!vault?.secretAccessKey;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const password = (s: UserStore) => keyVaultsSettings(s).password || '';
|
|
38
|
-
|
|
39
|
-
export const keyVaultsConfigSelectors = {
|
|
40
|
-
azureConfig,
|
|
41
|
-
bedrockConfig,
|
|
42
|
-
cloudflareConfig,
|
|
43
|
-
getVaultByProvider,
|
|
44
|
-
isProviderApiKeyNotEmpty,
|
|
45
|
-
isProviderEndpointNotEmpty,
|
|
46
|
-
keyVaultsSettings,
|
|
47
|
-
ollamaConfig,
|
|
48
|
-
openAIConfig,
|
|
49
|
-
password,
|
|
50
|
-
};
|