fix(core): 修复图像模型配置的删除和容错处理

## 问题
- 开发期间修改配置ID后,旧配置存储在本地但数据结构不完整
- 删除损坏配置时报错"Configuration does not exist"
- 即使删除成功,配置仍然存在于列表中

## 根本原因
- 存储key和配置ID不一致:旧配置自带ID字段与存储key不匹配
- 删除操作使用修复后的ID查找,无法匹配存储中的实际key

## 解决方案

### 1. deleteConfig - 容错处理
- 移除严格的存在性检查,不再抛出异常
- 允许删除不存在的配置(降级处理)
- 添加详细的日志输出用于诊断

### 2. getConfig - 安全修复
- 尝试修复损坏的配置结构
- 即使修复失败也返回配置,确保可以删除
- 补齐缺失的provider/model字段

### 3. getAllConfigs - 关键修复
- **强制使用存储key作为配置ID**(最关键)
- 保证读写一致性:删除时使用的ID = 存储中的key
- 对无法修复的配置返回占位对象,标记为disabled

### 4. ensureSelfContained - 容错降级
- 捕获修复失败的异常
- 创建占位配置,包含完整的provider/model结构
- 自动标记为disabled,引导用户删除

## 效果
- ✅ 损坏配置可以正常显示和删除
- ✅ 删除操作不再报错
- ✅ ID一致性得到保证
- ✅ 向后兼容,支持配置结构变更
- ✅ 用户无需手动清理本地存储
This commit is contained in:
linshen committed 2025-09-29 23:40:24 +08:00
1 parent 719ce8daa9
commit 22a1e4ac3f
1 file changed
+86 -24
@@ -132,10 +132,18 @@ export class ImageModelManager implements IImageModelManager {
this.storageKey,
(current) => {
const data = current || {}
// 强制删除:无论配置是否存在都尝试删除
// 这确保损坏的配置也能被清理
if (!data[id]) {
throw new Error(`Configuration with id '${id}' does not exist`)
console.warn(`[ImageModelManager] Config ${id} not found in storage, but proceeding anyway`)
// 仍然返回原数据,因为确实没什么可删的
return data
}
// 配置存在,正常删除
const { [id]: removed, ...rest } = data
console.log(`[ImageModelManager] Successfully deleted config: ${id}`)
return rest
}
)
@@ -146,25 +154,48 @@ export class ImageModelManager implements IImageModelManager {
const data: Record<string, ImageModelConfig> = raw ? JSON.parse(raw) : {}
const cfg = data[id]
if (!cfg) return null
// 轻量迁移兜底:返回前补齐缺失的 id,避免 UI 无法删除
// 说明:旧数据来自开发期,仅补 id 用于删除,不补 providerId/modelId/provider/model
if (!(cfg as any).id) {
return { ...(cfg as any), id } as ImageModelConfig
;(cfg as any).id = id
}
// 尝试修复损坏的配置,确保能够正常读取和删除
try {
return this.ensureSelfContained(cfg)
} catch (error) {
// 即使修复失败,也返回配置(已在ensureSelfContained中标记为disabled)
console.warn(`[ImageModelManager] Failed to fully repair config ${id}, but returning for deletion:`, error)
return cfg
}
return cfg
}
async getAllConfigs(): Promise<ImageModelConfig[]> {
const raw = await this.storage.getItem(this.storageKey)
const data: Record<string, ImageModelConfig> = raw ? JSON.parse(raw) : {}
// 轻量迁移兜底:为缺失 id 的旧记录补齐 id(仅返回层面,不强制持久化)
// 说明:旧数据来自开发期,仅补 id 以便在界面上删除,无需补齐其它字段
// 轻量迁移兜底:为缺失 id 的旧记录补齐 id,并尝试修复损坏的配置
return Object.entries(data).map(([key, cfg]) => {
if (cfg && typeof cfg === 'object' && !(cfg as any).id) {
return { ...(cfg as any), id: key } as ImageModelConfig
if (!cfg || typeof cfg !== 'object') {
return null
}
return cfg
})
// 始终使用存储键作为公开的 id,保持删除等操作一致
;(cfg as any).id = key
// 尝试修复配置,如果失败则返回占位配置(标记为disabled)
try {
return this.ensureSelfContained(cfg)
} catch (error) {
console.warn(`[ImageModelManager] Failed to repair config ${key}, returning placeholder:`, error)
// 返回最小占位配置,确保能在UI中显示和删除
return {
...cfg,
id: key,
enabled: false
} as ImageModelConfig
}
}).filter((cfg): cfg is ImageModelConfig => cfg !== null)
}
async getEnabledConfigs(): Promise<ImageModelConfig[]> {
@@ -249,23 +280,54 @@ export class ImageModelManager implements IImageModelManager {
return config
}
// 获取provider和model信息
const adapter = this.registry.getAdapter(config.providerId)
const provider = adapter.getProvider()
try {
// 获取provider和model信息
const adapter = this.registry.getAdapter(config.providerId)
const provider = adapter.getProvider()
// 尝试从静态模型列表获取模型信息
let model = this.registry.getStaticModels(config.providerId).find(m => m.id === config.modelId)
// 尝试从静态模型列表获取模型信息
let model = this.registry.getStaticModels(config.providerId).find(m => m.id === config.modelId)
// 如果静态模型不存在,使用buildDefaultModel构建
if (!model) {
model = adapter.buildDefaultModel(config.modelId)
}
// 如果静态模型不存在,使用buildDefaultModel构建
if (!model) {
model = adapter.buildDefaultModel(config.modelId)
}
// 返回自包含配置
return {
...config,
provider,
model
// 返回自包含配置
return {
...config,
provider,
model
}
} catch (error) {
// 对于无法修复的旧配置,创建占位数据并禁用,允许用户查看和删除
console.warn(`[ImageModelManager] Cannot repair legacy config ${config.id}, marking as disabled:`, error)
return {
...config,
enabled: false,
provider: {
id: config.providerId || 'unknown',
name: `Unknown Provider (${config.providerId || 'unknown'})`,
description: '此配置损坏,无法修复',
requiresApiKey: false,
supportsDynamicModels: false,
defaultBaseURL: '',
connectionSchema: { required: [], optional: [], fieldTypes: {} }
},
model: {
id: config.modelId || 'unknown',
name: `Unknown Model (${config.modelId || 'unknown'})`,
description: '此配置损坏,请删除后重新创建',
providerId: config.providerId || 'unknown',
capabilities: {
text2image: false,
image2image: false,
multiImage: false
},
parameterDefinitions: [],
defaultParameterValues: {}
}
} as ImageModelConfig
}
}