diff --git a/crates/goose/src/providers/anthropic.rs b/crates/goose/src/providers/anthropic.rs index cd5be5396c61..5f2976af4e05 100644 --- a/crates/goose/src/providers/anthropic.rs +++ b/crates/goose/src/providers/anthropic.rs @@ -37,10 +37,6 @@ const ANTHROPIC_KNOWN_MODELS: &[&str] = &[ "claude-sonnet-4-20250514", "claude-opus-4-0", "claude-opus-4-20250514", - // Legacy Claude 3.x models - "claude-3-7-sonnet-latest", - "claude-3-7-sonnet-20250219", - "claude-3-opus-latest", ]; const ANTHROPIC_DOC_URL: &str = "https://docs.anthropic.com/en/docs/about-claude/models"; diff --git a/crates/goose/src/providers/canonical/name_builder.rs b/crates/goose/src/providers/canonical/name_builder.rs index c82629ed56c4..5765cfcbd82a 100644 --- a/crates/goose/src/providers/canonical/name_builder.rs +++ b/crates/goose/src/providers/canonical/name_builder.rs @@ -333,55 +333,23 @@ mod tests { Some("anthropic/claude-3.5-sonnet".to_string()) ); - // === Claude word-order swapping (3.x series) === + // 3.x: {model}-{version} → {version}-{model} assert_eq!( map_to_canonical_model("databricks", "claude-haiku-3-5", r), Some("anthropic/claude-3.5-haiku".to_string()) ); - assert_eq!( - map_to_canonical_model("databricks", "claude-sonnet-3-7", r), - Some("anthropic/claude-3.7-sonnet".to_string()) - ); - assert_eq!( - map_to_canonical_model("databricks", "ng-tools-claude-haiku-3-5", r), - Some("anthropic/claude-3.5-haiku".to_string()) - ); - // === Claude word-order swapping (4.x series) === - assert_eq!( - map_to_canonical_model("databricks", "claude-4-opus", r), - Some("anthropic/claude-opus-4".to_string()) - ); + // 4.x: {version}-{model} → {model}-{version} assert_eq!( map_to_canonical_model("databricks", "claude-4-sonnet", r), Some("anthropic/claude-sonnet-4".to_string()) ); + + // 4.x with minor version + prefix stripping assert_eq!( map_to_canonical_model("databricks", "raml-claude-opus-4-5", r), Some("anthropic/claude-opus-4.5".to_string()) ); - assert_eq!( - map_to_canonical_model("databricks", "databricks-claude-sonnet-4-5", r), - Some("anthropic/claude-sonnet-4.5".to_string()) - ); - - // === Claude with custom prefixes === - assert_eq!( - map_to_canonical_model("databricks", "goose-claude-4-opus", r), - Some("anthropic/claude-opus-4".to_string()) - ); - assert_eq!( - map_to_canonical_model("databricks", "kgoose-claude-4-sonnet", r), - Some("anthropic/claude-sonnet-4".to_string()) - ); - assert_eq!( - map_to_canonical_model("databricks", "headless-goose-claude-4-sonnet", r), - Some("anthropic/claude-sonnet-4".to_string()) - ); - assert_eq!( - map_to_canonical_model("databricks", "kgoose-cashapp-claude-4-sonnet", r), - Some("anthropic/claude-sonnet-4".to_string()) - ); // === Claude with platform suffixes === assert_eq!( diff --git a/crates/goose/src/providers/formats/anthropic.rs b/crates/goose/src/providers/formats/anthropic.rs index 3771b3adadca..a2d81cb96d9c 100644 --- a/crates/goose/src/providers/formats/anthropic.rs +++ b/crates/goose/src/providers/formats/anthropic.rs @@ -394,9 +394,18 @@ pub fn create_request( return Err(anyhow!("No valid messages to send to Anthropic API")); } - // https://docs.anthropic.com/en/docs/about-claude/models/all-models#model-comparison-table - // Claude 3.7 supports max output tokens up to 8192 - let max_tokens = model_config.max_tokens.unwrap_or(8192); + // https://platform.claude.com/docs/en/about-claude/models/overview + // 64k output tokens works for most claude models, but not old opus: + let max_tokens = model_config.max_tokens.unwrap_or_else(|| { + let name = &model_config.model_name; + if name.contains("claude-3-haiku") { + 4096 + } else if name.contains("claude-opus-4-0") || name.contains("claude-opus-4-1") { + 32000 + } else { + 64000 + } + }); let mut payload = json!({ "model": model_config.model_name, "messages": anthropic_messages, @@ -421,18 +430,15 @@ pub fn create_request( // Add temperature if specified and not using extended thinking model if let Some(temp) = model_config.temperature { - // Claude 3.7 models with thinking enabled don't support temperature - if !model_config.model_name.starts_with("claude-3-7-sonnet-") { - payload - .as_object_mut() - .unwrap() - .insert("temperature".to_string(), json!(temp)); - } + payload + .as_object_mut() + .unwrap() + .insert("temperature".to_string(), json!(temp)); } // Add thinking parameters for claude-3-7-sonnet model let is_thinking_enabled = std::env::var("CLAUDE_THINKING_ENABLED").is_ok(); - if model_config.model_name.starts_with("claude-3-7-sonnet-") && is_thinking_enabled { + if is_thinking_enabled { // Minimum budget_tokens is 1024 let budget_tokens = std::env::var("CLAUDE_THINKING_BUDGET") .unwrap_or_else(|_| "16000".to_string()) @@ -452,7 +458,6 @@ pub fn create_request( }), ); } - Ok(payload) } @@ -931,45 +936,6 @@ mod tests { assert!(spec_array[0].get("cache_control").is_some()); } - #[test] - fn test_create_request_with_thinking() -> Result<()> { - let original_value = std::env::var("CLAUDE_THINKING_ENABLED").ok(); - std::env::set_var("CLAUDE_THINKING_ENABLED", "true"); - - let result = (|| { - let model_config = ModelConfig::new_or_fail("claude-3-7-sonnet-20250219"); - let system = "You are a helpful assistant."; - let messages = vec![Message::user().with_text("Hello")]; - let tools = vec![]; - - let payload = create_request(&model_config, system, &messages, &tools)?; - - // Verify basic structure - assert_eq!(payload["model"], "claude-3-7-sonnet-20250219"); - assert_eq!(payload["messages"][0]["role"], "user"); - assert_eq!(payload["messages"][0]["content"][0]["text"], "Hello"); - - // Verify thinking parameters - assert!(payload.get("thinking").is_some()); - assert_eq!(payload["thinking"]["type"], "enabled"); - assert!(payload["thinking"]["budget_tokens"].as_i64().unwrap() >= 1024); - - // Temperature should not be present for 3.7 models with thinking - assert!(payload.get("temperature").is_none()); - - Ok(()) - })(); - - // Restore the original env var state - match original_value { - Some(val) => std::env::set_var("CLAUDE_THINKING_ENABLED", val), - None => std::env::remove_var("CLAUDE_THINKING_ENABLED"), - } - - // Return the test result - result - } - #[test] fn test_cache_pricing_calculation() -> Result<()> { // Test realistic cache scenario: small fresh input, large cached content diff --git a/crates/goose/src/providers/formats/databricks.rs b/crates/goose/src/providers/formats/databricks.rs index fc196e50d0a7..6d2f2cf77443 100644 --- a/crates/goose/src/providers/formats/databricks.rs +++ b/crates/goose/src/providers/formats/databricks.rs @@ -583,7 +583,6 @@ pub fn create_request( .insert("tools".to_string(), json!(tools_spec)); } - // Add thinking parameters for Claude 3.7 Sonnet model when requested let is_thinking_enabled = std::env::var("CLAUDE_THINKING_ENABLED").is_ok(); if is_claude_sonnet && is_thinking_enabled { // Minimum budget_tokens is 1024 @@ -608,7 +607,6 @@ pub fn create_request( }), ); - // Temperature is fixed to 2 when using claude 3.7 thinking with Databricks payload .as_object_mut() .unwrap() diff --git a/crates/goose/src/providers/gcpvertexai.rs b/crates/goose/src/providers/gcpvertexai.rs index ef32442f7fee..a1d45c556e24 100644 --- a/crates/goose/src/providers/gcpvertexai.rs +++ b/crates/goose/src/providers/gcpvertexai.rs @@ -462,9 +462,7 @@ impl Provider for GcpVertexAIProvider { "gcp_vertex_ai", "GCP Vertex AI", "Access variety of AI models such as Claude, Gemini through Vertex AI", - GcpVertexAIModel::Gemini(GeminiVersion::Flash25) - .to_string() - .as_str(), + "gemini-2.5-flash", known_models, GCP_VERTEX_AI_DOC_URL, vec![ diff --git a/crates/goose/src/providers/openrouter.rs b/crates/goose/src/providers/openrouter.rs index 23b8a7422da0..e3d4cd2ea5ea 100644 --- a/crates/goose/src/providers/openrouter.rs +++ b/crates/goose/src/providers/openrouter.rs @@ -17,16 +17,16 @@ use crate::providers::formats::openai::{create_request, get_usage, response_to_m use rmcp::model::Tool; pub const OPENROUTER_DEFAULT_MODEL: &str = "anthropic/claude-sonnet-4"; -pub const OPENROUTER_DEFAULT_FAST_MODEL: &str = "google/gemini-flash-2.5"; +pub const OPENROUTER_DEFAULT_FAST_MODEL: &str = "google/gemini-2.5-flash"; pub const OPENROUTER_MODEL_PREFIX_ANTHROPIC: &str = "anthropic"; // OpenRouter can run many models, we suggest the default pub const OPENROUTER_KNOWN_MODELS: &[&str] = &[ + "x-ai/grok-code-fast-1", "anthropic/claude-sonnet-4.5", "anthropic/claude-sonnet-4", "anthropic/claude-opus-4.1", "anthropic/claude-opus-4", - "anthropic/claude-3.7-sonnet", "google/gemini-2.5-pro", "google/gemini-2.5-flash", "deepseek/deepseek-r1-0528",