Skip to content
Merged
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
4 changes: 0 additions & 4 deletions crates/goose/src/providers/anthropic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
40 changes: 4 additions & 36 deletions crates/goose/src/providers/canonical/name_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand Down
68 changes: 17 additions & 51 deletions crates/goose/src/providers/formats/anthropic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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));
Comment on lines 423 to +436
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Temperature is now always added regardless of model when specified in model_config. The previous code excluded temperature for claude-3-7-sonnet models with thinking enabled. If users can still specify claude-3-7-sonnet models (even though they're removed from the known models list), this could cause API errors. Consider either: (1) explicitly blocking claude-3-7 model names, or (2) keeping the temperature exclusion for backward compatibility.

Copilot uses AI. Check for mistakes.
}

// Add thinking parameters for claude-3-7-sonnet model
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment on line 430 still references "claude-3-7-sonnet model" but the check on line 432 now applies thinking parameters to ALL models when CLAUDE_THINKING_ENABLED is set, not just Claude 3.7. The comment should be updated to reflect this broader applicability.

Suggested change
// Add thinking parameters for claude-3-7-sonnet model
// Add thinking parameters for all models when CLAUDE_THINKING_ENABLED is set

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment still mentions "claude-3-7-sonnet model" but the thinking parameters are now applied to all models when CLAUDE_THINKING_ENABLED is set. Update the comment to reflect that thinking is no longer model-specific.

Suggested change
// Add thinking parameters for claude-3-7-sonnet model
// Add thinking parameters when CLAUDE_THINKING_ENABLED is set (applies to all models)

Copilot uses AI. Check for mistakes.
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())
Expand All @@ -452,7 +458,6 @@ pub fn create_request(
}),
);
}

Ok(payload)
}

Expand Down Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions crates/goose/src/providers/formats/databricks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand Down
4 changes: 1 addition & 3 deletions crates/goose/src/providers/gcpvertexai.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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![
Expand Down
4 changes: 2 additions & 2 deletions crates/goose/src/providers/openrouter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading