From fa7ff2639f83415d4f4be61819fc1391c281aeb0 Mon Sep 17 00:00:00 2001 From: zbigniew sobiecki Date: Sat, 25 Apr 2026 18:29:34 +0200 Subject: [PATCH] feat(models): add Opus 4.7, GPT-5.5, and 1M context variants to engine dropdowns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the latest Anthropic and OpenAI models to the dashboard engine pickers: - Claude Code: Opus 4.7, plus the 1M-context variants for Opus 4.7, Opus 4.6, and Sonnet 4.6 (using the canonical `[1m]` suffix syntax documented by Anthropic). - Codex: GPT-5.5. Also wire pricing metadata for the new model IDs (`claude-opus-4-7` = $5/$25 per Anthropic's current pricing — Opus pricing dropped vs the 4.1/4.5 generation; `gpt-5.5` = $5/$30 per OpenAI's published rates), and a conservative rate-limit profile for Opus 4.7 mirroring the existing Opus tier-1 throttle (50 RPM, 10K TPM). Defaults stay unchanged (Sonnet 4.5 for Claude Code, GPT-5.4 for Codex) to keep this PR additive. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/backends/claude-code/models.ts | 4 ++++ src/backends/codex/models.ts | 1 + src/config/rateLimits.ts | 7 +++++++ src/utils/llmMetrics.ts | 5 +++++ tests/unit/backends/claude-code.test.ts | 15 +++++++++++++-- 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/backends/claude-code/models.ts b/src/backends/claude-code/models.ts index 76707237..809f6f03 100644 --- a/src/backends/claude-code/models.ts +++ b/src/backends/claude-code/models.ts @@ -1,6 +1,10 @@ export const CLAUDE_CODE_MODELS = [ + { value: 'claude-opus-4-7', label: 'Claude Opus 4.7' }, + { value: 'claude-opus-4-7[1m]', label: 'Claude Opus 4.7 (1M context)' }, { value: 'claude-opus-4-6', label: 'Claude Opus 4.6' }, + { value: 'claude-opus-4-6[1m]', label: 'Claude Opus 4.6 (1M context)' }, { value: 'claude-sonnet-4-6', label: 'Claude Sonnet 4.6' }, + { value: 'claude-sonnet-4-6[1m]', label: 'Claude Sonnet 4.6 (1M context)' }, { value: 'claude-sonnet-4-5-20250929', label: 'Claude Sonnet 4.5' }, { value: 'claude-haiku-4-5-20251001', label: 'Claude Haiku 4.5' }, ] as const; diff --git a/src/backends/codex/models.ts b/src/backends/codex/models.ts index 0f73ed24..2b8648f6 100644 --- a/src/backends/codex/models.ts +++ b/src/backends/codex/models.ts @@ -1,4 +1,5 @@ export const CODEX_MODELS = [ + { value: 'gpt-5.5', label: 'GPT-5.5' }, { value: 'gpt-5.4', label: 'GPT-5.4' }, { value: 'gpt-5.3-codex', label: 'GPT-5.3 Codex' }, { value: 'gpt-5.3-codex-spark', label: 'GPT-5.3 Codex Spark' }, diff --git a/src/config/rateLimits.ts b/src/config/rateLimits.ts index 8165add6..5ab494d4 100644 --- a/src/config/rateLimits.ts +++ b/src/config/rateLimits.ts @@ -19,6 +19,13 @@ export const MODEL_RATE_LIMITS: ModelRateLimits = { safetyMargin: 0.8, // Conservative - start throttling at 80% }, + // Claude Opus 4.7 (Tier 1: 50 RPM, 10K TPM — Opus is throttle-sensitive) + 'anthropic:claude-opus-4-7': { + requestsPerMinute: 50, + tokensPerMinute: 10_000, + safetyMargin: 0.85, + }, + // Claude Sonnet 4.6 (Tier 1: 50 RPM, 40K TPM) 'anthropic:claude-sonnet-4-6': { requestsPerMinute: 50, diff --git a/src/utils/llmMetrics.ts b/src/utils/llmMetrics.ts index 97a3b2bb..e68a3c33 100644 --- a/src/utils/llmMetrics.ts +++ b/src/utils/llmMetrics.ts @@ -10,7 +10,11 @@ import type { TokenUsage } from 'llmist'; */ const MODEL_PRICING: Record = { // Anthropic Claude 4 family + 'anthropic:claude-opus-4-7': { input: 5.0, output: 25.0, cachedInput: 0.5 }, + 'anthropic:claude-opus-4-7[1m]': { input: 5.0, output: 25.0, cachedInput: 0.5 }, + 'anthropic:claude-opus-4-6[1m]': { input: 5.0, output: 25.0, cachedInput: 0.5 }, 'anthropic:claude-sonnet-4-6': { input: 3.0, output: 15.0, cachedInput: 0.3 }, + 'anthropic:claude-sonnet-4-6[1m]': { input: 3.0, output: 15.0, cachedInput: 0.3 }, 'anthropic:claude-sonnet-4-5': { input: 3.0, output: 15.0, cachedInput: 0.3 }, 'anthropic:claude-opus-4-5': { input: 15.0, output: 75.0, cachedInput: 1.5 }, 'anthropic:claude-haiku-3-5': { input: 0.8, output: 4.0, cachedInput: 0.08 }, @@ -20,6 +24,7 @@ const MODEL_PRICING: Record { }); describe('CLAUDE_CODE_MODELS constants', () => { - it('contains four models', () => { - expect(CLAUDE_CODE_MODELS).toHaveLength(4); + it('contains the expected models', () => { + expect(CLAUDE_CODE_MODELS).toHaveLength(8); + }); + + it('includes Opus 4.7 and the 1M context variants', () => { + expect(CLAUDE_CODE_MODEL_IDS).toContain('claude-opus-4-7'); + expect(CLAUDE_CODE_MODEL_IDS).toContain('claude-opus-4-7[1m]'); + expect(CLAUDE_CODE_MODEL_IDS).toContain('claude-sonnet-4-6[1m]'); + expect(CLAUDE_CODE_MODEL_IDS).toContain('claude-opus-4-6[1m]'); }); it('has value/label pairs', () => { @@ -315,6 +322,10 @@ describe('CLAUDE_CODE_MODELS constants', () => { describe('resolveClaudeModel', () => { it('passes through known Claude Code model IDs', () => { + expect(resolveClaudeModel('claude-opus-4-7')).toBe('claude-opus-4-7'); + expect(resolveClaudeModel('claude-opus-4-7[1m]')).toBe('claude-opus-4-7[1m]'); + expect(resolveClaudeModel('claude-sonnet-4-6[1m]')).toBe('claude-sonnet-4-6[1m]'); + expect(resolveClaudeModel('claude-opus-4-6[1m]')).toBe('claude-opus-4-6[1m]'); expect(resolveClaudeModel('claude-opus-4-6')).toBe('claude-opus-4-6'); expect(resolveClaudeModel('claude-sonnet-4-6')).toBe('claude-sonnet-4-6'); expect(resolveClaudeModel('claude-sonnet-4-5-20250929')).toBe('claude-sonnet-4-5-20250929');