use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use crate::error::{Result, SdkError};
#[derive(Debug, Clone)]
pub struct ToolDefinition {
pub name: String,
pub description: Option<String>,
pub input_schema: Option<String>,
pub output_schema: Option<String>,
}
#[derive(Clone)]
pub struct ToolHandle {
name: String,
registry: Arc<ToolRegistry>,
}
impl ToolHandle {
pub fn name(&self) -> &str {
&self.name
}
pub fn definition(&self) -> Result<ToolDefinition> {
self.registry.get(&self.name)
}
}
#[derive(Default)]
pub struct ToolRegistry {
inner: Mutex<HashMap<String, ToolDefinition>>,
}
impl ToolRegistry {
pub fn new() -> Arc<Self> {
Arc::new(Self::default())
}
pub fn register(self: &Arc<Self>, definition: ToolDefinition) -> Result<ToolHandle> {
let mut guard = self
.inner
.lock()
.map_err(|_| SdkError::Internal("tool registry mutex poisoned".to_string()))?;
if !guard.contains_key(&definition.name) {
guard.insert(definition.name.clone(), definition.clone());
}
Ok(ToolHandle {
name: definition.name,
registry: Arc::clone(self),
})
}
pub fn get(self: &Arc<Self>, name: &str) -> Result<ToolDefinition> {
let guard = self
.inner
.lock()
.map_err(|_| SdkError::Internal("tool registry mutex poisoned".to_string()))?;
guard
.get(name)
.cloned()
.ok_or_else(|| SdkError::Configuration {
message: format!("Tool '{name}' not found"),
field: Some("name".to_string()),
})
}
pub fn list(self: &Arc<Self>) -> Result<Vec<ToolDefinition>> {
let guard = self
.inner
.lock()
.map_err(|_| SdkError::Internal("tool registry mutex poisoned".to_string()))?;
Ok(guard.values().cloned().collect())
}
pub fn clear(self: &Arc<Self>) -> Result<()> {
let mut guard = self
.inner
.lock()
.map_err(|_| SdkError::Internal("tool registry mutex poisoned".to_string()))?;
guard.clear();
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn register_and_get_tool() {
let registry = ToolRegistry::new();
let definition = ToolDefinition {
name: "search".to_string(),
description: Some("Search the web".to_string()),
input_schema: None,
output_schema: None,
};
registry.register(definition).unwrap();
let tools = registry.list().unwrap();
assert_eq!(tools.len(), 1);
assert_eq!(tools[0].name, "search");
}
}