| |
| |
| |
| |
|
|
| import { describe, it, expect } from 'vitest'; |
| import { |
| formatModelName, |
| DEFAULT_MODEL, |
| type FormatModelNameOptions, |
| } from '../../../src/lib/agent-context-parser'; |
| import type { ClaudeCompatibleProvider, ProviderModel } from '@automaker/types'; |
|
|
| describe('agent-context-parser.ts', () => { |
| describe('DEFAULT_MODEL', () => { |
| it('should be claude-opus-4-6', () => { |
| expect(DEFAULT_MODEL).toBe('claude-opus-4-6'); |
| }); |
| }); |
|
|
| describe('formatModelName', () => { |
| describe('Provider-aware lookup', () => { |
| it('should return provider displayName when providerId matches and model is found', () => { |
| const providers: ClaudeCompatibleProvider[] = [ |
| { |
| id: 'moonshot-ai', |
| name: 'Moonshot AI', |
| models: [ |
| { id: 'claude-sonnet-4-5', displayName: 'Moonshot v1.8' }, |
| { id: 'claude-opus-4-6', displayName: 'Moonshot v1.8 Pro' }, |
| ], |
| }, |
| ]; |
|
|
| const options: FormatModelNameOptions = { |
| providerId: 'moonshot-ai', |
| claudeCompatibleProviders: providers, |
| }; |
|
|
| expect(formatModelName('claude-sonnet-4-5', options)).toBe('Moonshot v1.8'); |
| expect(formatModelName('claude-opus-4-6', options)).toBe('Moonshot v1.8 Pro'); |
| }); |
|
|
| it('should return provider displayName for GLM models', () => { |
| const providers: ClaudeCompatibleProvider[] = [ |
| { |
| id: 'zhipu', |
| name: 'Zhipu AI', |
| models: [ |
| { id: 'claude-sonnet-4-5', displayName: 'GLM 4.7' }, |
| { id: 'claude-opus-4-6', displayName: 'GLM 4.7 Pro' }, |
| ], |
| }, |
| ]; |
|
|
| const options: FormatModelNameOptions = { |
| providerId: 'zhipu', |
| claudeCompatibleProviders: providers, |
| }; |
|
|
| expect(formatModelName('claude-sonnet-4-5', options)).toBe('GLM 4.7'); |
| }); |
|
|
| it('should return provider displayName for MiniMax models', () => { |
| const providers: ClaudeCompatibleProvider[] = [ |
| { |
| id: 'minimax', |
| name: 'MiniMax', |
| models: [ |
| { id: 'claude-sonnet-4-5', displayName: 'MiniMax M2.1' }, |
| { id: 'claude-opus-4-6', displayName: 'MiniMax M2.1 Pro' }, |
| ], |
| }, |
| ]; |
|
|
| const options: FormatModelNameOptions = { |
| providerId: 'minimax', |
| claudeCompatibleProviders: providers, |
| }; |
|
|
| expect(formatModelName('claude-sonnet-4-5', options)).toBe('MiniMax M2.1'); |
| }); |
|
|
| it('should fallback to default formatting when providerId is not found', () => { |
| const providers: ClaudeCompatibleProvider[] = [ |
| { |
| id: 'moonshot-ai', |
| name: 'Moonshot AI', |
| models: [{ id: 'claude-sonnet-4-5', displayName: 'Moonshot v1.8' }], |
| }, |
| ]; |
|
|
| const options: FormatModelNameOptions = { |
| providerId: 'unknown-provider', |
| claudeCompatibleProviders: providers, |
| }; |
|
|
| |
| expect(formatModelName('claude-sonnet-4-5', options)).toBe('Sonnet 4.5'); |
| }); |
|
|
| it('should fallback to default formatting when model is not in provider models', () => { |
| const providers: ClaudeCompatibleProvider[] = [ |
| { |
| id: 'moonshot-ai', |
| name: 'Moonshot AI', |
| models: [{ id: 'claude-sonnet-4-5', displayName: 'Moonshot v1.8' }], |
| }, |
| ]; |
|
|
| const options: FormatModelNameOptions = { |
| providerId: 'moonshot-ai', |
| claudeCompatibleProviders: providers, |
| }; |
|
|
| |
| expect(formatModelName('claude-haiku-4-5', options)).toBe('Haiku 4.5'); |
| }); |
|
|
| it('should handle empty providers array', () => { |
| const options: FormatModelNameOptions = { |
| providerId: 'moonshot-ai', |
| claudeCompatibleProviders: [], |
| }; |
|
|
| expect(formatModelName('claude-sonnet-4-5', options)).toBe('Sonnet 4.5'); |
| }); |
|
|
| it('should handle provider with no models array', () => { |
| const providers: ClaudeCompatibleProvider[] = [ |
| { |
| id: 'moonshot-ai', |
| name: 'Moonshot AI', |
| }, |
| ]; |
|
|
| const options: FormatModelNameOptions = { |
| providerId: 'moonshot-ai', |
| claudeCompatibleProviders: providers, |
| }; |
|
|
| expect(formatModelName('claude-sonnet-4-5', options)).toBe('Sonnet 4.5'); |
| }); |
|
|
| it('should handle model with no displayName', () => { |
| const providers: ClaudeCompatibleProvider[] = [ |
| { |
| id: 'moonshot-ai', |
| name: 'Moonshot AI', |
| models: [{ id: 'claude-sonnet-4-5' } as unknown as ProviderModel], |
| }, |
| ]; |
|
|
| const options: FormatModelNameOptions = { |
| providerId: 'moonshot-ai', |
| claudeCompatibleProviders: providers, |
| }; |
|
|
| expect(formatModelName('claude-sonnet-4-5', options)).toBe('Sonnet 4.5'); |
| }); |
|
|
| it('should ignore provider lookup when providerId is undefined', () => { |
| const providers: ClaudeCompatibleProvider[] = [ |
| { |
| id: 'moonshot-ai', |
| name: 'Moonshot AI', |
| models: [{ id: 'claude-sonnet-4-5', displayName: 'Moonshot v1.8' }], |
| }, |
| ]; |
|
|
| const options: FormatModelNameOptions = { |
| providerId: undefined, |
| claudeCompatibleProviders: providers, |
| }; |
|
|
| expect(formatModelName('claude-sonnet-4-5', options)).toBe('Sonnet 4.5'); |
| }); |
|
|
| it('should ignore provider lookup when claudeCompatibleProviders is undefined', () => { |
| const options: FormatModelNameOptions = { |
| providerId: 'moonshot-ai', |
| claudeCompatibleProviders: undefined, |
| }; |
|
|
| expect(formatModelName('claude-sonnet-4-5', options)).toBe('Sonnet 4.5'); |
| }); |
|
|
| it('should use default formatting when no options provided', () => { |
| expect(formatModelName('claude-sonnet-4-5')).toBe('Sonnet 4.5'); |
| expect(formatModelName('claude-opus-4-6')).toBe('Opus 4.6'); |
| }); |
|
|
| it('should handle OpenRouter provider with multiple models', () => { |
| const providers: ClaudeCompatibleProvider[] = [ |
| { |
| id: 'openrouter', |
| name: 'OpenRouter', |
| models: [ |
| { id: 'claude-sonnet-4-5', displayName: 'Claude Sonnet (OpenRouter)' }, |
| { id: 'claude-opus-4-6', displayName: 'Claude Opus (OpenRouter)' }, |
| { id: 'gpt-4o', displayName: 'GPT-4o (OpenRouter)' }, |
| ], |
| }, |
| ]; |
|
|
| const options: FormatModelNameOptions = { |
| providerId: 'openrouter', |
| claudeCompatibleProviders: providers, |
| }; |
|
|
| expect(formatModelName('claude-sonnet-4-5', options)).toBe('Claude Sonnet (OpenRouter)'); |
| expect(formatModelName('claude-opus-4-6', options)).toBe('Claude Opus (OpenRouter)'); |
| expect(formatModelName('gpt-4o', options)).toBe('GPT-4o (OpenRouter)'); |
| }); |
| }); |
|
|
| describe('Claude model formatting (default)', () => { |
| it('should format claude-opus-4-6 as Opus 4.6', () => { |
| expect(formatModelName('claude-opus-4-6')).toBe('Opus 4.6'); |
| }); |
|
|
| it('should format claude-opus as Opus 4.6', () => { |
| expect(formatModelName('claude-opus')).toBe('Opus 4.6'); |
| }); |
|
|
| it('should format other opus models as Opus 4.5', () => { |
| expect(formatModelName('claude-opus-4-5')).toBe('Opus 4.5'); |
| expect(formatModelName('claude-3-opus')).toBe('Opus 4.5'); |
| }); |
|
|
| it('should format claude-sonnet-4-6 as Sonnet 4.6', () => { |
| expect(formatModelName('claude-sonnet-4-6')).toBe('Sonnet 4.6'); |
| }); |
|
|
| it('should format claude-sonnet as Sonnet 4.6', () => { |
| expect(formatModelName('claude-sonnet')).toBe('Sonnet 4.6'); |
| }); |
|
|
| it('should format other sonnet models as Sonnet 4.5', () => { |
| expect(formatModelName('claude-sonnet-4-5')).toBe('Sonnet 4.5'); |
| expect(formatModelName('claude-3-sonnet')).toBe('Sonnet 4.5'); |
| }); |
|
|
| it('should format haiku models as Haiku 4.5', () => { |
| expect(formatModelName('claude-haiku-4-5')).toBe('Haiku 4.5'); |
| expect(formatModelName('claude-3-haiku')).toBe('Haiku 4.5'); |
| expect(formatModelName('claude-haiku')).toBe('Haiku 4.5'); |
| }); |
| }); |
|
|
| describe('Codex/GPT model formatting', () => { |
| it('should format codex-gpt-5.3-codex as GPT-5.3 Codex', () => { |
| expect(formatModelName('codex-gpt-5.3-codex')).toBe('GPT-5.3 Codex'); |
| }); |
|
|
| it('should format codex-gpt-5.2-codex as GPT-5.2 Codex', () => { |
| expect(formatModelName('codex-gpt-5.2-codex')).toBe('GPT-5.2 Codex'); |
| }); |
|
|
| it('should format codex-gpt-5.2 as GPT-5.2', () => { |
| expect(formatModelName('codex-gpt-5.2')).toBe('GPT-5.2'); |
| }); |
|
|
| it('should format codex-gpt-5.1-codex-max as GPT-5.1 Max', () => { |
| expect(formatModelName('codex-gpt-5.1-codex-max')).toBe('GPT-5.1 Max'); |
| }); |
|
|
| it('should format codex-gpt-5.1-codex-mini as GPT-5.1 Mini', () => { |
| expect(formatModelName('codex-gpt-5.1-codex-mini')).toBe('GPT-5.1 Mini'); |
| }); |
|
|
| it('should format codex-gpt-5.1 as GPT-5.1', () => { |
| expect(formatModelName('codex-gpt-5.1')).toBe('GPT-5.1'); |
| }); |
|
|
| it('should format gpt- prefixed models in uppercase', () => { |
| expect(formatModelName('gpt-4o')).toBe('GPT-4O'); |
| expect(formatModelName('gpt-4-turbo')).toBe('GPT-4-TURBO'); |
| }); |
|
|
| it('should format o-prefixed models (o1, o3, etc.) in uppercase', () => { |
| expect(formatModelName('o1')).toBe('O1'); |
| expect(formatModelName('o1-mini')).toBe('O1-MINI'); |
| expect(formatModelName('o3')).toBe('O3'); |
| }); |
| }); |
|
|
| describe('Cursor model formatting', () => { |
| it('should format cursor-auto as Cursor Auto', () => { |
| expect(formatModelName('cursor-auto')).toBe('Cursor Auto'); |
| }); |
|
|
| it('should format auto as Cursor Auto', () => { |
| expect(formatModelName('auto')).toBe('Cursor Auto'); |
| }); |
|
|
| it('should format cursor-composer-1 as Composer 1', () => { |
| expect(formatModelName('cursor-composer-1')).toBe('Composer 1'); |
| }); |
|
|
| it('should format composer-1 as Composer 1', () => { |
| expect(formatModelName('composer-1')).toBe('Composer 1'); |
| }); |
|
|
| it('should format cursor-sonnet (but falls through to Sonnet due to earlier check)', () => { |
| |
| expect(formatModelName('cursor-sonnet')).toBe('Sonnet 4.5'); |
| expect(formatModelName('cursor-sonnet-4-5')).toBe('Sonnet 4.5'); |
| }); |
|
|
| it('should format cursor-opus (but falls through to Opus due to earlier check)', () => { |
| |
| expect(formatModelName('cursor-opus')).toBe('Opus 4.5'); |
| expect(formatModelName('cursor-opus-4-6')).toBe('Opus 4.6'); |
| }); |
|
|
| it('should format cursor-gpt models', () => { |
| |
| expect(formatModelName('cursor-gpt-4')).toBe('GPT-4'); |
| |
| expect(formatModelName('cursor-gpt-4o')).toBe('GPT-4o'); |
| }); |
|
|
| it('should format cursor-gemini models', () => { |
| |
| expect(formatModelName('cursor-gemini-pro')).toBe('Cursor Gemini-pro'); |
| |
| expect(formatModelName('cursor-gemini-2')).toBe('Cursor Gemini-2'); |
| }); |
|
|
| it('should format cursor-grok as Cursor Grok', () => { |
| expect(formatModelName('cursor-grok')).toBe('Cursor Grok'); |
| }); |
| }); |
|
|
| describe('Unknown model formatting (fallback)', () => { |
| it('should format unknown models by splitting and joining parts', () => { |
| |
| expect(formatModelName('unknown-model-name')).toBe('model name'); |
| expect(formatModelName('some-random-model')).toBe('random model'); |
| }); |
|
|
| it('should handle models with fewer parts', () => { |
| expect(formatModelName('single')).toBe(''); |
| expect(formatModelName('two-parts')).toBe('parts'); |
| }); |
| }); |
| }); |
| }); |
|
|