use super::BaseTool;
use std::collections::HashMap;
use std::sync::Arc;
pub struct ToolRegistry {
tools: HashMap<String, Arc<dyn BaseTool>>,
}
impl ToolRegistry {
pub fn new() -> Self {
Self {
tools: HashMap::new(),
}
}
pub fn register(&mut self, tool: Arc<dyn BaseTool>) -> Option<Arc<dyn BaseTool>> {
let name = tool.name().to_string();
self.tools.insert(name, tool)
}
pub fn get(&self, name: &str) -> Option<&Arc<dyn BaseTool>> {
self.tools.get(name)
}
pub fn tool_names(&self) -> Vec<&str> {
self.tools.keys().map(|s: &String| s.as_str()).collect()
}
pub fn tools(&self) -> Vec<&Arc<dyn BaseTool>> {
self.tools.values().collect()
}
pub fn len(&self) -> usize {
self.tools.len()
}
pub fn is_empty(&self) -> bool {
self.tools.is_empty()
}
pub fn remove(&mut self, name: &str) -> Option<Arc<dyn BaseTool>> {
self.tools.remove(name)
}
pub fn contains(&self, name: &str) -> bool {
self.tools.contains_key(name)
}
pub fn describe_tools(&self) -> String {
if self.tools.is_empty() {
return "No tools available".to_string();
}
let mut description = String::from("Available tools:\n");
for (name, tool) in &self.tools {
description.push_str(&format!("- {}: {}\n", name, tool.description()));
if let Some(schema) = tool.args_schema() {
if let Some(props) = schema.get("properties") {
description.push_str(" Input parameters:\n");
if let Some(obj) = props.as_object() {
for (prop_name, prop_value) in obj {
let prop_desc = prop_value
.get("description")
.and_then(|d: &serde_json::Value| d.as_str())
.unwrap_or("No description");
description.push_str(&format!(" - {}: {}\n", prop_name, prop_desc));
}
}
}
}
}
description
}
}
impl Default for ToolRegistry {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Debug for ToolRegistry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ToolRegistry")
.field("tool_count", &self.tools.len())
.field("tool_names", &self.tool_names())
.finish()
}
}