use std::sync::Arc;
use crate::llm::{ToolCall, ToolSchema};
use super::tool::{Tool, ToolContext, ToolResult};
#[derive(Default)]
pub struct ToolRegistry {
tools: Vec<Arc<dyn Tool>>,
}
impl ToolRegistry {
pub fn new() -> Self {
Self { tools: Vec::new() }
}
pub fn register(&mut self, tool: Arc<dyn Tool>) {
if let Some(slot) = self.tools.iter_mut().find(|t| t.name() == tool.name()) {
*slot = tool;
} else {
self.tools.push(tool);
}
}
pub fn schemas(&self) -> Vec<ToolSchema> {
self.tools.iter().map(|t| t.schema()).collect()
}
pub fn is_empty(&self) -> bool {
self.tools.is_empty()
}
pub fn has(&self, name: &str) -> bool {
self.tools.iter().any(|t| t.name() == name)
}
pub fn len(&self) -> usize {
self.tools.len()
}
fn get(&self, name: &str) -> Option<&Arc<dyn Tool>> {
self.tools.iter().find(|t| t.name() == name)
}
pub async fn execute(&self, call: &ToolCall, ctx: &ToolContext) -> ToolResult {
let tool = match self.get(&call.name) {
Some(t) => t,
None => return ToolResult::error(format!("unknown tool: {}", call.name)),
};
match tool.execute(ctx, call.args.clone()).await {
Ok(result) => result,
Err(e) => ToolResult::error(format!("tool '{}' failed: {e}", call.name)),
}
}
}