Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 24 additions & 10 deletions src-tauri/src/proxy/common/model_mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@ static CLAUDE_TO_GEMINI: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|
m.insert("claude-opus-4", "claude-opus-4-5-thinking");
m.insert("claude-opus-4-5-20251101", "claude-opus-4-5-thinking");

// Claude Opus 4.6 (nuevo modelo thinking)
m.insert("claude-opus-4-6-thinking", "claude-opus-4-6-thinking");
m.insert("claude-opus-4-6", "claude-opus-4-6-thinking");
m.insert("claude-opus-4-6-20260201", "claude-opus-4-6-thinking");
// Claude Opus 4.6
//
// NOTE:
// - `*-thinking` is treated as a logical alias in Antigravity to indicate "thinking on by default".
// - Upstream model ids may not include `-thinking` (Claude Code / Anthropic-style naming), so we map
// Opus 4.6 thinking aliases back to the physical `claude-opus-4-6` id for compatibility.
m.insert("claude-opus-4-6-thinking", "claude-opus-4-6");
m.insert("claude-opus-4-6", "claude-opus-4-6");
m.insert("claude-opus-4-6-20260201", "claude-opus-4-6");

m.insert("claude-haiku-4", "claude-sonnet-4-5");
m.insert("claude-3-haiku-20240307", "claude-sonnet-4-5");
Expand Down Expand Up @@ -260,15 +265,16 @@ pub fn resolve_model_route(
result
}

/// Normalize any physical model name to one of the 3 standard protection IDs.
/// Normalize any physical model name to a standard protection ID.
/// This ensures quota protection works consistently regardless of API versioning or request variations.
///
/// Standard IDs:
/// - `gemini-3-flash`: All Flash variants (1.5-flash, 2.5-flash, 3-flash, etc.)
/// - `gemini-3-pro-high`: All Pro variants (1.5-pro, 2.5-pro, etc.)
/// - `claude-sonnet-4-5`: All Claude Sonnet variants (3-5-sonnet, sonnet-4-5, etc.)
/// - `claude-opus-4-6`: All Claude Opus 4.6 variants (including versioned / logical aliases)
///
/// Returns `None` if the model doesn't match any of the 3 protected categories.
/// Returns `None` if the model doesn't match any protected category.
pub fn normalize_to_standard_id(model_name: &str) -> Option<String> {
// [FIX] Strict matching based on user-defined groups (Case Insensitive)
let lower = model_name.to_lowercase();
Expand All @@ -283,10 +289,15 @@ pub fn normalize_to_standard_id(model_name: &str) -> Option<String> {
return Some("gemini-3-pro-high".to_string());
}

// [High-End Isolation] Opus 4.6 should NOT be normalized to Sonnet 4.5
// This allows specific capability check for "claude-opus-4-6-thinking"
// [High-End Isolation] Opus 4.6 should have its own standard id.
//
// Why:
// - We must NOT normalize Opus 4.6 into the generic Claude bucket (`claude-sonnet-4-5`),
// otherwise Pro/Free accounts could be incorrectly selected and then rejected upstream.
// - At the same time, we want all Opus 4.6 variants to match consistently:
// `claude-opus-4-6`, `claude-opus-4-6-thinking`, `claude-opus-4-6-20260201`, etc.
if lower.contains("claude-opus-4-6") {
return None;
return Some("claude-opus-4-6".to_string());
}

// Group 3: Claude 4.5 Sonnet (includes Opus etc. assigned to this bucket)
Expand Down Expand Up @@ -328,7 +339,10 @@ mod tests {
);

// Test Normalization Exception
assert_eq!(normalize_to_standard_id("claude-opus-4-6-thinking"), None);
assert_eq!(
normalize_to_standard_id("claude-opus-4-6-thinking"),
Some("claude-opus-4-6".to_string())
);
assert_eq!(
normalize_to_standard_id("claude-sonnet-4-5"),
Some("claude-sonnet-4-5".to_string())
Expand Down
8 changes: 7 additions & 1 deletion src/config/modelConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ export const MODEL_CONFIG: Record<string, ModelConfig> = {
protectedKey: 'claude-opus',
Icon: Claude.Color,
},
// Opus 4.6 upstream id (some clients / quota APIs may report without "-thinking")
'claude-opus-4-6': {
label: 'Claude 4.6 Opus',
shortLabel: 'Claude 4.6 Op',
protectedKey: 'claude-opus',
Icon: Claude.Color,
},
'claude-opus-4-6-thinking': {
label: 'Claude 4.6 Opus Think',
shortLabel: 'Claude 4.6 Op',
Expand Down Expand Up @@ -203,4 +210,3 @@ export function sortModels<T extends { id: string }>(models: T[]): T[] {
return a.id.localeCompare(b.id);
});
}

7 changes: 7 additions & 0 deletions src/hooks/useProxyModels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ export const useProxyModels = () => {
group: 'Claude 4.5',
icon: <Cpu size={16} />
},
{
id: 'claude-opus-4-6',
name: 'Claude 4.6 Opus',
desc: t('proxy.model.claude_opus_thinking'),
group: 'Claude 4.6',
icon: <Cpu size={16} />
},
{
id: 'claude-opus-4-6-thinking',
name: 'Claude 4.6 Opus (Thinking)',
Expand Down