use super::{Capability, CapabilityStatus, SystemPromptContext};
use crate::llm_driver_registry::ToolSearchConfig;
use async_trait::async_trait;
pub const DEFAULT_TOOL_SEARCH_THRESHOLD: usize = 15;
pub const OPENAI_TOOL_SEARCH_CAPABILITY_ID: &str = "openai_tool_search";
pub struct OpenAiToolSearchCapability {
threshold: usize,
}
impl OpenAiToolSearchCapability {
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::llm_model_profiles::get_model_profile(&crate::llm_models::LlmProviderType::Openai, model)
.is_some_and(|profile| profile.tool_search)
}
impl Default for OpenAiToolSearchCapability {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl Capability for OpenAiToolSearchCapability {
fn id(&self) -> &str {
OPENAI_TOOL_SEARCH_CAPABILITY_ID
}
fn name(&self) -> &str {
"OpenAI Tool Search"
}
fn description(&self) -> &str {
"Enables deferred tool loading for models that support it (GPT-5.4 and newer). \
Reduces token usage by loading tool schemas on-demand instead of upfront."
}
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 = OpenAiToolSearchCapability::new();
assert_eq!(cap.id(), OPENAI_TOOL_SEARCH_CAPABILITY_ID);
assert_eq!(cap.name(), "OpenAI Tool Search");
assert_eq!(cap.status(), CapabilityStatus::Available);
assert!(cap.tools().is_empty());
}
#[test]
fn test_default_threshold() {
let cap = OpenAiToolSearchCapability::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 = OpenAiToolSearchCapability::with_threshold(5);
let config = cap.tool_search_config();
assert_eq!(config.threshold, 5);
}
}