Files
prompt-optimizer/packages/core/tests/unit/parameter-utils.test.ts
T
linshen 006565c599 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移除计划
2025-10-12 22:26:58 +08:00

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')
})
})