Skip to main content

deepseek/agent/builtin_tools/
read.rs

1use async_trait::async_trait;
2use serde_json::{json, Value};
3
4use crate::agent::tool::{Tool, ToolDefinition};
5
6
7pub struct ReadTool;
8
9#[async_trait]
10impl Tool for ReadTool {
11    fn name(&self) -> &str {
12        "Read"
13    }
14
15    fn read_only_hint(&self) -> bool {
16        true
17    }
18
19    fn definition(&self) -> ToolDefinition {
20        ToolDefinition {
21            name: self.name().to_string(),
22            description: "Read a UTF-8 text file from disk. Optionally slice by 1-based line offset and limit.".into(),
23            parameters: json!({
24                "type": "object",
25                "properties": {
26                    "path":   { "type": "string", "description": "Absolute or cwd-relative path." },
27                    "offset": { "type": "integer", "description": "1-based line to start at.", "minimum": 1 },
28                    "limit":  { "type": "integer", "description": "Maximum number of lines to return.", "minimum": 1 }
29                },
30                "required": ["path"]
31            }),
32        }
33    }
34
35    async fn call_json(&self, args: Value) -> Result<String, String> {
36        let path = args
37            .get("path")
38            .and_then(Value::as_str)
39            .ok_or_else(|| "Read: missing string `path`".to_string())?;
40        let offset = args.get("offset").and_then(Value::as_u64).map(|n| n as usize);
41        let limit = args.get("limit").and_then(Value::as_u64).map(|n| n as usize);
42
43        let body = tokio::fs::read_to_string(path)
44            .await
45            .map_err(|e| format!("Read({path}): {e}"))?;
46
47        if offset.is_none() && limit.is_none() {
48            return Ok(body);
49        }
50
51        let mut out = String::new();
52        let start = offset.unwrap_or(1).saturating_sub(1);
53        let count = limit.unwrap_or(usize::MAX);
54        for line in body.lines().skip(start).take(count) {
55            out.push_str(line);
56            out.push('\n');
57        }
58        Ok(out)
59    }
60}