hyper_agent_ai/
tool_registry.rs1use motosan_chat_tool::{Tool, ToolContext, ToolDef, ToolResult, Value};
2use std::collections::HashMap;
3use std::sync::Arc;
4use tokio::sync::RwLock;
5
6pub struct ToolRegistry {
7 inner: Arc<RwLock<HashMap<String, Arc<dyn Tool>>>>,
8}
9
10impl ToolRegistry {
11 pub fn new() -> Self {
12 Self {
13 inner: Arc::new(RwLock::new(HashMap::new())),
14 }
15 }
16
17 pub async fn register(&self, tool: Arc<dyn Tool>) {
18 let def = tool.def();
19 self.inner.write().await.insert(def.name.clone(), tool);
20 }
21
22 pub async fn get(&self, name: &str) -> Option<Arc<dyn Tool>> {
23 self.inner.read().await.get(name).cloned()
24 }
25
26 pub async fn list(&self) -> Vec<ToolDef> {
27 self.inner.read().await.values().map(|t| t.def()).collect()
28 }
29
30 pub async fn execute(&self, name: &str, input: Value, ctx: ToolContext) -> Option<ToolResult> {
31 let tool = self.get(name).await?;
32 Some(tool.call(input, &ctx).await)
33 }
34}
35
36impl Default for ToolRegistry {
37 fn default() -> Self {
38 Self::new()
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45 use crate::tools::DoNothingTool;
46
47 #[tokio::test]
48 async fn register_and_list() {
49 let registry = ToolRegistry::new();
50 registry.register(Arc::new(DoNothingTool)).await;
51 let tools = registry.list().await;
52 assert_eq!(tools.len(), 1);
53 assert_eq!(tools[0].name, "do_nothing");
54 }
55
56 #[tokio::test]
57 async fn get_returns_none_for_unknown() {
58 let registry = ToolRegistry::new();
59 assert!(registry.get("nonexistent").await.is_none());
60 }
61}