use crate::api::types::*;
pub(super) const BETA_HEADER_NAME: &str = "anthropic-beta";
pub(super) const BETA_TOKEN_EFFICIENT: &str = "token-efficient-tools-2025-02-19";
#[allow(dead_code)]
pub(super) const BETA_COMPACT: &str = "compact-2026-01-12";
pub(super) const BETA_TOKEN_EFFICIENT_AND_COMPACT: &str =
"token-efficient-tools-2025-02-19,compact-2026-01-12";
pub(super) fn anthropic_beta_for(model: &str) -> &'static str {
if crate::api::model_info::lookup(model).supports_server_compaction {
BETA_TOKEN_EFFICIENT_AND_COMPACT
} else {
BETA_TOKEN_EFFICIENT
}
}
pub const LEGACY_THINKING_BUDGET_LOW: u32 = 1024;
pub const LEGACY_THINKING_BUDGET_MEDIUM: u32 = 5120;
pub const LEGACY_THINKING_BUDGET_HIGH: u32 = 16384;
pub const COMPACTION_TRIGGER_FLOOR: u32 = 50_000;
pub fn legacy_thinking_budget(effort: ReasoningEffort) -> u32 {
match effort {
ReasoningEffort::Low => LEGACY_THINKING_BUDGET_LOW,
ReasoningEffort::Medium => LEGACY_THINKING_BUDGET_MEDIUM,
ReasoningEffort::High | ReasoningEffort::XHigh | ReasoningEffort::Max => {
LEGACY_THINKING_BUDGET_HIGH
}
}
}
pub fn effort_label(effort: ReasoningEffort) -> &'static str {
match effort {
ReasoningEffort::Low => "low",
ReasoningEffort::Medium => "medium",
ReasoningEffort::High => "high",
ReasoningEffort::XHigh => "xhigh",
ReasoningEffort::Max => "max",
}
}
pub fn requires_adaptive_thinking(model: &str) -> bool {
crate::api::model_info::lookup(model).requires_adaptive_thinking
}
pub(super) fn prepare_request(mut request: CreateMessageRequest) -> CreateMessageRequest {
request.messages = sanitize_messages_for_anthropic(request.messages);
request.prompt_cache_key = None;
request.reasoning = None;
if let Some(tools) = request.tools.take() {
let filtered: Vec<Tool> = tools
.into_iter()
.filter(|t| !matches!(t, Tool::OpenAIWebSearch { tool_type: _ }))
.collect();
if !filtered.is_empty() {
request.tools = Some(filtered);
}
}
request
}
pub(crate) fn sanitize_messages_for_anthropic(messages: Vec<Message>) -> Vec<Message> {
messages
.into_iter()
.map(|mut msg| {
if let MessageContent::Blocks { content } = msg.content {
let filtered_content = content
.into_iter()
.filter_map(|block| match block {
MessageContentBlock::Summary { .. } => None,
MessageContentBlock::Reasoning { .. } => None,
other => Some(other),
})
.collect();
msg.content = MessageContent::Blocks {
content: filtered_content,
};
}
msg
})
.collect()
}