feat: add claude-opus-4-7 model and update all model costs

Adds Claude Opus 4.7 to the model picker as the new most capable model.
Reorganises model list to reflect current vs previous generation, and
marks Sonnet 4 and Opus 4 as deprecated (retiring June 15, 2026).

Also corrects claude-opus-4-6 context window from 200K to 1M tokens,
and updates pricing comments to reflect May 2026 source date.

Closes #268
This commit is contained in:
2026-05-06 13:18:46 -07:00
committed by Naomi Carrigan
parent 7a1ab89ad8
commit bbbddaceaa
3 changed files with 43 additions and 15 deletions
+30 -7
View File
@@ -86,9 +86,10 @@ impl ContextWarning {
/// Get the context window limit (in tokens) for a given model /// Get the context window limit (in tokens) for a given model
fn get_context_window_limit(model: &str) -> u64 { fn get_context_window_limit(model: &str) -> u64 {
match model { match model {
// Claude 4.6 family // Claude 4.7 - 1M token context window
"claude-opus-4-6" => 200_000, "claude-opus-4-7" => 1_000_000,
"claude-sonnet-4-6" => 1_000_000, // 1M token context window // Claude 4.6 family - 1M token context window
"claude-opus-4-6" | "claude-sonnet-4-6" => 1_000_000,
// Claude 4.5 family - 200K standard context // Claude 4.5 family - 200K standard context
"claude-opus-4-5-20251101" "claude-opus-4-5-20251101"
| "claude-sonnet-4-5-20250929" | "claude-sonnet-4-5-20250929"
@@ -490,7 +491,7 @@ fn is_consecutive_day(prev_date: &str, current_date: &str) -> bool {
} }
} }
// Pricing as of February 2026 // Pricing as of May 2026
// https://platform.claude.com/docs/en/about-claude/models/overview // https://platform.claude.com/docs/en/about-claude/models/overview
// Cache pricing: https://platform.claude.com/docs/en/build-with-claude/prompt-caching // Cache pricing: https://platform.claude.com/docs/en/build-with-claude/prompt-caching
pub fn calculate_cost( pub fn calculate_cost(
@@ -501,14 +502,17 @@ pub fn calculate_cost(
cache_read_tokens: Option<u64>, cache_read_tokens: Option<u64>,
) -> f64 { ) -> f64 {
let (input_price_per_million, output_price_per_million) = match model { let (input_price_per_million, output_price_per_million) = match model {
// Current generation (Claude 4.6) // Current generation (Claude 4.7/4.6/4.5)
"claude-opus-4-6" => (5.0, 25.0), "claude-opus-4-7" => (5.0, 25.0),
"claude-sonnet-4-6" => (3.0, 15.0), "claude-sonnet-4-6" => (3.0, 15.0),
"claude-haiku-4-5-20251001" => (1.0, 5.0),
// Previous generation (Claude 4.6)
"claude-opus-4-6" => (5.0, 25.0),
// Previous generation (Claude 4.5) // Previous generation (Claude 4.5)
"claude-opus-4-5-20251101" => (5.0, 25.0), "claude-opus-4-5-20251101" => (5.0, 25.0),
"claude-sonnet-4-5-20250929" => (3.0, 15.0), "claude-sonnet-4-5-20250929" => (3.0, 15.0),
"claude-haiku-4-5-20251001" => (1.0, 5.0),
// Previous generation (Claude 4.x) // Previous generation (Claude 4.x)
"claude-opus-4-1-20250805" => (15.0, 75.0), "claude-opus-4-1-20250805" => (15.0, 75.0),
@@ -681,6 +685,15 @@ mod tests {
assert!((cost - 0.165).abs() < 0.0001); assert!((cost - 0.165).abs() < 0.0001);
} }
#[test]
fn test_cost_calculation_opus_47() {
let cost = calculate_cost(1000, 2000, "claude-opus-4-7", None, None);
// Opus 4.7 pricing: $5/MTok input, $25/MTok output
// 1000 input tokens = $0.005, 2000 output tokens = $0.05
// Total = $0.055
assert!((cost - 0.055).abs() < 0.0001);
}
#[test] #[test]
fn test_cost_calculation_opus_45() { fn test_cost_calculation_opus_45() {
let cost = calculate_cost(1000, 2000, "claude-opus-4-5-20251101", None, None); let cost = calculate_cost(1000, 2000, "claude-opus-4-5-20251101", None, None);
@@ -1019,6 +1032,16 @@ mod tests {
// Context Window Tracking tests // Context Window Tracking tests
// ===================== // =====================
#[test]
fn test_context_window_limit_opus_47() {
assert_eq!(get_context_window_limit("claude-opus-4-7"), 1_000_000);
}
#[test]
fn test_context_window_limit_opus_46() {
assert_eq!(get_context_window_limit("claude-opus-4-6"), 1_000_000);
}
#[test] #[test]
fn test_context_window_limit_claude_4() { fn test_context_window_limit_claude_4() {
assert_eq!(get_context_window_limit("claude-opus-4-5-20251101"), 200_000); assert_eq!(get_context_window_limit("claude-opus-4-5-20251101"), 200_000);
+8 -5
View File
@@ -144,17 +144,20 @@
const availableModels = [ const availableModels = [
{ value: "", label: "Default (from ~/.claude)" }, { value: "", label: "Default (from ~/.claude)" },
// Current generation (Claude 4.6) // Current generation (Claude 4.7/4.6/4.5)
{ value: "claude-opus-4-6", label: "Claude Opus 4.6 (Most Capable)" }, { value: "claude-opus-4-7", label: "Claude Opus 4.7 (Most Capable)" },
{ value: "claude-sonnet-4-6", label: "Claude Sonnet 4.6 (Recommended)" }, { value: "claude-sonnet-4-6", label: "Claude Sonnet 4.6 (Recommended)" },
{ value: "claude-haiku-4-5-20251001", label: "Claude Haiku 4.5 (Fast & Cheap)" },
// Previous generation (Claude 4.6)
{ value: "claude-opus-4-6", label: "Claude Opus 4.6" },
// Previous generation (Claude 4.5) // Previous generation (Claude 4.5)
{ value: "claude-sonnet-4-5-20250929", label: "Claude Sonnet 4.5" }, { value: "claude-sonnet-4-5-20250929", label: "Claude Sonnet 4.5" },
{ value: "claude-haiku-4-5-20251001", label: "Claude Haiku 4.5 (Fast & Cheap)" },
{ value: "claude-opus-4-5-20251101", label: "Claude Opus 4.5" }, { value: "claude-opus-4-5-20251101", label: "Claude Opus 4.5" },
// Previous generation (Claude 4.x) // Previous generation (Claude 4.x)
{ value: "claude-opus-4-1-20250805", label: "Claude Opus 4.1" }, { value: "claude-opus-4-1-20250805", label: "Claude Opus 4.1" },
{ value: "claude-sonnet-4-20250514", label: "Claude Sonnet 4" }, // Deprecated — retire June 15, 2026
{ value: "claude-opus-4-20250514", label: "Claude Opus 4" }, { value: "claude-sonnet-4-20250514", label: "Claude Sonnet 4 (Deprecated)" },
{ value: "claude-opus-4-20250514", label: "Claude Opus 4 (Deprecated)" },
]; ];
const commonTools = [ const commonTools = [
+5 -3
View File
@@ -10,13 +10,15 @@ export type BudgetType = "token" | "cost";
// Model pricing (per million tokens) - keep in sync with stats.rs // Model pricing (per million tokens) - keep in sync with stats.rs
// Source: https://platform.claude.com/docs/en/about-claude/models/overview // Source: https://platform.claude.com/docs/en/about-claude/models/overview
export const MODEL_PRICING: Record<string, { input: number; output: number }> = { export const MODEL_PRICING: Record<string, { input: number; output: number }> = {
// Current generation (Claude 4.6) // Current generation (Claude 4.7/4.6/4.5)
"claude-opus-4-6": { input: 5.0, output: 25.0 }, "claude-opus-4-7": { input: 5.0, output: 25.0 },
"claude-sonnet-4-6": { input: 3.0, output: 15.0 }, "claude-sonnet-4-6": { input: 3.0, output: 15.0 },
"claude-haiku-4-5-20251001": { input: 1.0, output: 5.0 },
// Previous generation (Claude 4.6)
"claude-opus-4-6": { input: 5.0, output: 25.0 },
// Previous generation (Claude 4.5) // Previous generation (Claude 4.5)
"claude-opus-4-5-20251101": { input: 5.0, output: 25.0 }, "claude-opus-4-5-20251101": { input: 5.0, output: 25.0 },
"claude-sonnet-4-5-20250929": { input: 3.0, output: 15.0 }, "claude-sonnet-4-5-20250929": { input: 3.0, output: 15.0 },
"claude-haiku-4-5-20251001": { input: 1.0, output: 5.0 },
// Previous generation (Claude 4.x) // Previous generation (Claude 4.x)
"claude-opus-4-1-20250805": { input: 15.0, output: 75.0 }, "claude-opus-4-1-20250805": { input: 15.0, output: 75.0 },
"claude-opus-4-20250514": { input: 15.0, output: 75.0 }, "claude-opus-4-20250514": { input: 15.0, output: 75.0 },