Skip to main content

sgr_agent_tools/
find.rs

1//! FindTool — find files/directories by name pattern.
2
3use std::sync::Arc;
4
5use schemars::JsonSchema;
6use serde::Deserialize;
7use serde_json::Value;
8use sgr_agent_core::agent_tool::{Tool, ToolError, ToolOutput, parse_args};
9use sgr_agent_core::context::AgentContext;
10use sgr_agent_core::schema::json_schema_for;
11
12use crate::backend::FileBackend;
13use crate::helpers::{backend_err, def_root};
14
15pub struct FindTool<B: FileBackend>(pub Arc<B>);
16
17#[derive(Deserialize, JsonSchema)]
18struct FindArgs {
19    /// Search root directory
20    #[serde(default = "def_root")]
21    root: String,
22    /// File/directory name pattern
23    name: String,
24    /// Filter: "files", "dirs", or empty for all
25    #[serde(default, rename = "type")]
26    file_type: String,
27    /// Max results (0 = no limit)
28    #[serde(default)]
29    limit: i32,
30}
31
32#[async_trait::async_trait]
33impl<B: FileBackend> Tool for FindTool<B> {
34    fn name(&self) -> &str {
35        "find"
36    }
37    fn description(&self) -> &str {
38        "Find files/directories by name pattern"
39    }
40    fn is_read_only(&self) -> bool {
41        true
42    }
43    fn parameters_schema(&self) -> Value {
44        json_schema_for::<FindArgs>()
45    }
46    async fn execute(&self, args: Value, _ctx: &mut AgentContext) -> Result<ToolOutput, ToolError> {
47        let a: FindArgs = parse_args(&args)?;
48        self.0
49            .find(&a.root, &a.name, &a.file_type, a.limit)
50            .await
51            .map(ToolOutput::text)
52            .map_err(backend_err)
53    }
54    async fn execute_readonly(
55        &self,
56        args: Value,
57        _ctx: &AgentContext,
58    ) -> Result<ToolOutput, ToolError> {
59        let a: FindArgs = parse_args(&args)?;
60        self.0
61            .find(&a.root, &a.name, &a.file_type, a.limit)
62            .await
63            .map(ToolOutput::text)
64            .map_err(backend_err)
65    }
66}