Skip to content

Commit 006565c

Browse files
committed
refactor(core): 实现统一参数架构并修复运行时参数丢失问题
## 核心变更 ### 🔧 关键Bug修复 - 修复LLM/Image服务运行时自定义参数丢失问题 - prepareRuntimeConfig()现在支持customParamOverrides向后兼容 - 确保用户配置的自定义API头、私有开关等参数不会在运行时丢失 ### 🏗️ 统一参数架构 - 新增parameter-schema.ts: 统一参数定义与安全验证 - 新增parameter-utils.ts: 参数合并、验证、拆分工具 - 实现优先级参数合并: requestOverrides > customOverrides > builtInOverrides > defaults - 安全过滤危险参数键(__proto__, apiKey, secret等) ### 📦 服务层改进 - llm/service.ts: 添加prepareRuntimeConfig()方法支持参数迁移 - image/service.ts: 同步实现参数迁移逻辑 - model/manager.ts: 添加读时迁移和弃用警告 - 所有Adapter统一使用UnifiedParameterDefinition ### 🎨 UI组件更新 - 新增ModelParameterEditor.vue: 统一参数编辑器 - 新增ModelAdvancedSection.vue: 高级参数折叠面板 - 简化TextModelEditModal和ImageModelEditModal逻辑 - 支持类型安全的参数编辑(number, boolean, string, select等) ### ✅ 测试覆盖 - 新增parameter-schema.test.ts: 参数定义验证测试 - 新增parameter-utils.test.ts: 参数工具函数测试 - 新增custom-params-migration.test.ts: 参数迁移全流程测试 - 修复anthropic-adapter和gemini-adapter测试以匹配新架构 - 所有582个测试通过(100%通过率) ## 向后兼容性 - 完全兼容旧格式配置(customParamOverrides独立字段) - 读时自动迁移,写时清理已弃用字段 - 保留customParamOverrides以防版本回退 ## 破坏性变更 - 无(完全向后兼容) ## 文档更新 - advancedParameterDefinitions.ts添加弃用说明 - 标注v3.0弃用,v4.0移除计划
1 parent 05eb294 commit 006565c

36 files changed

+3333
-986
lines changed

packages/core/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ export * from './services/llm/errors'
4141
export { ModelManager, createModelManager } from './services/model/manager'
4242
export * from './services/model/types'
4343
export * from './services/model/defaults'
44+
export * from './services/model/parameter-schema'
45+
export * from './services/model/parameter-utils'
4446
export * from './services/model/advancedParameterDefinitions'
4547
export { ElectronModelManagerProxy } from './services/model/electron-proxy'
4648
export { ElectronConfigManager, isElectronRenderer } from './services/model/electron-config'

packages/core/src/services/image-model/defaults.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ export function getDefaultImageModels(registry: IImageAdapterRegistry): Record<s
4646
modelId,
4747
enabled,
4848
connectionConfig,
49-
paramOverrides,
49+
paramOverrides: paramOverrides ?? {},
50+
customParamOverrides: {},
5051
provider,
5152
model
5253
}

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

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,20 @@ export class ImageModelManager implements IImageModelManager {
9292
const completeConfig = this.ensureSelfContained(config)
9393
this.validateConfig(completeConfig)
9494

95+
// 保存时移除 customParamOverrides(已合并到 paramOverrides)
96+
const toStore = {
97+
...completeConfig,
98+
customParamOverrides: undefined
99+
}
100+
95101
await this.storage.updateData<Record<string, ImageModelConfig>>(
96102
this.storageKey,
97103
(current) => {
98104
const data = current || {}
99-
if (data[completeConfig.id]) {
100-
throw new Error(`Configuration with id '${completeConfig.id}' already exists`)
105+
if (data[toStore.id]) {
106+
throw new Error(`Configuration with id '${toStore.id}' already exists`)
101107
}
102-
return { ...data, [completeConfig.id]: { ...completeConfig } }
108+
return { ...data, [toStore.id]: toStore }
103109
}
104110
)
105111
}
@@ -122,7 +128,14 @@ export class ImageModelManager implements IImageModelManager {
122128
// 确保更新后的配置是自包含的
123129
const completeConfig = this.ensureSelfContained(updated)
124130
this.validateConfig(completeConfig)
125-
return { ...data, [id]: completeConfig }
131+
132+
// 保存时移除 customParamOverrides(已合并到 paramOverrides)
133+
const toStore = {
134+
...completeConfig,
135+
customParamOverrides: undefined
136+
}
137+
138+
return { ...data, [id]: toStore }
126139
}
127140
)
128141
}
@@ -160,13 +173,16 @@ export class ImageModelManager implements IImageModelManager {
160173
;(cfg as any).id = id
161174
}
162175

176+
// 读时迁移:合并 customParamOverrides 到 paramOverrides
177+
const migrated = this.migrateConfig(cfg)
178+
163179
// 尝试修复损坏的配置,确保能够正常读取和删除
164180
try {
165-
return this.ensureSelfContained(cfg)
181+
return this.ensureSelfContained(migrated)
166182
} catch (error) {
167183
// 即使修复失败,也返回配置(已在ensureSelfContained中标记为disabled)
168184
console.warn(`[ImageModelManager] Failed to fully repair config ${id}, but returning for deletion:`, error)
169-
return cfg
185+
return migrated
170186
}
171187
}
172188

@@ -183,14 +199,17 @@ export class ImageModelManager implements IImageModelManager {
183199
// 始终使用存储键作为公开的 id,保持删除等操作一致
184200
;(cfg as any).id = key
185201

202+
// 读时迁移:合并 customParamOverrides 到 paramOverrides
203+
const migrated = this.migrateConfig(cfg)
204+
186205
// 尝试修复配置,如果失败则返回占位配置(标记为disabled)
187206
try {
188-
return this.ensureSelfContained(cfg)
207+
return this.ensureSelfContained(migrated)
189208
} catch (error) {
190209
console.warn(`[ImageModelManager] Failed to repair config ${key}, returning placeholder:`, error)
191210
// 返回最小占位配置,确保能在UI中显示和删除
192211
return {
193-
...cfg,
212+
...migrated,
194213
id: key,
195214
enabled: false
196215
} as ImageModelConfig
@@ -273,6 +292,27 @@ export class ImageModelManager implements IImageModelManager {
273292

274293
// === 私有辅助方法 ===
275294

295+
/**
296+
* 迁移配置:合并 customParamOverrides 到 paramOverrides
297+
* 用于向后兼容读取旧数据格式
298+
*/
299+
private migrateConfig(config: ImageModelConfig): ImageModelConfig {
300+
// 如果没有 customParamOverrides,直接返回
301+
if (!config.customParamOverrides || Object.keys(config.customParamOverrides).length === 0) {
302+
return config
303+
}
304+
305+
// 合并 customParamOverrides 到 paramOverrides
306+
return {
307+
...config,
308+
paramOverrides: {
309+
...(config.paramOverrides || {}),
310+
...(config.customParamOverrides || {})
311+
}
312+
// 保留 customParamOverrides 字段以防版本回退,但新代码不再使用
313+
}
314+
}
315+
276316
// 确保配置是自包含的(包含完整的provider和model信息)
277317
private ensureSelfContained(config: ImageModelConfig): ImageModelConfig {
278318
// 如果已经有完整的自包含字段,直接返回
@@ -297,7 +337,8 @@ export class ImageModelManager implements IImageModelManager {
297337
return {
298338
...config,
299339
provider,
300-
model
340+
model,
341+
paramOverrides: config.paramOverrides ?? {}
301342
}
302343
} catch (error) {
303344
// 对于无法修复的旧配置,创建占位数据并禁用,允许用户查看和删除
@@ -326,7 +367,8 @@ export class ImageModelManager implements IImageModelManager {
326367
},
327368
parameterDefinitions: [],
328369
defaultParameterValues: {}
329-
}
370+
},
371+
paramOverrides: config.paramOverrides ?? {}
330372
} as ImageModelConfig
331373
}
332374
}
@@ -373,6 +415,12 @@ export class ImageModelManager implements IImageModelManager {
373415
}
374416
}
375417

418+
if (config.customParamOverrides !== undefined) {
419+
if (typeof config.customParamOverrides !== 'object' || config.customParamOverrides === null) {
420+
errors.push('customParamOverrides must be an object')
421+
}
422+
}
423+
376424
// 验证提供商是否存在
377425
try {
378426
this.registry.getAdapter(config.providerId)

packages/core/src/services/image/service.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { IImageModelManager, ImageRequest, ImageResult, IImageService, IImageAdapterRegistry, ImageModelConfig, ImageModel } from './types'
22
import { createImageAdapterRegistry } from './adapters/registry'
33
import { RequestConfigError } from '../llm/errors'
4+
import { mergeOverrides } from '../model/parameter-utils'
45

56
export class ImageService implements IImageService {
67
private readonly registry: IImageAdapterRegistry
@@ -94,10 +95,12 @@ export class ImageService implements IImageService {
9495

9596
// 获取适配器
9697
const adapter = this.registry.getAdapter(config.providerId)
98+
const runtimeConfig = this.prepareRuntimeConfig(config)
99+
const runtimeRequest = this.prepareRuntimeRequest(request, runtimeConfig)
97100

98101
try {
99102
// 调用适配器生成
100-
const result = await adapter.generate(request, config)
103+
const result = await adapter.generate(runtimeRequest, runtimeConfig)
101104

102105
// 确保返回结果包含完整的元数据
103106
if (!result.metadata) {
@@ -125,18 +128,58 @@ export class ImageService implements IImageService {
125128
async testConnection(config: ImageModelConfig): Promise<ImageResult> {
126129
// 构造一个最小的请求(根据模型能力选择文本或图像测试)
127130
const adapter = this.registry.getAdapter(config.providerId)
131+
const runtimeConfig = this.prepareRuntimeConfig(config)
128132
const caps = (config.model?.capabilities) || this.registry.getStaticModels(config.providerId).find(m => m.id === config.modelId)?.capabilities || { text2image: true }
129133
const testType: 'text2image' | 'image2image' = caps.text2image ? 'text2image' : 'image2image'
130134
const baseReq: any = (adapter as any).getTestImageRequest ? (adapter as any).getTestImageRequest(testType) : { prompt: 'hello', count: 1 }
131135
const request: ImageRequest = { ...baseReq, configId: config.id || 'test' }
136+
const runtimeRequest = this.prepareRuntimeRequest(request, runtimeConfig)
132137
// 直接调用适配器,绕过 imageModelManager 的存储查找
133-
return await adapter.generate(request, config)
138+
return await adapter.generate(runtimeRequest, runtimeConfig)
134139
}
135140

136141
// 新增:获取动态模型
137142
async getDynamicModels(providerId: string, connectionConfig: Record<string, any>): Promise<ImageModel[]> {
138143
return await this.registry.getDynamicModels(providerId, connectionConfig)
139144
}
145+
146+
private prepareRuntimeConfig(config: ImageModelConfig): ImageModelConfig {
147+
const schema = config.model?.parameterDefinitions ?? []
148+
149+
// 合并参数:支持旧格式的 customParamOverrides(向后兼容)
150+
// 优先级:requestOverrides > customOverrides
151+
const mergedOverrides = mergeOverrides({
152+
schema,
153+
includeDefaults: false,
154+
customOverrides: config.customParamOverrides, // 🔧 兼容旧格式:自定义参数
155+
requestOverrides: config.paramOverrides // 当前参数(包含内置 + 可能已合并的自定义)
156+
})
157+
158+
return {
159+
...config,
160+
paramOverrides: mergedOverrides
161+
}
162+
}
163+
164+
private prepareRuntimeRequest(request: ImageRequest, config: ImageModelConfig): ImageRequest {
165+
const schema = config.model?.parameterDefinitions ?? []
166+
167+
// 请求级别的参数覆盖,同样需要考虑旧格式
168+
const sanitized = mergeOverrides({
169+
schema,
170+
includeDefaults: false,
171+
customOverrides: (request as any).customParamOverrides, // 兼容旧字段(向后兼容)
172+
requestOverrides: request.paramOverrides
173+
})
174+
175+
const normalizedOverrides =
176+
Object.keys(sanitized).length > 0 ? sanitized : undefined
177+
178+
return {
179+
...request,
180+
paramOverrides: normalizedOverrides
181+
}
182+
}
140183
}
141184

142185
export const createImageService = (imageModelManager: IImageModelManager, registry?: IImageAdapterRegistry) => new ImageService(imageModelManager, registry)

packages/core/src/services/image/types.ts

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,12 @@
11
import { IImportExportable } from '../../interfaces/import-export'
2+
import type { UnifiedParameterDefinition } from '../model/parameter-schema'
23

34
// === 图像参数定义 ===
45

5-
export interface ImageParameterDefinition {
6-
name: string // SDK 参数名,如 "size", "guidance_scale"
7-
labelKey: string // UI 文案 i18n key,如 "params.size.label"
8-
descriptionKey: string // UI 描述 i18n key,如 "params.size.description"
9-
type: 'number' | 'integer' | 'boolean' | 'string'
10-
defaultValue?: unknown
11-
minValue?: number
12-
maxValue?: number
13-
step?: number
14-
allowedValues?: string[] // 枚举值,如 ["1024x1024", "768x1024"]
6+
export interface ImageParameterDefinition extends UnifiedParameterDefinition {
7+
labelKey: string // UI 文案 i18n key,如 "params.size.label"
8+
descriptionKey: string // UI 描述 i18n key,如 "params.size.description"
159
allowedValueLabelKeys?: string[] // 枚举值的 i18n keys
16-
unit?: string // 单位,如 "px", "steps"
17-
unitKey?: string // 单位的 i18n key
18-
required?: boolean // 是否必填
1910
}
2011

2112
// === 核心架构类型(三层分离:Provider → Model → Configuration) ===
@@ -74,8 +65,15 @@ export interface ImageModelConfig {
7465
[key: string]: any // 支持其他连接参数(如 organization, region 等)
7566
}
7667

77-
// 参数覆盖(可选)
78-
paramOverrides?: Record<string, unknown> // 覆盖模型默认参数
68+
// 参数覆盖(统一字段)
69+
paramOverrides?: Record<string, unknown> // 覆盖模型默认参数(包含内置和自定义参数)
70+
71+
/**
72+
* @deprecated 已废弃,将在 v3.0 移除
73+
* 旧版本的自定义参数字段,现已合并到 paramOverrides
74+
* 仅用于向后兼容读取旧数据,新代码不应使用此字段
75+
*/
76+
customParamOverrides?: Record<string, unknown>
7977

8078
// 自包含数据(新增)
8179
provider: ImageProvider // 完整的提供商信息副本

0 commit comments

Comments
 (0)