Skip to content

Commit 4098b78

Browse files
committed
fix(core): 优化模型初始化策略,保护用户自定义配置不被覆盖
- 改进ModelManager初始化逻辑,仅在缺失元数据时补齐默认值 - 增强连接测试功能,提升配置验证和错误处理 - 新增测试用例验证配置保护机制的有效性
1 parent d0bbd71 commit 4098b78

File tree

3 files changed

+77
-27
lines changed

3 files changed

+77
-27
lines changed

packages/core/src/services/model/manager.ts

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -107,25 +107,24 @@ export class ModelManager implements IModelManager {
107107
const existingModel = updatedModels[key];
108108

109109
if (isTextModelConfig(existingModel)) {
110-
// 已经是新格式,保留用户配置
111-
const updatedModel = {
112-
...defaultConfig,
113-
// 保留用户的启用状态和连接配置
114-
enabled: existingModel.enabled !== undefined ? existingModel.enabled : defaultConfig.enabled,
115-
connectionConfig: {
116-
...defaultConfig.connectionConfig,
117-
...(existingModel.connectionConfig || {})
118-
},
119-
paramOverrides: {
120-
...defaultConfig.paramOverrides,
121-
...(existingModel.paramOverrides || {})
122-
}
123-
};
124-
125-
if (JSON.stringify(updatedModels[key]) !== JSON.stringify(updatedModel)) {
110+
// 已经是新格式,保留用户配置,仅在缺失关键字段时补齐默认值
111+
const updatedModel = { ...existingModel } as TextModelConfig;
112+
let patched = false;
113+
114+
if (!updatedModel.providerMeta && defaultConfig.providerMeta) {
115+
updatedModel.providerMeta = defaultConfig.providerMeta;
116+
patched = true;
117+
}
118+
119+
if (!updatedModel.modelMeta && defaultConfig.modelMeta) {
120+
updatedModel.modelMeta = defaultConfig.modelMeta;
121+
patched = true;
122+
}
123+
124+
if (patched) {
126125
updatedModels[key] = updatedModel;
127126
hasUpdates = true;
128-
console.log(`[ModelManager] Updated default model: ${key}`);
127+
console.log(`[ModelManager] Patched missing metadata for model: ${key}`);
129128
}
130129
} else if (isLegacyConfig(existingModel)) {
131130
// 旧格式,尝试使用 Registry 转换为新格式

packages/core/tests/unit/model/manager.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,45 @@ describe('ModelManager', () => {
101101
});
102102
});
103103

104+
describe('initialization behavior', () => {
105+
it('should not overwrite existing model metadata or connection settings when reinitialized', async () => {
106+
const targetId = 'openai';
107+
const existing = await modelManager.getModel(targetId);
108+
expect(existing).toBeDefined();
109+
110+
const customProviderMeta = {
111+
...existing!.providerMeta,
112+
name: 'Custom Provider Name'
113+
};
114+
115+
const customModelMeta = {
116+
...existing!.modelMeta,
117+
id: 'custom-openai-model',
118+
name: 'Custom OpenAI Model'
119+
};
120+
121+
const customBaseURL = 'https://custom-openai.example.com/v1';
122+
123+
await modelManager.updateModel(targetId, {
124+
providerMeta: customProviderMeta,
125+
modelMeta: customModelMeta,
126+
connectionConfig: {
127+
...existing!.connectionConfig,
128+
baseURL: customBaseURL
129+
}
130+
});
131+
132+
const secondRegistry = new TextAdapterRegistry();
133+
const reloadedManager = new ModelManager(storageProvider, secondRegistry);
134+
const reloaded = await reloadedManager.getModel(targetId);
135+
136+
expect(reloaded?.providerMeta.name).toBe('Custom Provider Name');
137+
expect(reloaded?.modelMeta.id).toBe('custom-openai-model');
138+
expect(reloaded?.modelMeta.name).toBe('Custom OpenAI Model');
139+
expect(reloaded?.connectionConfig.baseURL).toBe(customBaseURL);
140+
});
141+
});
142+
104143
describe('getModel', () => {
105144
it('should retrieve an existing model by key', async () => {
106145
const model = createTextModelConfig('MyModel', 'MyModel');

packages/ui/src/composables/useTextModelManager.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -569,33 +569,45 @@ export function useTextModelManager() {
569569
formConnectionStatus.value = { type: 'info', message: t('modelManager.testing') }
570570

571571
try {
572-
// 获取原始配置
573-
const existingConfig = await modelManager.getModel(editingModelId.value)
572+
const existingConfig = editingModelId.value ? await modelManager.getModel(editingModelId.value) : undefined
574573
if (!existingConfig) {
575574
throw new Error('模型配置不存在')
576575
}
577576

578-
// 创建临时测试配置,使用当前表单的参数覆盖
579-
// 注意:如果 API Key 被脱敏显示,需要使用原始 Key
580-
const connectionConfig = {
577+
if (!form.value.providerId || !form.value.modelId) {
578+
throw new Error('模型未选择')
579+
}
580+
581+
const providerMeta = ensureProviderMeta(form.value.providerId, existingConfig.providerMeta)
582+
const modelMeta = ensureModelMeta(form.value.providerId, form.value.modelId, existingConfig.modelMeta)
583+
584+
const baseURL = typeof form.value.connectionConfig?.baseURL === 'string'
585+
? form.value.connectionConfig.baseURL.trim()
586+
: undefined
587+
588+
const connectionConfig: TextConnectionConfig = {
589+
...existingConfig.connectionConfig,
581590
...form.value.connectionConfig,
591+
baseURL: baseURL || existingConfig.connectionConfig?.baseURL,
582592
apiKey: form.value.displayMaskedKey && form.value.originalApiKey
583593
? form.value.originalApiKey
584594
: form.value.connectionConfig.apiKey
585595
}
586596

597+
if (!connectionConfig.apiKey && existingConfig.connectionConfig?.apiKey) {
598+
connectionConfig.apiKey = existingConfig.connectionConfig.apiKey
599+
}
600+
587601
const tempConfig: TextModelConfig = {
588-
...existingConfig,
589-
id: `temp-test-${editingModelId.value}`,
602+
id: `temp-test-${editingModelId.value}-${Date.now()}`,
590603
name: form.value.name,
591604
enabled: form.value.enabled,
592-
providerMeta: { ...existingConfig.providerMeta },
593-
modelMeta: { ...existingConfig.modelMeta },
605+
providerMeta,
606+
modelMeta,
594607
connectionConfig,
595608
paramOverrides: { ...(form.value.paramOverrides || {}) }
596609
}
597610

598-
// 创建临时模型用于测试
599611
await modelManager.addModel(tempConfig.id, tempConfig)
600612

601613
try {

0 commit comments

Comments
 (0)