Skip to main content

dot/tools/
mod.rs

1pub mod batch;
2pub mod file;
3pub mod glob;
4pub mod grep;
5pub mod multiedit;
6pub mod patch;
7pub mod shell;
8pub mod web;
9
10use crate::provider::ToolDefinition;
11
12pub trait Tool: Send + Sync {
13    fn name(&self) -> &str;
14    fn description(&self) -> &str;
15    fn input_schema(&self) -> serde_json::Value;
16    fn execute(&self, input: serde_json::Value) -> anyhow::Result<String>;
17}
18
19pub struct ToolRegistry {
20    tools: Vec<Box<dyn Tool>>,
21}
22
23impl ToolRegistry {
24    pub fn new() -> Self {
25        ToolRegistry { tools: Vec::new() }
26    }
27
28    pub fn register(&mut self, tool: Box<dyn Tool>) {
29        self.tools.push(tool);
30    }
31
32    pub fn register_many(&mut self, tools: Vec<Box<dyn Tool>>) {
33        self.tools.extend(tools);
34    }
35
36    pub fn definitions(&self) -> Vec<ToolDefinition> {
37        self.tools
38            .iter()
39            .map(|t| ToolDefinition {
40                name: t.name().to_string(),
41                description: t.description().to_string(),
42                input_schema: t.input_schema(),
43            })
44            .collect()
45    }
46
47    /// Return tool definitions filtered by an allow/deny map.
48    /// If the map is empty, all tools are returned. Otherwise, tools
49    /// explicitly set to `false` are excluded.
50    pub fn definitions_filtered(
51        &self,
52        filter: &std::collections::HashMap<String, bool>,
53    ) -> Vec<ToolDefinition> {
54        if filter.is_empty() {
55            return self.definitions();
56        }
57        self.tools
58            .iter()
59            .filter(|t| filter.get(t.name()).copied().unwrap_or(true))
60            .map(|t| ToolDefinition {
61                name: t.name().to_string(),
62                description: t.description().to_string(),
63                input_schema: t.input_schema(),
64            })
65            .collect()
66    }
67
68    pub fn execute(&self, name: &str, input: serde_json::Value) -> anyhow::Result<String> {
69        for tool in &self.tools {
70            if tool.name() == name {
71                tracing::debug!("Executing tool: {}", name);
72                return tool.execute(input);
73            }
74        }
75        anyhow::bail!("Unknown tool: {}", name)
76    }
77
78    pub fn tool_count(&self) -> usize {
79        self.tools.len()
80    }
81
82    pub fn default_tools() -> Self {
83        let mut registry = Self::new();
84        registry.register(Box::new(file::ReadFileTool));
85        registry.register(Box::new(file::WriteFileTool));
86        registry.register(Box::new(file::ListDirectoryTool));
87        registry.register(Box::new(file::SearchFilesTool));
88        registry.register(Box::new(shell::RunCommandTool));
89        registry.register(Box::new(glob::GlobTool));
90        registry.register(Box::new(grep::GrepTool));
91        registry.register(Box::new(web::WebFetchTool));
92        registry.register(Box::new(patch::ApplyPatchTool));
93        registry.register(Box::new(multiedit::MultiEditTool));
94        registry.register(Box::new(batch::BatchTool));
95        registry
96    }
97}
98
99impl Default for ToolRegistry {
100    fn default() -> Self {
101        Self::new()
102    }
103}