Skip to main content

matrixcode_core/tools/
read.rs

1use anyhow::Result;
2use async_trait::async_trait;
3use serde_json::{Value, json};
4
5use super::{Tool, ToolDefinition};
6
7pub struct ReadTool;
8
9#[async_trait]
10impl Tool for ReadTool {
11    fn definition(&self) -> ToolDefinition {
12        ToolDefinition {
13            name: "read".to_string(),
14            description: "Read the contents of a file at the given path".to_string(),
15            parameters: json!({
16                "type": "object",
17                "properties": {
18                    "path": {
19                        "type": "string",
20                        "description": "The file path to read"
21                    },
22                    "offset": {
23                        "type": "integer",
24                        "description": "Line number to start reading from (0-based)"
25                    },
26                    "limit": {
27                        "type": "integer",
28                        "description": "Maximum number of lines to read"
29                    }
30                },
31                "required": ["path"]
32            }),
33        }
34    }
35
36    async fn execute(&self, params: Value) -> Result<String> {
37        // Create spinner immediately at the start to fill the gap before actual operation
38        // let mut spinner = ToolSpinner::new("preparing read");
39
40        let path = params["path"].as_str().ok_or_else(|| anyhow::anyhow!("missing 'path'"))?;
41
42        // Update spinner message for the actual read operation
43        // spinner.set_message(&format!("reading {}", path));
44
45        let content = tokio::fs::read_to_string(path).await?;
46
47        let offset = params["offset"].as_u64().unwrap_or(0) as usize;
48        let limit = params["limit"].as_u64().map(|l| l as usize);
49
50        let lines: Vec<&str> = content.lines().collect();
51        let end = limit.map(|l| (offset + l).min(lines.len())).unwrap_or(lines.len());
52        let selected = &lines[offset.min(lines.len())..end.min(lines.len())];
53
54        let result: String = selected
55            .iter()
56            .enumerate()
57            .map(|(i, line)| format!("{:4} | {}", offset + i + 1, line))
58            .collect::<Vec<_>>()
59            .join("\n");
60
61        // spinner.finish_success(&format!("{} lines", selected.len()));
62        Ok(result)
63    }
64}