## 核心变更 ### 🔧 关键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移除计划
90 lines
2.4 KiB
TypeScript
90 lines
2.4 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
mergeOverrides,
|
|
splitOverridesBySchema,
|
|
validateOverrides
|
|
} from '../../src/services/model/parameter-utils'
|
|
import type { UnifiedParameterDefinition } from '../../src/services/model/parameter-schema'
|
|
|
|
const schema: UnifiedParameterDefinition[] = [
|
|
{
|
|
name: 'temperature',
|
|
type: 'number',
|
|
minValue: 0,
|
|
maxValue: 2,
|
|
defaultValue: 1
|
|
},
|
|
{
|
|
name: 'max_tokens',
|
|
type: 'integer',
|
|
minValue: 1,
|
|
maxValue: 40000
|
|
},
|
|
{
|
|
name: 'stopSequences',
|
|
type: 'string',
|
|
tags: ['string-array']
|
|
},
|
|
{
|
|
name: 'mode',
|
|
type: 'string',
|
|
allowedValues: ['fast', 'standard']
|
|
}
|
|
]
|
|
|
|
describe('parameter-utils', () => {
|
|
it('splits overrides by schema', () => {
|
|
const overrides = { temperature: 0.5, custom_flag: true }
|
|
const { builtIn, custom } = splitOverridesBySchema(schema, overrides)
|
|
expect(builtIn).toEqual({ temperature: 0.5 })
|
|
expect(custom).toEqual({ custom_flag: true })
|
|
})
|
|
|
|
it('merges overrides with priority request > builtIn > custom', () => {
|
|
const merged = mergeOverrides({
|
|
schema,
|
|
includeDefaults: true,
|
|
customOverrides: { custom_key: 'foo', temperature: 0.4 },
|
|
builtInOverrides: { temperature: 0.7, max_tokens: 1000 },
|
|
requestOverrides: { temperature: 0.9 }
|
|
})
|
|
|
|
expect(merged.temperature).toBe(0.9)
|
|
expect(merged.max_tokens).toBe(1000)
|
|
expect(merged.custom_key).toBe('foo')
|
|
expect(merged.mode).toBeUndefined()
|
|
})
|
|
|
|
it('omits unsafe custom keys and empty values', () => {
|
|
const merged = mergeOverrides({
|
|
schema,
|
|
customOverrides: { '__proto__': 'bad', empty: '' },
|
|
builtInOverrides: { temperature: '' }
|
|
})
|
|
expect(merged).toEqual({})
|
|
})
|
|
|
|
it('validates overrides against schema', () => {
|
|
const { errors, warnings } = validateOverrides({
|
|
schema,
|
|
overrides: { temperature: 3, stopSequences: ['ok', 123], unknown: 1 }
|
|
})
|
|
|
|
expect(errors.length).toBe(2)
|
|
expect(errors[0].parameterName).toBe('temperature')
|
|
expect(errors[1].parameterName).toBe('stopSequences')
|
|
expect(warnings.length).toBe(1)
|
|
expect(warnings[0].parameterName).toBe('unknown')
|
|
})
|
|
|
|
it('rejects dangerous custom parameters', () => {
|
|
const { errors } = validateOverrides({
|
|
schema,
|
|
overrides: undefined,
|
|
customOverrides: { apiKey: 'secret' }
|
|
})
|
|
expect(errors.length).toBe(1)
|
|
expect(errors[0].parameterName).toBe('apiKey')
|
|
})
|
|
})
|