use super::{Capability, CapabilityLocalization, CapabilityStatus, SystemPromptContext};
use crate::driver_registry::ToolSearchConfig;
use async_trait::async_trait;
pub use super::openai_tool_search::DEFAULT_TOOL_SEARCH_THRESHOLD;
pub const CLAUDE_TOOL_SEARCH_CAPABILITY_ID: &str = "claude_tool_search";
pub struct ClaudeToolSearchCapability {
threshold: usize,
}
impl ClaudeToolSearchCapability {
pub fn new() -> Self {
Self {
threshold: DEFAULT_TOOL_SEARCH_THRESHOLD,
}
}
pub fn with_threshold(threshold: usize) -> Self {
Self { threshold }
}
pub fn tool_search_config(&self) -> ToolSearchConfig {
ToolSearchConfig {
enabled: true,
threshold: self.threshold,
}
}
}
pub fn model_supports_native_tool_search(model: &str) -> bool {
crate::model_profiles::get_model_profile(&crate::provider::DriverId::Anthropic, model)
.is_some_and(|profile| profile.tool_search)
}
impl Default for ClaudeToolSearchCapability {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl Capability for ClaudeToolSearchCapability {
fn id(&self) -> &str {
CLAUDE_TOOL_SEARCH_CAPABILITY_ID
}
fn name(&self) -> &str {
"Claude Tool Search"
}
fn description(&self) -> &str {
"Enables deferred tool loading for Claude models that support it \
(Sonnet 4, Opus 4, Haiku 4.5, and Fable 5 and newer). Reduces token \
usage by loading tool schemas on-demand instead of upfront."
}
fn localizations(&self) -> Vec<CapabilityLocalization> {
vec![CapabilityLocalization::text(
"uk",
"Пошук інструментів Claude",
"Вмикає відкладене завантаження інструментів для моделей Claude, які його підтримують (Sonnet 4, Opus 4, Haiku 4.5 та Fable 5 і новіші). Зменшує використання токенів, завантажуючи схеми інструментів на вимогу, а не заздалегідь.",
)]
}
fn status(&self) -> CapabilityStatus {
CapabilityStatus::Available
}
fn category(&self) -> Option<&str> {
Some("Optimization")
}
async fn system_prompt_contribution(&self, _ctx: &SystemPromptContext) -> Option<String> {
None }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_capability_metadata() {
let cap = ClaudeToolSearchCapability::new();
assert_eq!(cap.id(), CLAUDE_TOOL_SEARCH_CAPABILITY_ID);
assert_eq!(cap.name(), "Claude Tool Search");
assert_eq!(cap.status(), CapabilityStatus::Available);
assert!(cap.tools().is_empty());
}
#[test]
fn test_default_threshold() {
let cap = ClaudeToolSearchCapability::new();
let config = cap.tool_search_config();
assert!(config.enabled);
assert_eq!(config.threshold, DEFAULT_TOOL_SEARCH_THRESHOLD);
}
#[test]
fn test_custom_threshold() {
let cap = ClaudeToolSearchCapability::with_threshold(5);
assert_eq!(cap.tool_search_config().threshold, 5);
}
#[test]
fn test_native_support_lookup() {
assert!(model_supports_native_tool_search("claude-opus-4-8"));
assert!(model_supports_native_tool_search("claude-sonnet-4-6"));
assert!(model_supports_native_tool_search("claude-haiku-4-5"));
assert!(model_supports_native_tool_search("claude-fable-5"));
assert!(!model_supports_native_tool_search("claude-3-5-haiku"));
assert!(!model_supports_native_tool_search("gpt-5.5"));
}
}