Skip to main content

lc_core/tools/
registry.rs

1// src/core/tools/registry.rs
2//! Tool registry for managing multiple tools.
3//!
4//! Provides unified lookup and execution interface.
5
6use super::BaseTool;
7use std::collections::HashMap;
8use std::sync::Arc;
9
10/// Tool registry for storing and managing multiple tool instances.
11///
12/// Provides name-based lookup and execution functionality.
13///
14/// # Example
15/// ```ignore
16/// use langchainrust::ToolRegistry;
17/// use langchainrust::Calculator;
18/// use std::sync::Arc;
19///
20/// let registry = ToolRegistry::new();
21/// registry.register(Arc::new(Calculator::new()));
22///
23/// let tool = registry.get("calculator").unwrap();
24/// ```
25pub struct ToolRegistry {
26    /// Tool storage (indexed by name).
27    tools: HashMap<String, Arc<dyn BaseTool>>,
28}
29
30impl ToolRegistry {
31    /// Creates an empty tool registry.
32    pub fn new() -> Self {
33        Self {
34            tools: HashMap::new(),
35        }
36    }
37
38    /// Registers a tool.
39    ///
40    /// # Arguments
41    /// * `tool` - Tool to register (wrapped in Arc for sharing).
42    ///
43    /// # Returns
44    /// Previous tool if name conflict, otherwise None.
45    pub fn register(&mut self, tool: Arc<dyn BaseTool>) -> Option<Arc<dyn BaseTool>> {
46        let name = tool.name().to_string();
47        self.tools.insert(name, tool)
48    }
49
50    /// Gets a tool by name.
51    ///
52    /// # Arguments
53    /// * `name` - Tool name.
54    ///
55    /// # Returns
56    /// Tool reference if found, otherwise None.
57    pub fn get(&self, name: &str) -> Option<&Arc<dyn BaseTool>> {
58        self.tools.get(name)
59    }
60
61    /// Returns all tool names.
62    pub fn tool_names(&self) -> Vec<&str> {
63        self.tools.keys().map(|s: &String| s.as_str()).collect()
64    }
65
66    /// Returns all tools.
67    pub fn tools(&self) -> Vec<&Arc<dyn BaseTool>> {
68        self.tools.values().collect()
69    }
70
71    /// Returns tool count.
72    pub fn len(&self) -> usize {
73        self.tools.len()
74    }
75
76    /// Returns whether registry is empty.
77    pub fn is_empty(&self) -> bool {
78        self.tools.is_empty()
79    }
80
81    /// Removes a tool by name.
82    ///
83    /// # Arguments
84    /// * `name` - Tool name.
85    ///
86    /// # Returns
87    /// Removed tool if found, otherwise None.
88    pub fn remove(&mut self, name: &str) -> Option<Arc<dyn BaseTool>> {
89        self.tools.remove(name)
90    }
91
92    /// Checks if a tool exists.
93    pub fn contains(&self, name: &str) -> bool {
94        self.tools.contains_key(name)
95    }
96
97    /// Generates tool description for LLM.
98    ///
99    /// Used to show available tools to the LLM.
100    pub fn describe_tools(&self) -> String {
101        if self.tools.is_empty() {
102            return "No tools available".to_string();
103        }
104
105        let mut description = String::from("Available tools:\n");
106
107        for (name, tool) in &self.tools {
108            description.push_str(&format!("- {}: {}\n", name, tool.description()));
109
110            // Add input format description
111            if let Some(schema) = tool.args_schema() {
112                if let Some(props) = schema.get("properties") {
113                    description.push_str("  Input parameters:\n");
114                    if let Some(obj) = props.as_object() {
115                        for (prop_name, prop_value) in obj {
116                            let prop_desc = prop_value
117                                .get("description")
118                                .and_then(|d: &serde_json::Value| d.as_str())
119                                .unwrap_or("No description");
120                            description.push_str(&format!("    - {}: {}\n", prop_name, prop_desc));
121                        }
122                    }
123                }
124            }
125        }
126
127        description
128    }
129}
130
131impl Default for ToolRegistry {
132    fn default() -> Self {
133        Self::new()
134    }
135}
136
137impl std::fmt::Debug for ToolRegistry {
138    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139        f.debug_struct("ToolRegistry")
140            .field("tool_count", &self.tools.len())
141            .field("tool_names", &self.tool_names())
142            .finish()
143    }
144}