@lobehub/chat 1.53.7 → 1.53.9
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/changelog/v1.json +18 -0
- package/docs/self-hosting/advanced/model-list.mdx +9 -7
- package/docs/self-hosting/advanced/model-list.zh-CN.mdx +9 -7
- package/locales/ar/modelProvider.json +5 -0
- package/locales/bg-BG/modelProvider.json +5 -0
- package/locales/de-DE/modelProvider.json +5 -0
- package/locales/en-US/modelProvider.json +5 -0
- package/locales/es-ES/modelProvider.json +5 -0
- package/locales/fa-IR/modelProvider.json +5 -0
- package/locales/fr-FR/modelProvider.json +5 -0
- package/locales/it-IT/modelProvider.json +5 -0
- package/locales/ja-JP/modelProvider.json +5 -0
- package/locales/ko-KR/modelProvider.json +5 -0
- package/locales/nl-NL/modelProvider.json +5 -0
- package/locales/pl-PL/modelProvider.json +5 -0
- package/locales/pt-BR/modelProvider.json +5 -0
- package/locales/ru-RU/modelProvider.json +5 -0
- package/locales/tr-TR/modelProvider.json +5 -0
- package/locales/vi-VN/modelProvider.json +5 -0
- package/locales/zh-CN/auth.json +1 -1
- package/locales/zh-CN/changelog.json +1 -1
- package/locales/zh-CN/chat.json +1 -1
- package/locales/zh-CN/clerk.json +1 -1
- package/locales/zh-CN/common.json +1 -1
- package/locales/zh-CN/components.json +1 -1
- package/locales/zh-CN/discover.json +1 -1
- package/locales/zh-CN/error.json +1 -1
- package/locales/zh-CN/file.json +1 -1
- package/locales/zh-CN/knowledgeBase.json +1 -1
- package/locales/zh-CN/metadata.json +1 -1
- package/locales/zh-CN/migration.json +1 -1
- package/locales/zh-CN/modelProvider.json +6 -1
- package/locales/zh-CN/models.json +1049 -1049
- package/locales/zh-CN/plugin.json +1 -1
- package/locales/zh-CN/portal.json +1 -1
- package/locales/zh-CN/providers.json +70 -70
- package/locales/zh-CN/ragEval.json +1 -1
- package/locales/zh-CN/setting.json +1 -1
- package/locales/zh-CN/thread.json +1 -1
- package/locales/zh-CN/tool.json +1 -1
- package/locales/zh-CN/topic.json +1 -1
- package/locales/zh-CN/welcome.json +1 -1
- package/locales/zh-TW/modelProvider.json +5 -0
- package/package.json +1 -1
- package/src/app/[variants]/(main)/settings/provider/(detail)/azure/page.tsx +4 -8
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/ModelItem.tsx +67 -61
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/ModelTitle/index.tsx +37 -10
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/ProviderSettingsContext.ts +9 -0
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/index.tsx +27 -17
- package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/Checker.tsx +47 -26
- package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/index.tsx +5 -1
- package/src/config/modelProviders/spark.ts +2 -0
- package/src/const/version.ts +1 -2
- package/src/database/server/models/aiModel.ts +6 -0
- package/src/locales/default/modelProvider.ts +5 -0
- package/src/server/routers/lambda/aiModel.ts +5 -0
- package/src/services/aiModel/client.ts +4 -0
- package/src/services/aiModel/server.test.ts +122 -0
- package/src/services/aiModel/server.ts +4 -0
- package/src/services/aiModel/type.ts +2 -0
- package/src/store/aiInfra/slices/aiModel/action.ts +5 -0
- package/src/store/aiInfra/slices/aiModel/selectors.ts +3 -0
- package/src/types/aiProvider.ts +7 -1
@@ -1,18 +1,19 @@
|
|
1
1
|
'use client';
|
2
2
|
|
3
3
|
import { CheckCircleFilled } from '@ant-design/icons';
|
4
|
-
import {
|
5
|
-
import {
|
4
|
+
import { ModelIcon } from '@lobehub/icons';
|
5
|
+
import { Alert, Highlighter, Icon } from '@lobehub/ui';
|
6
|
+
import { Button, Select, Space } from 'antd';
|
6
7
|
import { useTheme } from 'antd-style';
|
8
|
+
import { Loader2Icon } from 'lucide-react';
|
7
9
|
import { ReactNode, memo, useState } from 'react';
|
8
10
|
import { useTranslation } from 'react-i18next';
|
9
11
|
import { Flexbox } from 'react-layout-kit';
|
10
12
|
|
11
13
|
import { TraceNameMap } from '@/const/trace';
|
12
|
-
import { useIsMobile } from '@/hooks/useIsMobile';
|
13
14
|
import { useProviderName } from '@/hooks/useProviderName';
|
14
15
|
import { chatService } from '@/services/chat';
|
15
|
-
import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
|
16
|
+
import { aiModelSelectors, aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
|
16
17
|
import { ChatMessageError } from '@/types/message';
|
17
18
|
|
18
19
|
const Error = memo<{ error: ChatMessageError }>(({ error }) => {
|
@@ -20,9 +21,8 @@ const Error = memo<{ error: ChatMessageError }>(({ error }) => {
|
|
20
21
|
const providerName = useProviderName(error.body?.provider);
|
21
22
|
|
22
23
|
return (
|
23
|
-
<Flexbox gap={8} style={{
|
24
|
+
<Flexbox gap={8} style={{ width: '100%' }}>
|
24
25
|
<Alert
|
25
|
-
banner
|
26
26
|
extra={
|
27
27
|
<Flexbox>
|
28
28
|
<Highlighter copyButtonSize={'small'} language={'json'} type={'pure'}>
|
@@ -54,10 +54,15 @@ const Checker = memo<ConnectionCheckerProps>(
|
|
54
54
|
({ model, provider, checkErrorRender: CheckErrorRender }) => {
|
55
55
|
const { t } = useTranslation('setting');
|
56
56
|
|
57
|
-
const
|
57
|
+
const isProviderConfigUpdating = useAiInfraStore(
|
58
|
+
aiProviderSelectors.isProviderConfigUpdating(provider),
|
59
|
+
);
|
60
|
+
const totalModels = useAiInfraStore(aiModelSelectors.aiProviderChatModelListIds);
|
61
|
+
const updateAiProviderConfig = useAiInfraStore((s) => s.updateAiProviderConfig);
|
58
62
|
|
59
63
|
const [loading, setLoading] = useState(false);
|
60
64
|
const [pass, setPass] = useState(false);
|
65
|
+
const [checkModel, setCheckModel] = useState(model);
|
61
66
|
|
62
67
|
const theme = useTheme();
|
63
68
|
const [error, setError] = useState<ChatMessageError | undefined>();
|
@@ -71,6 +76,7 @@ const Checker = memo<ConnectionCheckerProps>(
|
|
71
76
|
setPass(false);
|
72
77
|
isError = true;
|
73
78
|
},
|
79
|
+
|
74
80
|
onFinish: async (value) => {
|
75
81
|
if (!isError && value) {
|
76
82
|
setError(undefined);
|
@@ -104,7 +110,6 @@ const Checker = memo<ConnectionCheckerProps>(
|
|
104
110
|
},
|
105
111
|
});
|
106
112
|
};
|
107
|
-
const isMobile = useIsMobile();
|
108
113
|
|
109
114
|
const defaultError = error ? <Error error={error as ChatMessageError} /> : null;
|
110
115
|
|
@@ -115,26 +120,42 @@ const Checker = memo<ConnectionCheckerProps>(
|
|
115
120
|
);
|
116
121
|
|
117
122
|
return (
|
118
|
-
<Flexbox
|
119
|
-
<
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
123
|
+
<Flexbox gap={8}>
|
124
|
+
<Space.Compact block>
|
125
|
+
<Select
|
126
|
+
listItemHeight={36}
|
127
|
+
onSelect={async (value) => {
|
128
|
+
setCheckModel(value);
|
129
|
+
await updateAiProviderConfig(provider, { checkModel: value });
|
130
|
+
}}
|
131
|
+
optionRender={({ value }) => {
|
132
|
+
return (
|
133
|
+
<Flexbox align={'center'} gap={6} horizontal>
|
134
|
+
<ModelIcon model={value as string} size={20} />
|
135
|
+
{value}
|
136
|
+
</Flexbox>
|
137
|
+
);
|
138
|
+
}}
|
139
|
+
options={totalModels.map((id) => ({ label: id, value: id }))}
|
140
|
+
suffixIcon={isProviderConfigUpdating && <Icon icon={Loader2Icon} spin />}
|
141
|
+
value={checkModel}
|
142
|
+
virtual
|
143
|
+
/>
|
144
|
+
<Button disabled={isProviderConfigUpdating} loading={loading} onClick={checkConnection}>
|
135
145
|
{t('llm.checker.button')}
|
136
146
|
</Button>
|
137
|
-
</
|
147
|
+
</Space.Compact>
|
148
|
+
|
149
|
+
{pass && (
|
150
|
+
<Flexbox gap={4} horizontal>
|
151
|
+
<CheckCircleFilled
|
152
|
+
style={{
|
153
|
+
color: theme.colorSuccess,
|
154
|
+
}}
|
155
|
+
/>
|
156
|
+
{t('llm.checker.pass')}
|
157
|
+
</Flexbox>
|
158
|
+
)}
|
138
159
|
{error && errorContent}
|
139
160
|
</Flexbox>
|
140
161
|
);
|
@@ -275,7 +275,11 @@ const ProviderConfig = memo<ProviderConfigProps>(
|
|
275
275
|
children: isLoading ? (
|
276
276
|
<Skeleton.Button active />
|
277
277
|
) : (
|
278
|
-
<Checker
|
278
|
+
<Checker
|
279
|
+
checkErrorRender={checkErrorRender}
|
280
|
+
model={data?.checkModel || checkModel!}
|
281
|
+
provider={id}
|
282
|
+
/>
|
279
283
|
),
|
280
284
|
desc: t('providerModels.config.checker.desc'),
|
281
285
|
label: t('providerModels.config.checker.title'),
|
package/src/const/version.ts
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
import pkg from '@/../package.json';
|
2
|
-
import { getServerDBConfig } from '@/config/db';
|
3
2
|
|
4
3
|
import { BRANDING_NAME, ORG_NAME } from './branding';
|
5
4
|
|
6
5
|
export const CURRENT_VERSION = pkg.version;
|
7
6
|
|
8
|
-
export const isServerMode =
|
7
|
+
export const isServerMode = process.env.NEXT_PUBLIC_SERVICE_MODE === 'server';
|
9
8
|
export const isUsePgliteDB = process.env.NEXT_PUBLIC_CLIENT_DB === 'pglite';
|
10
9
|
|
11
10
|
export const isDeprecatedEdition = !isServerMode && !isUsePgliteDB;
|
@@ -197,6 +197,12 @@ export class AiModelModel {
|
|
197
197
|
);
|
198
198
|
}
|
199
199
|
|
200
|
+
clearModelsByProvider(providerId: string) {
|
201
|
+
return this.db
|
202
|
+
.delete(aiModels)
|
203
|
+
.where(and(eq(aiModels.providerId, providerId), eq(aiModels.userId, this.userId)));
|
204
|
+
}
|
205
|
+
|
200
206
|
updateModelsOrder = async (providerId: string, sortMap: AiModelSortMap[]) => {
|
201
207
|
await this.db.transaction(async (tx) => {
|
202
208
|
const updates = sortMap.map(({ id, sort }) => {
|
@@ -278,6 +278,11 @@ export default {
|
|
278
278
|
latestTime: '上次更新时间:{{time}}',
|
279
279
|
noLatestTime: '暂未获取列表',
|
280
280
|
},
|
281
|
+
resetAll: {
|
282
|
+
conform: '确认重置当前模型的所有修改?重置后当前模型列表将会回到默认状态',
|
283
|
+
success: '重置成功',
|
284
|
+
title: '重置所有修改',
|
285
|
+
},
|
281
286
|
search: '搜索模型...',
|
282
287
|
searchResult: '搜索到 {{count}} 个模型',
|
283
288
|
title: '模型列表',
|
@@ -59,6 +59,11 @@ export const aiModelRouter = router({
|
|
59
59
|
return ctx.aiModelModel.batchUpdateAiModels(input.id, input.models);
|
60
60
|
}),
|
61
61
|
|
62
|
+
clearModelsByProvider: aiModelProcedure
|
63
|
+
.input(z.object({ providerId: z.string() }))
|
64
|
+
.mutation(async ({ input, ctx }) => {
|
65
|
+
return ctx.aiModelModel.clearModelsByProvider(input.providerId);
|
66
|
+
}),
|
62
67
|
clearRemoteModels: aiModelProcedure
|
63
68
|
.input(z.object({ providerId: z.string() }))
|
64
69
|
.mutation(async ({ input, ctx }) => {
|
@@ -47,6 +47,10 @@ export class ClientService extends BaseClientService implements IAiModelService
|
|
47
47
|
return this.aiModel.clearRemoteModels(providerId);
|
48
48
|
};
|
49
49
|
|
50
|
+
clearModelsByProvider: IAiModelService['clearModelsByProvider'] = async (providerId) => {
|
51
|
+
return this.aiModel.clearModelsByProvider(providerId);
|
52
|
+
};
|
53
|
+
|
50
54
|
updateAiModelOrder: IAiModelService['updateAiModelOrder'] = async (providerId, items) => {
|
51
55
|
return this.aiModel.updateModelsOrder(providerId, items);
|
52
56
|
};
|
@@ -0,0 +1,122 @@
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
2
|
+
|
3
|
+
import { lambdaClient } from '@/libs/trpc/client';
|
4
|
+
import { AiProviderModelListItem } from '@/types/aiModel';
|
5
|
+
|
6
|
+
import { ServerService } from './server';
|
7
|
+
|
8
|
+
vi.mock('@/libs/trpc/client', () => ({
|
9
|
+
lambdaClient: {
|
10
|
+
aiModel: {
|
11
|
+
createAiModel: { mutate: vi.fn() },
|
12
|
+
getAiProviderModelList: { query: vi.fn() },
|
13
|
+
getAiModelById: { query: vi.fn() },
|
14
|
+
toggleModelEnabled: { mutate: vi.fn() },
|
15
|
+
updateAiModel: { mutate: vi.fn() },
|
16
|
+
batchUpdateAiModels: { mutate: vi.fn() },
|
17
|
+
batchToggleAiModels: { mutate: vi.fn() },
|
18
|
+
clearModelsByProvider: { mutate: vi.fn() },
|
19
|
+
clearRemoteModels: { mutate: vi.fn() },
|
20
|
+
updateAiModelOrder: { mutate: vi.fn() },
|
21
|
+
removeAiModel: { mutate: vi.fn() },
|
22
|
+
},
|
23
|
+
},
|
24
|
+
}));
|
25
|
+
|
26
|
+
describe('ServerService', () => {
|
27
|
+
const service = new ServerService();
|
28
|
+
|
29
|
+
it('should create AI model', async () => {
|
30
|
+
const params = {
|
31
|
+
id: 'test-id',
|
32
|
+
providerId: 'test-provider',
|
33
|
+
displayName: 'Test Model',
|
34
|
+
};
|
35
|
+
await service.createAiModel(params);
|
36
|
+
expect(vi.mocked(lambdaClient.aiModel.createAiModel.mutate)).toHaveBeenCalledWith(params);
|
37
|
+
});
|
38
|
+
|
39
|
+
it('should get AI provider model list', async () => {
|
40
|
+
await service.getAiProviderModelList('123');
|
41
|
+
expect(vi.mocked(lambdaClient.aiModel.getAiProviderModelList.query)).toHaveBeenCalledWith({
|
42
|
+
id: '123',
|
43
|
+
});
|
44
|
+
});
|
45
|
+
|
46
|
+
it('should get AI model by id', async () => {
|
47
|
+
await service.getAiModelById('123');
|
48
|
+
expect(vi.mocked(lambdaClient.aiModel.getAiModelById.query)).toHaveBeenCalledWith({
|
49
|
+
id: '123',
|
50
|
+
});
|
51
|
+
});
|
52
|
+
|
53
|
+
it('should toggle model enabled', async () => {
|
54
|
+
const params = { id: '123', providerId: 'test', enabled: true };
|
55
|
+
await service.toggleModelEnabled(params);
|
56
|
+
expect(vi.mocked(lambdaClient.aiModel.toggleModelEnabled.mutate)).toHaveBeenCalledWith(params);
|
57
|
+
});
|
58
|
+
|
59
|
+
it('should update AI model', async () => {
|
60
|
+
const value = { contextWindowTokens: 4000, displayName: 'Updated Model' };
|
61
|
+
await service.updateAiModel('123', 'openai', value);
|
62
|
+
expect(vi.mocked(lambdaClient.aiModel.updateAiModel.mutate)).toHaveBeenCalledWith({
|
63
|
+
id: '123',
|
64
|
+
providerId: 'openai',
|
65
|
+
value,
|
66
|
+
});
|
67
|
+
});
|
68
|
+
|
69
|
+
it('should batch update AI models', async () => {
|
70
|
+
const models: AiProviderModelListItem[] = [
|
71
|
+
{
|
72
|
+
id: '123',
|
73
|
+
enabled: true,
|
74
|
+
type: 'chat',
|
75
|
+
},
|
76
|
+
];
|
77
|
+
await service.batchUpdateAiModels('provider1', models);
|
78
|
+
expect(vi.mocked(lambdaClient.aiModel.batchUpdateAiModels.mutate)).toHaveBeenCalledWith({
|
79
|
+
id: 'provider1',
|
80
|
+
models,
|
81
|
+
});
|
82
|
+
});
|
83
|
+
|
84
|
+
it('should batch toggle AI models', async () => {
|
85
|
+
const models = ['123', '456'];
|
86
|
+
await service.batchToggleAiModels('provider1', models, true);
|
87
|
+
expect(vi.mocked(lambdaClient.aiModel.batchToggleAiModels.mutate)).toHaveBeenCalledWith({
|
88
|
+
id: 'provider1',
|
89
|
+
models,
|
90
|
+
enabled: true,
|
91
|
+
});
|
92
|
+
});
|
93
|
+
|
94
|
+
it('should clear models by provider', async () => {
|
95
|
+
await service.clearModelsByProvider('provider1');
|
96
|
+
expect(vi.mocked(lambdaClient.aiModel.clearModelsByProvider.mutate)).toHaveBeenCalledWith({
|
97
|
+
providerId: 'provider1',
|
98
|
+
});
|
99
|
+
});
|
100
|
+
|
101
|
+
it('should clear remote models', async () => {
|
102
|
+
await service.clearRemoteModels('provider1');
|
103
|
+
expect(vi.mocked(lambdaClient.aiModel.clearRemoteModels.mutate)).toHaveBeenCalledWith({
|
104
|
+
providerId: 'provider1',
|
105
|
+
});
|
106
|
+
});
|
107
|
+
|
108
|
+
it('should update AI model order', async () => {
|
109
|
+
const items = [{ id: '123', sort: 1 }];
|
110
|
+
await service.updateAiModelOrder('provider1', items);
|
111
|
+
expect(vi.mocked(lambdaClient.aiModel.updateAiModelOrder.mutate)).toHaveBeenCalledWith({
|
112
|
+
providerId: 'provider1',
|
113
|
+
sortMap: items,
|
114
|
+
});
|
115
|
+
});
|
116
|
+
|
117
|
+
it('should delete AI model', async () => {
|
118
|
+
const params = { id: '123', providerId: 'openai' };
|
119
|
+
await service.deleteAiModel(params);
|
120
|
+
expect(vi.mocked(lambdaClient.aiModel.removeAiModel.mutate)).toHaveBeenCalledWith(params);
|
121
|
+
});
|
122
|
+
});
|
@@ -30,6 +30,10 @@ export class ServerService implements IAiModelService {
|
|
30
30
|
return lambdaClient.aiModel.batchToggleAiModels.mutate({ enabled, id, models });
|
31
31
|
};
|
32
32
|
|
33
|
+
clearModelsByProvider: IAiModelService['clearModelsByProvider'] = async (providerId) => {
|
34
|
+
return lambdaClient.aiModel.clearModelsByProvider.mutate({ providerId });
|
35
|
+
};
|
36
|
+
|
33
37
|
clearRemoteModels: IAiModelService['clearRemoteModels'] = async (providerId) => {
|
34
38
|
return lambdaClient.aiModel.clearRemoteModels.mutate({ providerId });
|
35
39
|
};
|
@@ -24,6 +24,8 @@ export interface IAiModelService {
|
|
24
24
|
|
25
25
|
clearRemoteModels: (providerId: string) => Promise<any>;
|
26
26
|
|
27
|
+
clearModelsByProvider: (providerId: string) => Promise<any>;
|
28
|
+
|
27
29
|
updateAiModelOrder: (providerId: string, items: AiModelSortMap[]) => Promise<any>;
|
28
30
|
|
29
31
|
deleteAiModel: (params: { id: string; providerId: string }) => Promise<any>;
|
@@ -17,6 +17,7 @@ const FETCH_AI_PROVIDER_MODEL_LIST_KEY = 'FETCH_AI_PROVIDER_MODELS';
|
|
17
17
|
export interface AiModelAction {
|
18
18
|
batchToggleAiModels: (ids: string[], enabled: boolean) => Promise<void>;
|
19
19
|
batchUpdateAiModels: (models: AiProviderModelListItem[]) => Promise<void>;
|
20
|
+
clearModelsByProvider: (provider: string) => Promise<void>;
|
20
21
|
clearRemoteModels: (provider: string) => Promise<void>;
|
21
22
|
createNewAiModel: (params: CreateAiModelParams) => Promise<void>;
|
22
23
|
fetchRemoteModelList: (providerId: string) => Promise<void>;
|
@@ -55,6 +56,10 @@ export const createAiModelSlice: StateCreator<
|
|
55
56
|
await aiModelService.batchUpdateAiModels(id, models);
|
56
57
|
await get().refreshAiModelList();
|
57
58
|
},
|
59
|
+
clearModelsByProvider: async (provider) => {
|
60
|
+
await aiModelService.clearModelsByProvider(provider);
|
61
|
+
await get().refreshAiModelList();
|
62
|
+
},
|
58
63
|
clearRemoteModels: async (provider) => {
|
59
64
|
await aiModelService.clearRemoteModels(provider);
|
60
65
|
await get().refreshAiModelList();
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import { AIProviderStoreState } from '@/store/aiInfra/initialState';
|
2
2
|
import { AiModelSourceEnum } from '@/types/aiModel';
|
3
3
|
|
4
|
+
const aiProviderChatModelListIds = (s: AIProviderStoreState) =>
|
5
|
+
s.aiProviderModelList.filter((item) => item.type === 'chat').map((item) => item.id);
|
4
6
|
// List
|
5
7
|
const enabledAiProviderModelList = (s: AIProviderStoreState) =>
|
6
8
|
s.aiProviderModelList.filter((item) => item.enabled);
|
@@ -68,6 +70,7 @@ const modelContextWindowTokens = (id: string, provider: string) => (s: AIProvide
|
|
68
70
|
};
|
69
71
|
|
70
72
|
export const aiModelSelectors = {
|
73
|
+
aiProviderChatModelListIds,
|
71
74
|
disabledAiProviderModelList,
|
72
75
|
enabledAiProviderModelList,
|
73
76
|
filteredAiProviderModelList,
|
package/src/types/aiProvider.ts
CHANGED
@@ -72,6 +72,13 @@ export interface AiProviderSettings {
|
|
72
72
|
* @default false
|
73
73
|
*/
|
74
74
|
disableBrowserRequest?: boolean;
|
75
|
+
/**
|
76
|
+
* whether provider support edit model
|
77
|
+
*
|
78
|
+
* @default true
|
79
|
+
*/
|
80
|
+
modelEditable?: boolean;
|
81
|
+
|
75
82
|
proxyUrl?:
|
76
83
|
| {
|
77
84
|
desc?: string;
|
@@ -84,7 +91,6 @@ export interface AiProviderSettings {
|
|
84
91
|
* default openai
|
85
92
|
*/
|
86
93
|
sdkType?: AiProviderSDKType;
|
87
|
-
|
88
94
|
showAddNewModel?: boolean;
|
89
95
|
/**
|
90
96
|
* whether show api key in the provider config
|