deepseek/agent/builtin_tools/
glob.rs1use async_trait::async_trait;
2use serde_json::{json, Value};
3
4use crate::agent::tool::{Tool, ToolDefinition};
5
6const MAX_RESULTS: usize = 1000;
7
8pub struct GlobTool;
9
10#[async_trait]
11impl Tool for GlobTool {
12 fn name(&self) -> &str {
13 "Glob"
14 }
15
16 fn read_only_hint(&self) -> bool {
17 true
18 }
19
20 fn definition(&self) -> ToolDefinition {
21 ToolDefinition {
22 name: self.name().to_string(),
23 description: "Find files by glob pattern under a directory. Returns paths \
24 relative to that directory, one per line, sorted, capped at \
25 1000 results."
26 .into(),
27 parameters: json!({
28 "type": "object",
29 "properties": {
30 "pattern": { "type": "string", "description": "e.g. `**/*.rs`" },
31 "path": { "type": "string", "description": "Root directory (default: cwd)." }
32 },
33 "required": ["pattern"]
34 }),
35 }
36 }
37
38 async fn call_json(&self, args: Value) -> Result<String, String> {
39 let pattern = args
40 .get("pattern")
41 .and_then(Value::as_str)
42 .ok_or_else(|| "Glob: missing string `pattern`".to_string())?
43 .to_string();
44 let root = args
45 .get("path")
46 .and_then(Value::as_str)
47 .map(String::from)
48 .unwrap_or_else(|| ".".into());
49
50 let result = tokio::task::spawn_blocking(move || -> Result<String, String> {
51 let glob = globset::Glob::new(&pattern)
52 .map_err(|e| format!("Glob: bad pattern `{pattern}`: {e}"))?
53 .compile_matcher();
54 let root_path = std::path::PathBuf::from(&root);
55 let mut hits: Vec<String> = Vec::new();
56 for entry in walkdir::WalkDir::new(&root_path)
57 .into_iter()
58 .filter_map(Result::ok)
59 {
60 if !entry.file_type().is_file() {
61 continue;
62 }
63 let rel = entry
64 .path()
65 .strip_prefix(&root_path)
66 .unwrap_or(entry.path());
67 if glob.is_match(rel) {
68 hits.push(rel.display().to_string());
69 if hits.len() >= MAX_RESULTS {
70 break;
71 }
72 }
73 }
74 hits.sort();
75 Ok(hits.join("\n"))
76 })
77 .await
78 .map_err(|e| format!("Glob: task join error: {e}"))??;
79
80 Ok(result)
81 }
82}