Skip to main content

pi_agent/tools/
ls.rs

1use async_trait::async_trait;
2use serde_json::{json, Value};
3use tokio::fs;
4
5use crate::types::{AgentTool, AgentToolResult};
6
7pub struct LsTool;
8
9#[async_trait]
10impl AgentTool for LsTool {
11    fn name(&self) -> &str {
12        "ls"
13    }
14    fn description(&self) -> &str {
15        "List entries in a directory. Returns name and kind (file/dir/symlink)."
16    }
17    fn parameters(&self) -> Value {
18        json!({
19            "type": "object",
20            "properties": {"path": {"type": "string"}},
21            "required": ["path"]
22        })
23    }
24    async fn execute(&self, _id: &str, args: Value) -> Result<AgentToolResult, String> {
25        let path = args
26            .get("path")
27            .and_then(|v| v.as_str())
28            .ok_or("missing 'path'")?;
29        let mut read = fs::read_dir(path)
30            .await
31            .map_err(|e| format!("ls {path}: {e}"))?;
32        let mut buf = String::new();
33        while let Some(entry) = read.next_entry().await.map_err(|e| e.to_string())? {
34            let ft = entry.file_type().await.map_err(|e| e.to_string())?;
35            let kind = if ft.is_dir() {
36                "dir"
37            } else if ft.is_symlink() {
38                "symlink"
39            } else {
40                "file"
41            };
42            buf.push_str(&format!(
43                "{}\t{}\n",
44                kind,
45                entry.file_name().to_string_lossy()
46            ));
47        }
48        Ok(AgentToolResult::text(buf))
49    }
50}