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: "读取指定路径的文件内容".to_string(),
15            parameters: json!({
16                "type": "object",
17                "properties": {
18                    "path": {
19                        "type": "string",
20                        "description": "要读取的文件路径"
21                    },
22                    "offset": {
23                        "type": "integer",
24                        "description": "起始行号(从 0 开始)"
25                    },
26                    "limit": {
27                        "type": "integer",
28                        "description": "最大读取行数"
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"]
41            .as_str()
42            .ok_or_else(|| anyhow::anyhow!("missing 'path'"))?;
43
44        // Update spinner message for the actual read operation
45        // spinner.set_message(&format!("reading {}", path));
46
47        let content = tokio::fs::read_to_string(path).await?;
48
49        let offset = params["offset"].as_u64().unwrap_or(0) as usize;
50        let limit = params["limit"].as_u64().map(|l| l as usize);
51
52        let lines: Vec<&str> = content.lines().collect();
53        let end = limit
54            .map(|l| (offset + l).min(lines.len()))
55            .unwrap_or(lines.len());
56        let selected = &lines[offset.min(lines.len())..end.min(lines.len())];
57
58        let result: String = selected
59            .iter()
60            .enumerate()
61            .map(|(i, line)| format!("{:4} | {}", offset + i + 1, line))
62            .collect::<Vec<_>>()
63            .join("\n");
64
65        // spinner.finish_success(&format!("{} lines", selected.len()));
66        Ok(result)
67    }
68}