Files
EasyCLIProxyAPI/tests/codexModelCatalog.test.ts
T
lzt404 40ba85d6f0 fix(codex): load context defaults from CPA model definitions
- Resolve context limits from core model definitions, aliases, and configuration
- Preserve user overrides and display context sources and fallback hints
- Refresh defaults from CPA when restoring all model settings
- Keep restore-all available without customizations and remove its icon
- Allow saving restored defaults even when values remain unchanged
- Add regression coverage for context resolution and default restoration
2026-09-07 19:28:21 +08:00

72 lines
3.1 KiB
TypeScript

import { describe, expect, test } from 'bun:test';
import {
cloneCodexModelConfiguration,
codexContextSourceHint,
sameCodexModelConfiguration,
toggleCodexReasoningLevel,
validateCodexModelConfiguration,
type CodexModelConfiguration,
type CodexCatalogEditorModel,
} from '../src/services/codexModelCatalog';
const configuration = (): CodexModelConfiguration => ({
display_name: 'Third Party',
description: null,
context_window: 128_000,
max_context_window: 128_000,
effective_context_window_percent: 95,
auto_compact_token_limit: null,
default_reasoning_level: 'medium',
supported_reasoning_levels: [
{ effort: 'low', description: 'Low' },
{ effort: 'medium', description: 'Medium' },
{ effort: 'high', description: 'High' },
],
input_modalities: ['text', 'image'],
visibility: 'list',
supports_parallel_tool_calls: false,
});
describe('Codex 模型列表编辑', () => {
test("区分内核模型定义与兼容目录的后备上下文", () => {
const model: CodexCatalogEditorModel = {
slug: "model-a", hasOfficialTemplate: true, customized: false,
contextSource: "definition", configuration: configuration(), defaults: configuration(),
};
expect(codexContextSourceHint(model)).toBe("agents.catalog.contextSource.definition");
expect(codexContextSourceHint({ ...model, contextSource: "compatibility" }))
.toBe("agents.catalog.contextSource.compatibility");
model.configuration.context_window = 64_000;
expect(codexContextSourceHint(model)).toBe("agents.catalog.contextSource.customized");
model.configuration = cloneCodexModelConfiguration(model.defaults);
expect(codexContextSourceHint(model)).toBe("agents.catalog.contextSource.definition");
});
test('克隆配置时隔离数组字段', () => {
const original = configuration();
const cloned = cloneCodexModelConfiguration(original);
cloned.supported_reasoning_levels[0].description = 'Changed';
cloned.input_modalities.pop();
expect(original.supported_reasoning_levels[0].description).toBe('Low');
expect(original.input_modalities).toEqual(['text', 'image']);
expect(sameCodexModelConfiguration(original, cloned)).toBeFalse();
});
test('移除默认思考等级时选择剩余可用等级', () => {
const updated = toggleCodexReasoningLevel(configuration(), 'medium', false, []);
expect(updated.supported_reasoning_levels.map((level) => level.effort)).toEqual(['low', 'high']);
expect(updated.default_reasoning_level).toBe('low');
});
test('校验上下文、压缩阈值和输入类型', () => {
expect(validateCodexModelConfiguration(configuration())).toBeNull();
expect(validateCodexModelConfiguration({ ...configuration(), max_context_window: 64_000 }))
.toBe('agents.catalog.invalidMaximum');
expect(validateCodexModelConfiguration({ ...configuration(), auto_compact_token_limit: 200_000 }))
.toBe('agents.catalog.invalidCompact');
expect(validateCodexModelConfiguration({ ...configuration(), input_modalities: [] }))
.toBe('agents.catalog.invalidModalities');
});
});