Add xhigh thinking effort

Signed-off-by: jh-block <jhugo@block.xyz>
This commit is contained in:
jh-block
2026-05-20 14:26:44 +02:00
parent 12d93afa06
commit 65cda3c96c
13 changed files with 61 additions and 22 deletions
+7 -4
View File
@@ -17,6 +17,7 @@ pub enum ThinkingEffort {
Low,
Medium,
High,
XHigh,
Max,
}
@@ -28,7 +29,8 @@ impl FromStr for ThinkingEffort {
"low" => Ok(Self::Low),
"medium" | "med" => Ok(Self::Medium),
"high" => Ok(Self::High),
"max" | "xhigh" => Ok(Self::Max),
"xhigh" => Ok(Self::XHigh),
"max" => Ok(Self::Max),
other => Err(format!("unknown thinking effort: '{other}'")),
}
}
@@ -41,6 +43,7 @@ impl fmt::Display for ThinkingEffort {
Self::Low => write!(f, "low"),
Self::Medium => write!(f, "medium"),
Self::High => write!(f, "high"),
Self::XHigh => write!(f, "xhigh"),
Self::Max => write!(f, "max"),
}
}
@@ -445,7 +448,7 @@ impl ModelConfig {
"low" => ThinkingEffort::Low,
"medium" => ThinkingEffort::Medium,
"high" => ThinkingEffort::High,
"xhigh" => ThinkingEffort::Max,
"xhigh" => ThinkingEffort::XHigh,
_ => return,
};
self.model_name = parts[..parts.len() - 1].join("-");
@@ -794,7 +797,7 @@ mod tests {
]);
let config = ModelConfig::new("gpt-5.4-xhigh").unwrap();
assert_eq!(config.model_name, "gpt-5.4");
assert_eq!(config.thinking_effort(), Some(ThinkingEffort::Max));
assert_eq!(config.thinking_effort(), Some(ThinkingEffort::XHigh));
}
#[test]
@@ -857,7 +860,7 @@ mod tests {
);
assert_eq!("med".parse::<ThinkingEffort>(), Ok(ThinkingEffort::Medium));
assert_eq!("max".parse::<ThinkingEffort>(), Ok(ThinkingEffort::Max));
assert_eq!("xhigh".parse::<ThinkingEffort>(), Ok(ThinkingEffort::Max));
assert_eq!("xhigh".parse::<ThinkingEffort>(), Ok(ThinkingEffort::XHigh));
assert!("invalid".parse::<ThinkingEffort>().is_err());
}
}
@@ -243,6 +243,7 @@ fn reasoning_effort_for_config_with_config(
ThinkingEffort::Low => &["low", "medium", "high", "xhigh"],
ThinkingEffort::Medium => &["medium", "high", "low", "xhigh"],
ThinkingEffort::High => &["high", "medium", "xhigh", "low"],
ThinkingEffort::XHigh => &["xhigh", "high", "medium", "low"],
ThinkingEffort::Max => &["xhigh", "high", "medium", "low"],
};
+2 -1
View File
@@ -69,7 +69,7 @@ impl CodexProvider {
"low" => Some(crate::model::ThinkingEffort::Low),
"medium" => Some(crate::model::ThinkingEffort::Medium),
"high" => Some(crate::model::ThinkingEffort::High),
"xhigh" => Some(crate::model::ThinkingEffort::Max),
"xhigh" => Some(crate::model::ThinkingEffort::XHigh),
_ => None,
})
}
@@ -84,6 +84,7 @@ impl CodexProvider {
ThinkingEffort::Low => Some("low".to_string()),
ThinkingEffort::Medium => Some("medium".to_string()),
ThinkingEffort::High => Some("high".to_string()),
ThinkingEffort::XHigh => Some("xhigh".to_string()),
ThinkingEffort::Max => Some("xhigh".to_string()),
}
}
@@ -507,7 +507,7 @@ pub fn adaptive_effort_value(model_config: &ModelConfig) -> Option<&'static str>
}
fn adaptive_effort_value_for_model(
model_name: &str,
_model_name: &str,
effort: Option<ThinkingEffort>,
) -> Option<&'static str> {
match effort? {
@@ -515,7 +515,7 @@ fn adaptive_effort_value_for_model(
ThinkingEffort::Low => Some("low"),
ThinkingEffort::Medium => Some("medium"),
ThinkingEffort::High => Some("high"),
ThinkingEffort::Max if is_claude_opus_47(model_name) => Some("xhigh"),
ThinkingEffort::XHigh => Some("xhigh"),
ThinkingEffort::Max => Some("max"),
}
}
@@ -569,6 +569,7 @@ fn thinking_budget_tokens_for_values(
ThinkingEffort::Low => 4000,
ThinkingEffort::Medium => 10000,
ThinkingEffort::High => 16000,
ThinkingEffort::XHigh => 24000,
ThinkingEffort::Max => 32000,
})
}
@@ -1281,6 +1282,23 @@ mod tests {
let messages = vec![Message::user().with_text("Hello")];
let payload = create_request(&config, "system", &messages, &[])?;
assert_eq!(payload["thinking"]["type"], "adaptive");
assert_eq!(payload["thinking"]["display"], "summarized");
assert_eq!(payload["output_config"]["effort"], "max");
assert_eq!(payload["max_tokens"], 4096);
Ok(())
}
#[test]
fn test_create_request_adaptive_thinking_for_opus_47_xhigh_effort() -> Result<()> {
let _guard = env_lock::lock_env([("GOOSE_THINKING_EFFORT", None::<&str>)]);
let mut config = cfg_with_effort("claude-opus-4-7", "xhigh");
config.max_tokens = Some(4096);
let messages = vec![Message::user().with_text("Hello")];
let payload = create_request(&config, "system", &messages, &[])?;
assert_eq!(payload["thinking"]["type"], "adaptive");
assert_eq!(payload["thinking"]["display"], "summarized");
assert_eq!(payload["output_config"]["effort"], "xhigh");
@@ -1470,7 +1488,7 @@ mod tests {
assert_eq!(payload["thinking"]["type"], "adaptive");
assert_eq!(payload["thinking"]["display"], "summarized");
assert_eq!(payload["thinking"]["clear_thinking"], false);
assert_eq!(payload["output_config"]["effort"], "xhigh");
assert_eq!(payload["output_config"]["effort"], "max");
assert!(payload["thinking"].get("budget_tokens").is_none());
assert_eq!(payload["max_tokens"], 4096);
assert_eq!(payload["messages"][0]["content"][0]["type"], "thinking");
@@ -1114,19 +1114,12 @@ mod tests {
#[test]
fn test_create_request_reasoning_effort_xhigh() -> anyhow::Result<()> {
let model_config = ModelConfig {
model_name: "o3-xhigh".to_string(),
context_limit: Some(4096),
temperature: None,
max_tokens: Some(1024),
toolshim: false,
toolshim_model: None,
fast_model_config: None,
request_params: None,
reasoning: None,
};
let _guard = env_lock::lock_env([("GOOSE_THINKING_EFFORT", None::<&str>)]);
let mut model_config = ModelConfig::new_or_fail("gpt-5.4-xhigh");
model_config.max_tokens = Some(1024);
let request = create_request(&model_config, "system", &[], &[], &ImageFormat::OpenAi)?;
assert_eq!(request["model"], "o3");
assert_eq!(request["model"], "gpt-5.4");
assert_eq!(request["reasoning_effort"], "xhigh");
Ok(())
}
@@ -1209,10 +1202,17 @@ mod tests {
#[test]
fn test_create_request_enabled_thinking_budget_tracks_effort() -> anyhow::Result<()> {
let _guard = env_lock::lock_env([
("GOOSE_THINKING_EFFORT", None::<&str>),
("ANTHROPIC_THINKING_BUDGET", None::<&str>),
("CLAUDE_THINKING_BUDGET", None::<&str>),
]);
for (effort, expected_budget) in [
("low", 4000),
("medium", 10000),
("high", 16000),
("xhigh", 24000),
("max", 32000),
] {
let mut model_config = ModelConfig::new_or_fail("databricks-claude-3-7-sonnet");
+3 -1
View File
@@ -553,7 +553,9 @@ fn get_thinking_config(model_config: &ModelConfig) -> Option<ThinkingConfig> {
ThinkingEffort::Off | ThinkingEffort::Low | ThinkingEffort::Medium => {
ThinkingLevel::Low
}
ThinkingEffort::High | ThinkingEffort::Max => ThinkingLevel::High,
ThinkingEffort::High | ThinkingEffort::XHigh | ThinkingEffort::Max => {
ThinkingLevel::High
}
};
Some(ThinkingConfig {
@@ -94,6 +94,7 @@ fn reasoning_effort_for_openrouter(effort: ThinkingEffort) -> &'static str {
ThinkingEffort::Low => "low",
ThinkingEffort::Medium => "medium",
ThinkingEffort::High => "high",
ThinkingEffort::XHigh => "xhigh",
ThinkingEffort::Max => "xhigh",
}
}
+1
View File
@@ -251,6 +251,7 @@ pub fn openai_reasoning_effort_for_thinking(
ThinkingEffort::Low => &["low", "medium", "high", "xhigh"],
ThinkingEffort::Medium => &["medium", "high", "low", "xhigh"],
ThinkingEffort::High => &["high", "medium", "xhigh", "low"],
ThinkingEffort::XHigh => &["xhigh", "high", "medium", "low"],
ThinkingEffort::Max => &["xhigh", "high", "medium", "low"],
};
+1
View File
@@ -8676,6 +8676,7 @@
"low",
"medium",
"high",
"xhigh",
"max"
]
},
+1 -1
View File
@@ -1502,7 +1502,7 @@ export type ThinkingContent = {
thinking: string;
};
export type ThinkingEffort = 'off' | 'low' | 'medium' | 'high' | 'max';
export type ThinkingEffort = 'off' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
export type TokenState = {
accumulatedCost?: number | null;
@@ -53,6 +53,10 @@ const i18n = defineMessages({
id: 'switchModelModal.claudeEffortHigh',
defaultMessage: 'High - Deep reasoning (default)',
},
claudeEffortXHigh: {
id: 'switchModelModal.claudeEffortXHigh',
defaultMessage: 'XHigh - Extended coding and agentic work',
},
claudeEffortMax: {
id: 'switchModelModal.claudeEffortMax',
defaultMessage: 'Max - No constraints on thinking depth',
@@ -262,6 +266,7 @@ export const SwitchModelModal = ({
{ value: 'low', label: intl.formatMessage(i18n.claudeEffortLow) },
{ value: 'medium', label: intl.formatMessage(i18n.claudeEffortMedium) },
{ value: 'high', label: intl.formatMessage(i18n.claudeEffortHigh) },
{ value: 'xhigh', label: intl.formatMessage(i18n.claudeEffortXHigh) },
{ value: 'max', label: intl.formatMessage(i18n.claudeEffortMax) },
];
+3
View File
@@ -4409,6 +4409,9 @@
"switchModelModal.claudeEffortMedium": {
"defaultMessage": "Medium - Moderate thinking"
},
"switchModelModal.claudeEffortXHigh": {
"defaultMessage": "XHigh - Extended coding and agentic work"
},
"switchModelModal.claudeEnabled": {
"defaultMessage": "Enabled - Fixed token budget for thinking"
},
+3
View File
@@ -4307,6 +4307,9 @@
"switchModelModal.claudeEffortHigh": {
"defaultMessage": "高 - 深度推理(默认)"
},
"switchModelModal.claudeEffortXHigh": {
"defaultMessage": "超高 - 长程编码和代理任务"
},
"switchModelModal.claudeEffortLow": {
"defaultMessage": "低 - 最少思考,响应最快"
},