use crate::error::AgentError;
use crate::tool::{Tool, ToolResult};
pub struct GlobTool;
impl Tool for GlobTool {
fn name(&self) -> &str {
"glob"
}
fn description(&self) -> &str {
"Find files matching a glob pattern. Returns a list of matching file paths. \
Supports standard glob patterns like '**/*.rs', 'src/*.cpp', etc."
}
fn parameters_schema(&self) -> serde_json::Value {
serde_json::json!({
"type": "object",
"properties": {
"pattern": {
"type": "string",
"description": "Glob pattern to match files (e.g. '**/*.rs', 'src/**/*.cpp')"
}
},
"required": ["pattern"]
})
}
fn execute(&self, args: &serde_json::Value) -> Result<ToolResult, AgentError> {
let pattern = args["pattern"].as_str().ok_or_else(|| AgentError::Tool {
tool: "glob".to_string(),
message: "Missing 'pattern' argument".to_string(),
})?;
match glob::glob(pattern) {
Ok(paths) => {
let mut results = Vec::new();
let mut errors = 0;
for entry in paths {
match entry {
Ok(path) => results.push(path.display().to_string()),
Err(_) => errors += 1,
}
}
if results.is_empty() {
return Ok(ToolResult::ok(format!(
"No files matched pattern '{}'",
pattern
)));
}
let mut output = format!("Found {} file(s) matching '{}':\n", results.len(), pattern);
for path in &results {
output.push_str(&format!(" {}\n", path));
}
if errors > 0 {
output.push_str(&format!("({} entries could not be read)\n", errors));
}
Ok(ToolResult::ok(output))
}
Err(e) => Ok(ToolResult::err(format!(
"Invalid glob pattern '{}': {}",
pattern, e
))),
}
}
fn requires_permission(&self) -> bool {
false
}
}