Skip to main content

pi_agent/tools/
read.rs

1use async_trait::async_trait;
2use serde_json::{json, Value};
3use tokio::fs;
4
5use crate::types::{AgentTool, AgentToolResult};
6
7pub struct ReadTool;
8
9#[async_trait]
10impl AgentTool for ReadTool {
11    fn name(&self) -> &str {
12        "read"
13    }
14    fn description(&self) -> &str {
15        "Read the contents of a file from disk. Returns text content with optional line numbers."
16    }
17    fn parameters(&self) -> Value {
18        json!({
19            "type": "object",
20            "properties": {
21                "path": {"type": "string", "description": "Absolute or relative path to the file"},
22                "offset": {"type": "integer", "description": "Line offset (1-based), optional"},
23                "limit": {"type": "integer", "description": "Max number of lines, optional"}
24            },
25            "required": ["path"]
26        })
27    }
28    async fn execute(&self, _id: &str, args: Value) -> Result<AgentToolResult, String> {
29        let path = args
30            .get("path")
31            .and_then(|v| v.as_str())
32            .ok_or("missing 'path'")?;
33        let offset = args
34            .get("offset")
35            .and_then(|v| v.as_u64())
36            .map(|v| v as usize);
37        let limit = args
38            .get("limit")
39            .and_then(|v| v.as_u64())
40            .map(|v| v as usize);
41
42        let text = fs::read_to_string(path)
43            .await
44            .map_err(|e| format!("read {path}: {e}"))?;
45        let lines: Vec<&str> = text.lines().collect();
46        let start = offset.map(|o| o.saturating_sub(1)).unwrap_or(0);
47        let end = limit
48            .map(|l| std::cmp::min(start + l, lines.len()))
49            .unwrap_or(lines.len());
50
51        let mut buf = String::new();
52        for (i, line) in lines[start..end].iter().enumerate() {
53            buf.push_str(&format!("{:>5}\t{}\n", start + i + 1, line));
54        }
55        Ok(AgentToolResult::text(buf))
56    }
57}