use super::ant_model::AnthropicModelCapabilities;
use crate::{Result, chat::ReasoningEffort};
use serde_json::{Map, Value, json};
use value_ext::JsonValueExt;
pub(super) const REASONING_LOW: u32 = 1024;
pub(super) const REASONING_MEDIUM: u32 = 8000;
pub(super) const REASONING_HIGH: u32 = 24000;
pub(super) fn insert_anthropic_reasoning(
payload: &mut Value,
output_config: &mut Map<String, Value>,
capabilities: &AnthropicModelCapabilities,
effort: &ReasoningEffort,
capture_reasoning_content: bool,
) -> Result<()> {
let mut budget: Option<u32> = None;
let support_effort = capabilities.supports_effort;
let support_reasoning_max = capabilities.supports_max_effort;
let support_adaptive = capabilities.supports_adaptive_thinking;
let support_xhigh = capabilities.supports_xhigh_effort;
if matches!(effort, ReasoningEffort::Zero) {
if capabilities.thinking_enabled_by_default {
payload.x_insert("thinking", json!({"type": "disabled"}))?;
}
return Ok(());
}
if support_effort {
let effort = match effort {
ReasoningEffort::Minimal => "low",
ReasoningEffort::Low => "low",
ReasoningEffort::Medium => "medium",
ReasoningEffort::High => "high",
ReasoningEffort::XHigh if support_xhigh => "xhigh",
ReasoningEffort::Max if support_reasoning_max => "max",
ReasoningEffort::XHigh => "high",
ReasoningEffort::Max => "high",
ReasoningEffort::Budget(val) => {
budget = Some(*val);
""
}
ReasoningEffort::Zero => "",
};
if !effort.is_empty() {
output_config.insert("effort".to_string(), json!(effort));
}
}
if support_adaptive {
let mut thinking = match budget {
Some(budget) => json!({
"type": "adaptive",
"budget_tokens": budget }),
None => json!({
"type": "adaptive"}),
};
if capture_reasoning_content {
thinking.x_insert("display", "summarized")?;
}
payload.x_insert("thinking", thinking)?;
}
if !support_effort || matches!(effort, ReasoningEffort::Budget(_)) && capabilities.supports_legacy_budget_thinking {
let thinking_budget = match effort {
ReasoningEffort::Zero => None,
ReasoningEffort::Budget(budget) => Some(*budget),
ReasoningEffort::Low | ReasoningEffort::Minimal => Some(REASONING_LOW),
ReasoningEffort::Medium => Some(REASONING_MEDIUM),
ReasoningEffort::High | ReasoningEffort::Max | ReasoningEffort::XHigh => Some(REASONING_HIGH),
};
if let Some(thinking_budget) = thinking_budget {
payload.x_insert(
"thinking",
json!({
"type": "enabled",
"budget_tokens": thinking_budget
}),
)?;
}
}
Ok(())
}
#[cfg(test)]
#[path = "ant_reasoning_tests.rs"]
mod tests;