1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5#[serde(deny_unknown_fields)]
6pub struct ReadParams {
7 pub path: String,
8 #[serde(default, skip_serializing_if = "Option::is_none")]
9 pub offset: Option<usize>,
10 #[serde(default, skip_serializing_if = "Option::is_none")]
11 pub limit: Option<usize>,
12}
13
14#[derive(Debug, Clone, thiserror::Error)]
15pub enum ReadParseError {
16 #[error("{0}")]
17 Message(String),
18}
19
20pub fn safe_parse_read_params(input: &Value) -> Result<ReadParams, ReadParseError> {
21 let parsed: ReadParams = serde_json::from_value(input.clone())
22 .map_err(|e| ReadParseError::Message(e.to_string()))?;
23 if parsed.path.is_empty() {
24 return Err(ReadParseError::Message("path must not be empty".to_string()));
25 }
26 if let Some(o) = parsed.offset {
27 if o < 1 {
28 return Err(ReadParseError::Message("offset must be >= 1".to_string()));
29 }
30 }
31 if let Some(l) = parsed.limit {
32 if l < 1 {
33 return Err(ReadParseError::Message("limit must be >= 1".to_string()));
34 }
35 }
36 Ok(parsed)
37}
38
39pub const READ_TOOL_NAME: &str = "read";
40pub const READ_TOOL_DESCRIPTION: &str = "Read a file or directory from the local filesystem.\n\nUsage:\n- The path parameter should be an absolute path. If relative, it resolves against the session working directory.\n- By default, returns up to 2000 lines from the start of the file.\n- The offset parameter is the 1-indexed line number to start from.\n- For later sections, call this tool again with a larger offset.\n- Use the grep tool for content search in large files; glob to locate files by pattern.\n- Contents are returned with each line prefixed by its line number as \"<line>: <content>\".\n- Any line longer than 2000 characters is truncated.\n- Call this tool in parallel when reading multiple files.\n- Avoid tiny repeated slices (under 30 lines). Read a larger window instead.\n- Images and PDFs are returned as file attachments.\n- Binary files are refused; use specialized tools.";