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";
pub(super) const BETA_COMPACT: &str = "compact-2026-01-12";
pub(super) const BETA_SERVER_SIDE_FALLBACK: &str = "server-side-fallback-2026-07-01";
pub(super) fn anthropic_beta_for(model: &str) -> String {
let info = crate::api::model_info::lookup(model);
let mut tokens = vec![BETA_TOKEN_EFFICIENT];
if info.supports_server_compaction {
tokens.push(BETA_COMPACT);
}
if info.supports_refusal_fallback {
tokens.push(BETA_SERVER_SIDE_FALLBACK);
}
tokens.join(",")
}
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()
}