Add unified thinking effort control across all providers (#9242)

Signed-off-by: jh-block <jhugo@block.xyz>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jh-block
2026-05-20 10:42:42 +02:00
committed by GitHub
parent c467e7f998
commit 98a54e9ec6
30 changed files with 2175 additions and 526 deletions
+22 -80
View File
@@ -23,8 +23,6 @@ use goose::model::ModelConfig;
#[cfg(feature = "telemetry")]
use goose::posthog::{get_telemetry_choice, TELEMETRY_ENABLED_KEY};
use goose::providers::base::ConfigKey;
use goose::providers::chatgpt_codex::reasoning_levels_for_model;
use goose::providers::formats::anthropic::supports_adaptive_thinking;
use goose::providers::provider_test::test_provider_configuration;
use goose::providers::{create, providers, retry_operation, RetryConfig};
use goose::session::SessionType;
@@ -738,15 +736,13 @@ pub async fn configure_provider_dialog() -> anyhow::Result<bool> {
let spin = spinner();
spin.start("Attempting to fetch supported models...");
let models_res = {
let temp_model_config =
ModelConfig::new(&provider_meta.default_model)?.with_canonical_limits(provider_name);
let temp_provider = create(provider_name, temp_model_config, Vec::new()).await?;
retry_operation(&RetryConfig::default(), || async {
temp_provider.fetch_recommended_models().await
})
.await
};
let temp_model_config =
ModelConfig::new(&provider_meta.default_model)?.with_canonical_limits(provider_name);
let temp_provider = create(provider_name, temp_model_config, Vec::new()).await?;
let models_res = retry_operation(&RetryConfig::default(), || async {
temp_provider.fetch_recommended_models().await
})
.await;
spin.stop(style("Model fetch complete").green());
// Select a model: on fetch error show styled error and abort; if models available, show list; otherwise free-text input
@@ -766,78 +762,24 @@ pub async fn configure_provider_dialog() -> anyhow::Result<bool> {
}
};
if model.to_lowercase().starts_with("gemini-3") {
let thinking_level: &str = cliclack::select("Select thinking level for Gemini 3:")
.item("low", "Low - Better latency, lighter reasoning", "")
.item("high", "High - Deeper reasoning, higher latency", "")
.interact()?;
config.set_gemini3_thinking_level(thinking_level)?;
}
{
let supports_thinking = match temp_provider.fetch_model_info(&model).await {
Ok(model_info) => model_info.reasoning,
Err(_) => goose::model::ModelConfig::new(&model)
.map(|c| c.is_reasoning_model())
.unwrap_or(false),
};
if model.to_lowercase().starts_with("claude-") {
let supports_adaptive = supports_adaptive_thinking(&model);
let mut thinking_select = cliclack::select("Select extended thinking mode for Claude:");
if supports_adaptive {
thinking_select = thinking_select.item(
"adaptive",
"Adaptive - Claude decides when and how much to think (recommended)",
"",
);
}
thinking_select = thinking_select
.item("enabled", "Enabled - Fixed token budget for thinking", "")
.item("disabled", "Disabled - No extended thinking", "");
if supports_adaptive {
thinking_select = thinking_select.initial_value("adaptive");
} else {
thinking_select = thinking_select.initial_value("disabled");
}
let thinking_type: &str = thinking_select.interact()?;
config.set_claude_thinking_type(thinking_type)?;
if thinking_type == "adaptive" {
let effort: &str = cliclack::select("Select adaptive thinking effort level:")
.item("low", "Low - Minimal thinking, fastest responses", "")
if supports_thinking {
let effort: &str = cliclack::select("Select thinking effort:")
.item("off", "Off - No extended thinking", "")
.item("low", "Low - Better latency, lighter reasoning", "")
.item("medium", "Medium - Moderate thinking", "")
.item("high", "High - Deep reasoning (default)", "")
.item(
"max",
"Max - No constraints on thinking depth (Opus 4.6 only)",
"",
)
.initial_value("high")
.item("high", "High - Deep reasoning", "")
.item("max", "Max - No constraints on thinking depth", "")
.initial_value("off")
.interact()?;
config.set_claude_thinking_effort(effort)?;
} else if thinking_type == "enabled" {
let budget: String = cliclack::input("Enter thinking budget (tokens):")
.default_input("16000")
.validate(|input: &String| match input.parse::<i32>() {
Ok(n) if n > 0 => Ok(()),
_ => Err("Please enter a valid positive number"),
})
.interact()?;
config.set_claude_thinking_budget(budget.parse::<i32>()?)?;
}
}
if provider_name == "chatgpt_codex" {
let valid_levels = reasoning_levels_for_model(&model);
if !valid_levels.is_empty() {
let mut select = cliclack::select("Select reasoning effort level:");
for &level in valid_levels {
let description = match level {
"low" => "Low - Fast responses with lighter reasoning",
"medium" => "Medium - Balances speed and reasoning depth for everyday tasks",
"high" => "High - Greater reasoning depth for complex problems",
"xhigh" => "Extra High - Extra high reasoning depth for complex problems",
_ => "",
};
select = select.item(level, description, "");
}
select = select.initial_value("medium");
let effort: &str = select.interact()?;
config.set_chatgpt_codex_reasoning_effort(effort.to_string())?;
config.set_goose_thinking_effort(effort)?;
}
}
+1
View File
@@ -268,6 +268,7 @@ fn resolve_provider_and_model(
.is_some_and(|mc| mc.model_name == model_name)
{
let mut config = saved_model_config.unwrap();
config.normalize_effort_suffix();
if let Some(temp) = recipe_settings.and_then(|s| s.temperature) {
config = config.with_temperature(Some(temp));
}