import { describe, it, expect } from 'vitest'; import { normModelKey, findDevModel, sanitizePositiveInt, mergeModelCapabilities } from '../src/client/modelsDev'; import { I18N_DICT } from '../src/client/i18n'; describe('modelsDev utils', () => { it('normalizes model keys consistently', () => { expect(normModelKey('openai/gpt-4o-mini-20240718')).toBe('gpt4omini'); expect(normModelKey('claude-3-5-sonnet-20241022')).toBe('claude35sonnet'); expect(normModelKey('deepseek/deepseek-chat')).toBe('deepseekchat'); }); it('matches fuzzy dev models', () => { const list = [ { id: 'openai/gpt-4o', rawKey: 'gpt-4o', name: 'GPT-4o', modalities: { input: ['text', 'image'] }, reasoning: false }, { id: 'anthropic/claude-3-5-sonnet', rawKey: 'claude-3-5-sonnet', name: 'Claude 3.5 Sonnet', modalities: { input: ['text', 'image'] }, reasoning: false }, { id: 'deepseek/deepseek-r1', rawKey: 'deepseek-r1', name: 'DeepSeek R1', modalities: { input: ['text'] }, reasoning: true } ]; expect(findDevModel('gpt-4o', list)?.id).toBe('openai/gpt-4o'); expect(findDevModel('claude-3-5-sonnet-20241022', list)?.id).toBe('anthropic/claude-3-5-sonnet'); expect(findDevModel('deepseek-r1', list)?.id).toBe('deepseek/deepseek-r1'); }); it('sanitizes positive integers correctly and filters non-positive or non-finite values', () => { expect(sanitizePositiveInt(128000)).toBe(128000); expect(sanitizePositiveInt(1)).toBe(1); expect(sanitizePositiveInt('4096')).toBe(4096); expect(sanitizePositiveInt(0)).toBeUndefined(); expect(sanitizePositiveInt(-10)).toBeUndefined(); expect(sanitizePositiveInt(NaN)).toBeUndefined(); expect(sanitizePositiveInt(Infinity)).toBeUndefined(); expect(sanitizePositiveInt(-Infinity)).toBeUndefined(); expect(sanitizePositiveInt(128.5)).toBeUndefined(); expect(sanitizePositiveInt('0')).toBeUndefined(); expect(sanitizePositiveInt('-1')).toBeUndefined(); expect(sanitizePositiveInt('abc')).toBeUndefined(); expect(sanitizePositiveInt(null)).toBeUndefined(); expect(sanitizePositiveInt(undefined)).toBeUndefined(); }); it('merges model capabilities without writing zero or invalid contextWindow/maxTokens', () => { const matchedWithZero = { id: 'test/model-zero', rawKey: 'model-zero', name: 'Model Zero', limit: { context: 0, output: 0 }, modalities: { input: ['text'] }, reasoning: false }; const targetModel = { id: 'model-zero', name: 'Existing Name' }; const merged = mergeModelCapabilities(targetModel, matchedWithZero as any); expect(merged.id).toBe('model-zero'); expect(merged.name).toBe('Existing Name'); expect(merged.contextWindow).toBeUndefined(); expect('contextWindow' in merged).toBe(false); expect(merged.maxTokens).toBeUndefined(); expect('maxTokens' in merged).toBe(false); }); it('preserves valid existing contextWindow/maxTokens when incoming is zero or missing', () => { const matchedWithZero = { id: 'test/model-zero', rawKey: 'model-zero', name: 'Model Zero', limit: { context: 0, output: 0 } }; const existingModel = { id: 'model-zero', contextWindow: 131072, maxTokens: 8192 }; const merged = mergeModelCapabilities(existingModel, matchedWithZero as any); expect(merged.contextWindow).toBe(131072); expect(merged.maxTokens).toBe(8192); }); it('populates valid positive contextWindow/maxTokens from models.dev when existing is missing', () => { const matchedValid = { id: 'openai/gpt-4o', rawKey: 'gpt-4o', name: 'GPT-4o', limit: { context: 128000, output: 16384 } }; const existingModel = { id: 'gpt-4o' }; const merged = mergeModelCapabilities(existingModel, matchedValid as any); expect(merged.contextWindow).toBe(128000); expect(merged.maxTokens).toBe(16384); }); it('cleans up invalid existing values if present and matched is missing or zero', () => { const matchedWithZero = { id: 'test/model-bad', rawKey: 'model-bad', limit: { context: 0, output: -1 } }; const existingModelWithZero = { id: 'model-bad', contextWindow: 0, maxTokens: -5 }; const merged = mergeModelCapabilities(existingModelWithZero, matchedWithZero as any); expect('contextWindow' in merged).toBe(false); expect('maxTokens' in merged).toBe(false); }); it('provides bilingual dictionary keys', () => { expect(I18N_DICT.zh.modalTitle).toBeDefined(); expect(I18N_DICT.en.modalTitle).toBeDefined(); expect(I18N_DICT.zh.batchBtn).toBeDefined(); expect(I18N_DICT.en.batchBtn).toBeDefined(); }); });