everruns_core/capabilities/
openai_tool_search.rs1use super::{Capability, CapabilityLocalization, CapabilityStatus, SystemPromptContext};
15use crate::llm_driver_registry::ToolSearchConfig;
16use async_trait::async_trait;
17
18pub const DEFAULT_TOOL_SEARCH_THRESHOLD: usize = 15;
21
22pub const OPENAI_TOOL_SEARCH_CAPABILITY_ID: &str = "openai_tool_search";
24
25pub struct OpenAiToolSearchCapability {
31 threshold: usize,
32}
33
34impl OpenAiToolSearchCapability {
35 pub fn new() -> Self {
36 Self {
37 threshold: DEFAULT_TOOL_SEARCH_THRESHOLD,
38 }
39 }
40
41 pub fn with_threshold(threshold: usize) -> Self {
42 Self { threshold }
43 }
44
45 pub fn tool_search_config(&self) -> ToolSearchConfig {
47 ToolSearchConfig {
48 enabled: true,
49 threshold: self.threshold,
50 }
51 }
52}
53
54pub fn model_supports_native_tool_search(model: &str) -> bool {
63 crate::llm_model_profiles::get_model_profile(&crate::llm_models::LlmProviderType::Openai, model)
64 .is_some_and(|profile| profile.tool_search)
65}
66
67impl Default for OpenAiToolSearchCapability {
68 fn default() -> Self {
69 Self::new()
70 }
71}
72
73#[async_trait]
74impl Capability for OpenAiToolSearchCapability {
75 fn id(&self) -> &str {
76 OPENAI_TOOL_SEARCH_CAPABILITY_ID
77 }
78
79 fn name(&self) -> &str {
80 "OpenAI Tool Search"
81 }
82
83 fn description(&self) -> &str {
84 "Enables deferred tool loading for models that support it (GPT-5.4 and newer). \
85 Reduces token usage by loading tool schemas on-demand instead of upfront."
86 }
87
88 fn localizations(&self) -> Vec<CapabilityLocalization> {
89 vec![CapabilityLocalization::text(
90 "uk",
91 "Пошук інструментів OpenAI",
92 "Вмикає відкладене завантаження інструментів для моделей, які його підтримують (GPT-5.4 і новіші). Зменшує використання токенів, завантажуючи схеми інструментів на вимогу, а не заздалегідь.",
93 )]
94 }
95
96 fn status(&self) -> CapabilityStatus {
97 CapabilityStatus::Available
98 }
99
100 fn category(&self) -> Option<&str> {
101 Some("Optimization")
102 }
103
104 async fn system_prompt_contribution(&self, _ctx: &SystemPromptContext) -> Option<String> {
105 None }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_capability_metadata() {
115 let cap = OpenAiToolSearchCapability::new();
116 assert_eq!(cap.id(), OPENAI_TOOL_SEARCH_CAPABILITY_ID);
117 assert_eq!(cap.name(), "OpenAI Tool Search");
118 assert_eq!(cap.status(), CapabilityStatus::Available);
119 assert!(cap.tools().is_empty());
120 }
121
122 #[test]
123 fn test_default_threshold() {
124 let cap = OpenAiToolSearchCapability::new();
125 let config = cap.tool_search_config();
126 assert!(config.enabled);
127 assert_eq!(config.threshold, DEFAULT_TOOL_SEARCH_THRESHOLD);
128 }
129
130 #[test]
131 fn test_custom_threshold() {
132 let cap = OpenAiToolSearchCapability::with_threshold(5);
133 let config = cap.tool_search_config();
134 assert_eq!(config.threshold, 5);
135 }
136}