phi_core/tools/
registry.rs1use crate::types::AgentTool;
8use std::collections::HashMap;
9use std::sync::Arc;
10
11pub struct ToolRegistry {
23 factories: HashMap<String, Box<dyn Fn() -> Arc<dyn AgentTool> + Send + Sync>>,
24}
25
26impl ToolRegistry {
27 pub fn new() -> Self {
29 Self {
30 factories: HashMap::new(),
31 }
32 }
33
34 pub fn with_defaults(mut self) -> Self {
36 self.register("bash", || Arc::new(super::BashTool::default()));
37 self.register("read_file", || Arc::new(super::ReadFileTool::default()));
38 self.register("write_file", || Arc::new(super::WriteFileTool::new()));
39 self.register("edit_file", || Arc::new(super::EditFileTool::new()));
40 self.register("list_files", || Arc::new(super::ListFilesTool::default()));
41 self.register("search", || Arc::new(super::SearchTool::default()));
42 self
43 }
44
45 pub fn register(
49 &mut self,
50 name: &str,
51 factory: impl Fn() -> Arc<dyn AgentTool> + Send + Sync + 'static,
52 ) {
53 self.factories.insert(name.to_string(), Box::new(factory));
54 }
55
56 pub fn resolve(&self, names: &[String]) -> Vec<Arc<dyn AgentTool>> {
58 names
59 .iter()
60 .filter_map(|name| self.factories.get(name).map(|f| f()))
61 .collect()
62 }
63
64 pub fn contains(&self, name: &str) -> bool {
66 self.factories.contains_key(name)
67 }
68
69 pub fn len(&self) -> usize {
71 self.factories.len()
72 }
73
74 pub fn is_empty(&self) -> bool {
76 self.factories.is_empty()
77 }
78}
79
80impl Default for ToolRegistry {
81 fn default() -> Self {
82 Self::new()
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_empty_registry() {
92 let registry = ToolRegistry::new();
93 assert!(registry.is_empty());
94 let tools = registry.resolve(&["bash".to_string()]);
95 assert!(tools.is_empty());
96 }
97
98 #[test]
99 fn test_with_defaults() {
100 let registry = ToolRegistry::new().with_defaults();
101 assert_eq!(registry.len(), 6);
102 assert!(registry.contains("bash"));
103 assert!(registry.contains("read_file"));
104 assert!(registry.contains("write_file"));
105 assert!(registry.contains("edit_file"));
106 assert!(registry.contains("list_files"));
107 assert!(registry.contains("search"));
108 }
109
110 #[test]
111 fn test_resolve_subset() {
112 let registry = ToolRegistry::new().with_defaults();
113 let tools = registry.resolve(&["bash".to_string(), "search".to_string()]);
114 assert_eq!(tools.len(), 2);
115 }
116
117 #[test]
118 fn test_resolve_skips_unknown() {
119 let registry = ToolRegistry::new().with_defaults();
120 let tools = registry.resolve(&["bash".to_string(), "nonexistent".to_string()]);
121 assert_eq!(tools.len(), 1);
122 }
123
124 #[test]
125 fn test_custom_registration() {
126 let mut registry = ToolRegistry::new();
127 registry.register("bash", || Arc::new(super::super::BashTool::default()));
128 assert_eq!(registry.len(), 1);
129 assert!(registry.contains("bash"));
130 }
131}