matrixcode_core/tools/
read.rs1use anyhow::Result;
2use async_trait::async_trait;
3use serde_json::{Value, json};
4
5use super::{Tool, ToolDefinition};
6
7const MAX_FILE_SIZE: u64 = 5_000_000;
9const DEFAULT_MAX_LINES: usize = 500;
11
12pub struct ReadTool;
13
14#[async_trait]
15impl Tool for ReadTool {
16 fn definition(&self) -> ToolDefinition {
17 ToolDefinition {
18 name: "read".to_string(),
19 description: "读取指定路径的文件内容".to_string(),
20 parameters: json!({
21 "type": "object",
22 "properties": {
23 "path": {
24 "type": "string",
25 "description": "要读取的文件路径"
26 },
27 "offset": {
28 "type": "integer",
29 "description": "起始行号(从 0 开始)"
30 },
31 "limit": {
32 "type": "integer",
33 "description": "最大读取行数"
34 }
35 },
36 "required": ["path"]
37 }),
38 }
39 }
40
41 async fn execute(&self, params: Value) -> Result<String> {
42 let path = params["path"]
43 .as_str()
44 .ok_or_else(|| anyhow::anyhow!("missing 'path'"))?;
45
46 let metadata = tokio::fs::metadata(path).await?;
48 let file_size = metadata.len();
49
50 let offset = params["offset"].as_u64().unwrap_or(0) as usize;
51 let limit = params["limit"].as_u64().map(|l| l as usize);
52
53 if file_size > MAX_FILE_SIZE && limit.is_none() {
55 return Ok(format!(
56 "⚠️ File is large ({:.1}MB). Use offset/limit parameters to read specific sections.\n\
57 Example: read(path=\"{}\", offset=0, limit=100) to read first 100 lines.",
58 file_size as f64 / 1_000_000.0,
59 path
60 ));
61 }
62
63 let content = tokio::fs::read_to_string(path).await?;
64
65 let lines: Vec<&str> = content.lines().collect();
66 let total_lines = lines.len();
67
68 let effective_limit = limit.unwrap_or(DEFAULT_MAX_LINES);
70 let end = (offset + effective_limit).min(total_lines);
71 let selected = &lines[offset.min(total_lines)..end.min(total_lines)];
72
73 let mut result = String::new();
74
75 if offset > 0 || end < total_lines {
77 result.push_str(&format!(
78 "📄 {} (lines {}-{} of {})\n\n",
79 path,
80 offset + 1,
81 end,
82 total_lines
83 ));
84 }
85
86 for (i, line) in selected.iter().enumerate() {
87 result.push_str(&format!("{:4} | {}\n", offset + i + 1, line));
88 }
89
90 if end < total_lines {
92 result.push_str(&format!(
93 "\n... ({} more lines, use offset={} limit=N to continue)",
94 total_lines - end,
95 end
96 ));
97 }
98
99 Ok(result)
100 }
101}