mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 06:16:37 +00:00
573 lines
20 KiB
TypeScript
573 lines
20 KiB
TypeScript
/**
|
|
* Composite Variant Thinking Configuration Tests
|
|
*
|
|
* Tests per-tier thinking configuration for composite variants
|
|
*/
|
|
|
|
import { describe, it, expect } from 'bun:test';
|
|
import {
|
|
applyThinkingConfig,
|
|
applyThinkingSuffix,
|
|
detectTierFromModel,
|
|
getThinkingValueForTier,
|
|
} from '../../../src/cliproxy/config/thinking-config';
|
|
import { CLIProxyProvider } from '../../../src/cliproxy/types';
|
|
|
|
// ========================================
|
|
// applyThinkingSuffix
|
|
// ========================================
|
|
|
|
describe('applyThinkingSuffix', () => {
|
|
it('should append level name to model', () => {
|
|
const result = applyThinkingSuffix('gemini-3-pro-preview', 'high');
|
|
expect(result).toBe('gemini-3-pro-preview(high)');
|
|
});
|
|
|
|
it('should append numeric budget to model', () => {
|
|
const result = applyThinkingSuffix('claude-opus-4-6-thinking', 8192);
|
|
expect(result).toBe('claude-opus-4-6-thinking(8192)');
|
|
});
|
|
|
|
it('should not append suffix if model already has one', () => {
|
|
const result = applyThinkingSuffix('gemini-3-pro-preview(medium)', 'high');
|
|
expect(result).toBe('gemini-3-pro-preview(medium)');
|
|
});
|
|
|
|
it('should not append suffix if model already has numeric budget', () => {
|
|
const result = applyThinkingSuffix('claude-opus-4(8192)', 16384);
|
|
expect(result).toBe('claude-opus-4(8192)');
|
|
});
|
|
|
|
it('should handle empty parentheses as NOT having suffix', () => {
|
|
const result = applyThinkingSuffix('model()', 'high');
|
|
// Empty parens don't match regex /\([^)]+\)$/ (requires non-empty content)
|
|
expect(result).toBe('model()(high)');
|
|
});
|
|
|
|
it('should append to model with hyphens', () => {
|
|
const result = applyThinkingSuffix('gpt-4o-mini', 'low');
|
|
expect(result).toBe('gpt-4o-mini(low)');
|
|
});
|
|
});
|
|
|
|
// ========================================
|
|
// detectTierFromModel
|
|
// ========================================
|
|
|
|
describe('detectTierFromModel', () => {
|
|
it('should detect opus from model name containing "opus"', () => {
|
|
const result = detectTierFromModel('claude-opus-4-6-thinking');
|
|
expect(result).toBe('opus');
|
|
});
|
|
|
|
it('should detect sonnet from model name containing "sonnet"', () => {
|
|
const result = detectTierFromModel('claude-sonnet-4-5-thinking');
|
|
expect(result).toBe('sonnet');
|
|
});
|
|
|
|
it('should detect haiku from model name containing "haiku"', () => {
|
|
const result = detectTierFromModel('claude-haiku-4-5-20251001');
|
|
expect(result).toBe('haiku');
|
|
});
|
|
|
|
it('should default to sonnet for unknown model names', () => {
|
|
const result = detectTierFromModel('gpt-4o-mini');
|
|
expect(result).toBe('sonnet');
|
|
});
|
|
|
|
it('should default to sonnet for gemini models', () => {
|
|
const result = detectTierFromModel('gemini-3-pro-preview');
|
|
expect(result).toBe('sonnet');
|
|
});
|
|
|
|
it('should be case-insensitive', () => {
|
|
const result = detectTierFromModel('CLAUDE-OPUS-4');
|
|
expect(result).toBe('opus');
|
|
});
|
|
|
|
it('should detect haiku even with uppercase', () => {
|
|
const result = detectTierFromModel('CLAUDE-HAIKU-4');
|
|
expect(result).toBe('haiku');
|
|
});
|
|
});
|
|
|
|
// ========================================
|
|
// getThinkingValueForTier (mock config)
|
|
// ========================================
|
|
|
|
describe('getThinkingValueForTier', () => {
|
|
// Note: This function reads from unified config, so we're testing the logic
|
|
// For full integration tests, see composite-variant-service.test.ts
|
|
|
|
it('should return tier default when no provider override', () => {
|
|
const thinkingConfig = {
|
|
mode: 'auto' as const,
|
|
tier_defaults: {
|
|
opus: 'high',
|
|
sonnet: 'medium',
|
|
haiku: 'low',
|
|
},
|
|
};
|
|
|
|
const result = getThinkingValueForTier('opus', 'agy' as CLIProxyProvider, thinkingConfig);
|
|
expect(result).toBe('high');
|
|
});
|
|
|
|
it('should return provider-specific override when configured', () => {
|
|
const thinkingConfig = {
|
|
mode: 'auto' as const,
|
|
tier_defaults: {
|
|
opus: 'high',
|
|
sonnet: 'medium',
|
|
haiku: 'low',
|
|
},
|
|
provider_overrides: {
|
|
gemini: {
|
|
opus: 'xhigh',
|
|
sonnet: 'high',
|
|
haiku: 'medium',
|
|
},
|
|
},
|
|
};
|
|
|
|
const result = getThinkingValueForTier('opus', 'gemini' as CLIProxyProvider, thinkingConfig);
|
|
expect(result).toBe('xhigh');
|
|
});
|
|
|
|
it('should fall back to tier default when provider has no override for tier', () => {
|
|
const thinkingConfig = {
|
|
mode: 'auto' as const,
|
|
tier_defaults: {
|
|
opus: 'high',
|
|
sonnet: 'medium',
|
|
haiku: 'low',
|
|
},
|
|
provider_overrides: {
|
|
gemini: {
|
|
opus: 'xhigh',
|
|
// No sonnet override
|
|
},
|
|
},
|
|
};
|
|
|
|
const result = getThinkingValueForTier('sonnet', 'gemini' as CLIProxyProvider, thinkingConfig);
|
|
expect(result).toBe('medium');
|
|
});
|
|
|
|
it('should use centralized defaults when tier_defaults undefined', () => {
|
|
const thinkingConfig = {
|
|
mode: 'auto' as const,
|
|
// tier_defaults is optional - centralized defaults kick in
|
|
};
|
|
|
|
const result = getThinkingValueForTier('opus', 'agy' as CLIProxyProvider, thinkingConfig);
|
|
// DEFAULT_THINKING_TIER_DEFAULTS.opus = 'high'
|
|
expect(result).toBe('high');
|
|
});
|
|
});
|
|
|
|
// ========================================
|
|
// applyThinkingConfig with compositeTierThinking
|
|
// ========================================
|
|
|
|
describe('applyThinkingConfig - composite variant integration', () => {
|
|
it('should apply per-tier thinking from compositeTierThinking parameter', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-6-thinking',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
|
};
|
|
|
|
const compositeTierThinking = {
|
|
opus: 'xhigh',
|
|
sonnet: 'medium',
|
|
haiku: 'low',
|
|
};
|
|
|
|
const result = applyThinkingConfig(
|
|
envVars,
|
|
'agy' as CLIProxyProvider,
|
|
undefined, // No CLI override
|
|
compositeTierThinking
|
|
);
|
|
|
|
// Budget-based tier models are normalized to provider-specific budget values.
|
|
expect(result.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking(32768)');
|
|
expect(result.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-5-thinking(8192)');
|
|
// Haiku doesn't support thinking per model-catalog — no suffix
|
|
expect(result.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('claude-haiku-4-5-20251001');
|
|
// ANTHROPIC_MODEL is validated: 'medium' → 8192 for budget-type models
|
|
expect(result.ANTHROPIC_MODEL).toBe('claude-sonnet-4-5-thinking(8192)');
|
|
});
|
|
|
|
it('should apply partial per-tier thinking (only some tiers specified)', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-6-thinking',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
|
};
|
|
|
|
const compositeTierThinking = {
|
|
opus: 'xhigh',
|
|
// sonnet and haiku will fall back to global config
|
|
};
|
|
|
|
const result = applyThinkingConfig(
|
|
envVars,
|
|
'agy' as CLIProxyProvider,
|
|
undefined,
|
|
compositeTierThinking
|
|
);
|
|
|
|
// Budget-based tier models are normalized to provider-specific budget values.
|
|
expect(result.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking(32768)');
|
|
// Sonnet gets defaults from global config (mode=auto)
|
|
expect(result.ANTHROPIC_DEFAULT_SONNET_MODEL).toContain('claude-sonnet-4-5-thinking');
|
|
// Haiku doesn't support thinking — stays unchanged
|
|
expect(result.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('claude-haiku-4-5-20251001');
|
|
});
|
|
|
|
it('should allow per-tier thinking to be "off"', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-6-thinking',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
|
};
|
|
|
|
const compositeTierThinking = {
|
|
opus: 'high',
|
|
sonnet: 'medium',
|
|
haiku: 'off', // Explicitly disabled for haiku
|
|
};
|
|
|
|
const result = applyThinkingConfig(
|
|
envVars,
|
|
'agy' as CLIProxyProvider,
|
|
undefined,
|
|
compositeTierThinking
|
|
);
|
|
|
|
expect(result.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking(24576)');
|
|
expect(result.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-5-thinking(8192)');
|
|
// Haiku should NOT have suffix because thinking is not supported for haiku
|
|
expect(result.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('claude-haiku-4-5-20251001');
|
|
});
|
|
|
|
it('should prioritize CLI override over per-tier thinking', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-6-thinking',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
|
};
|
|
|
|
const compositeTierThinking = {
|
|
opus: 'xhigh',
|
|
sonnet: 'medium',
|
|
haiku: 'low',
|
|
};
|
|
|
|
const result = applyThinkingConfig(
|
|
envVars,
|
|
'agy' as CLIProxyProvider,
|
|
'minimal', // CLI override takes priority
|
|
compositeTierThinking
|
|
);
|
|
|
|
// All thinking-capable tiers should use the validated CLI override.
|
|
expect(result.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking(1024)');
|
|
expect(result.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-5-thinking(1024)');
|
|
// Haiku doesn't support thinking — stays unchanged regardless of CLI override
|
|
expect(result.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('claude-haiku-4-5-20251001');
|
|
});
|
|
|
|
it('should disable all tier thinking when CLI override is explicitly off', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-6-thinking',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
|
};
|
|
|
|
const compositeTierThinking = {
|
|
opus: 'xhigh',
|
|
sonnet: 'medium',
|
|
haiku: 'low',
|
|
};
|
|
|
|
const result = applyThinkingConfig(
|
|
envVars,
|
|
'agy' as CLIProxyProvider,
|
|
'off',
|
|
compositeTierThinking
|
|
);
|
|
|
|
expect(result.ANTHROPIC_MODEL).toBe('claude-sonnet-4-5-thinking');
|
|
expect(result.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking');
|
|
expect(result.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-5-thinking');
|
|
expect(result.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('claude-haiku-4-5-20251001');
|
|
});
|
|
|
|
it('treats off override aliases case-insensitively', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-6-thinking',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
|
};
|
|
|
|
const result = applyThinkingConfig(envVars, 'agy' as CLIProxyProvider, 'OFF', {
|
|
opus: 'xhigh',
|
|
sonnet: 'high',
|
|
});
|
|
|
|
expect(result.ANTHROPIC_MODEL).toBe('claude-sonnet-4-5-thinking');
|
|
expect(result.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking');
|
|
expect(result.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-5-thinking');
|
|
});
|
|
|
|
it('uses per-tier provider capability checks for mixed-provider composites', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'gemini-2.5-pro',
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'gemini-2.5-pro',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
|
};
|
|
|
|
const result = applyThinkingConfig(
|
|
envVars,
|
|
'gemini' as CLIProxyProvider,
|
|
undefined,
|
|
{
|
|
sonnet: 'high',
|
|
},
|
|
{
|
|
sonnet: { provider: 'agy' as CLIProxyProvider },
|
|
}
|
|
);
|
|
|
|
expect(result.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-5-thinking(24576)');
|
|
});
|
|
|
|
it('applies tier thinking even when default model does not support thinking', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'gpt-4o-mini',
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'gpt-4o-mini',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
|
};
|
|
|
|
const result = applyThinkingConfig(
|
|
envVars,
|
|
'codex' as CLIProxyProvider,
|
|
undefined,
|
|
{
|
|
sonnet: 'high',
|
|
},
|
|
{
|
|
sonnet: { provider: 'agy' as CLIProxyProvider },
|
|
}
|
|
);
|
|
|
|
// Default model provider/model do not support thinking.
|
|
expect(result.ANTHROPIC_MODEL).toBe('gpt-4o-mini');
|
|
// Supported mixed-provider tier must still receive its configured thinking value.
|
|
expect(result.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-5-thinking(24576)');
|
|
});
|
|
|
|
it('handles dotted agy Claude IDs for thinking capability lookup', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-opus-4.5-thinking',
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4.5-thinking',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4.5-thinking',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4.5',
|
|
};
|
|
|
|
const result = applyThinkingConfig(envVars, 'agy' as CLIProxyProvider, 'high');
|
|
|
|
// Capability lookup should succeed for dotted agy IDs after normalization.
|
|
// Tier values are normalized through budget validation too.
|
|
expect(result.ANTHROPIC_MODEL).toBe('claude-opus-4.5-thinking(24576)');
|
|
expect(result.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4.5-thinking(24576)');
|
|
expect(result.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4.5-thinking(24576)');
|
|
// Haiku does not support thinking in agy catalog.
|
|
expect(result.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('claude-haiku-4.5');
|
|
});
|
|
|
|
it('should handle numeric budgets in per-tier thinking', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-6-thinking',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
|
};
|
|
|
|
const compositeTierThinking = {
|
|
opus: '32768',
|
|
sonnet: '8192',
|
|
haiku: '512',
|
|
};
|
|
|
|
const result = applyThinkingConfig(
|
|
envVars,
|
|
'agy' as CLIProxyProvider,
|
|
undefined,
|
|
compositeTierThinking
|
|
);
|
|
|
|
// Tier models keep numeric values after validation when the provider supports them.
|
|
expect(result.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking(32768)');
|
|
expect(result.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-5-thinking(8192)');
|
|
// Haiku doesn't support thinking — stays unchanged
|
|
expect(result.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('claude-haiku-4-5-20251001');
|
|
});
|
|
|
|
it('should not apply thinking when mode is off and no override', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-6-thinking',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
|
};
|
|
|
|
const compositeTierThinking = {
|
|
opus: 'high',
|
|
sonnet: 'medium',
|
|
haiku: 'low',
|
|
};
|
|
|
|
// Mock thinking config with mode=off by calling without thinkingOverride
|
|
// and ensuring global config mode is 'off'
|
|
// This test would require mocking getThinkingConfig()
|
|
// For now, test the behavior when compositeTierThinking is undefined
|
|
|
|
const result = applyThinkingConfig(
|
|
envVars,
|
|
'agy' as CLIProxyProvider,
|
|
undefined,
|
|
undefined // No per-tier thinking
|
|
);
|
|
|
|
// When mode=auto and no compositeTierThinking, defaults apply
|
|
// This depends on global config - skipping full integration test here
|
|
expect(result).toBeDefined();
|
|
});
|
|
|
|
it('should skip thinking for models that do not support it', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'gpt-4o-mini', // Model that doesn't support thinking
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'gpt-4o-mini',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'gpt-4o-mini',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'gpt-4o-mini',
|
|
};
|
|
|
|
const compositeTierThinking = {
|
|
opus: 'high',
|
|
sonnet: 'medium',
|
|
haiku: 'low',
|
|
};
|
|
|
|
const result = applyThinkingConfig(
|
|
envVars,
|
|
'codex' as CLIProxyProvider,
|
|
undefined,
|
|
compositeTierThinking
|
|
);
|
|
|
|
// Models should remain unchanged (no thinking suffix) because they don't support it
|
|
// Note: This depends on supportsThinking() logic in model-catalog.ts
|
|
// For models that don't support thinking, no suffix should be added
|
|
expect(result.ANTHROPIC_MODEL).toBe('gpt-4o-mini');
|
|
});
|
|
|
|
it('should update ANTHROPIC_MODEL when it matches a tier model', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-opus-4-6-thinking', // Matches opus tier
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-6-thinking',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
|
};
|
|
|
|
const compositeTierThinking = {
|
|
opus: 'xhigh',
|
|
sonnet: 'medium',
|
|
haiku: 'low',
|
|
};
|
|
|
|
const result = applyThinkingConfig(
|
|
envVars,
|
|
'agy' as CLIProxyProvider,
|
|
undefined,
|
|
compositeTierThinking
|
|
);
|
|
|
|
// ANTHROPIC_MODEL is validated: xhigh → 32768 for budget-type models
|
|
expect(result.ANTHROPIC_MODEL).toBe('claude-opus-4-6-thinking(32768)');
|
|
// Tier model keeps the validated budget value.
|
|
expect(result.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking(32768)');
|
|
});
|
|
|
|
it('should preserve models that already have thinking suffix', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'claude-sonnet-4-5-thinking(high)', // Already has suffix
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-6-thinking',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking(high)',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
|
};
|
|
|
|
const compositeTierThinking = {
|
|
opus: 'xhigh',
|
|
sonnet: 'medium', // Won't override existing suffix
|
|
haiku: 'low',
|
|
};
|
|
|
|
const result = applyThinkingConfig(
|
|
envVars,
|
|
'agy' as CLIProxyProvider,
|
|
undefined,
|
|
compositeTierThinking
|
|
);
|
|
|
|
// Existing suffix on main model should be preserved.
|
|
expect(result.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-5-thinking(high)');
|
|
expect(result.ANTHROPIC_MODEL).toBe('claude-sonnet-4-5-thinking(high)');
|
|
// Other supported tiers still receive configured thinking after validation.
|
|
expect(result.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking(32768)');
|
|
});
|
|
|
|
it('should use codex effort suffix style when provider is codex', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'gpt-5.3-codex',
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'gpt-5.3-codex',
|
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'gpt-5.3-codex',
|
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'gpt-5-mini',
|
|
};
|
|
|
|
const result = applyThinkingConfig(
|
|
envVars,
|
|
'codex' as CLIProxyProvider,
|
|
'xhigh', // Explicit CLI override
|
|
undefined
|
|
);
|
|
|
|
expect(result.ANTHROPIC_MODEL).toBe('gpt-5.3-codex-xhigh');
|
|
expect(result.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('gpt-5.3-codex-xhigh');
|
|
expect(result.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('gpt-5.3-codex-xhigh');
|
|
expect(result.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('gpt-5-mini-high');
|
|
});
|
|
|
|
it('should normalize legacy codex parenthesized tier suffix to effort suffix format', () => {
|
|
const envVars: NodeJS.ProcessEnv = {
|
|
ANTHROPIC_MODEL: 'gpt-5.3-codex',
|
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'gpt-5.3-codex(high)',
|
|
};
|
|
|
|
const result = applyThinkingConfig(envVars, 'codex' as CLIProxyProvider, 'high');
|
|
|
|
expect(result.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('gpt-5.3-codex-high');
|
|
});
|
|
});
|