use crate::error::AgentError;
use crate::tool::{Tool, ToolResult};
pub struct EditFileTool;
impl Tool for EditFileTool {
fn name(&self) -> &str {
"edit"
}
fn description(&self) -> &str {
"Edit a file by searching for an exact string and replacing it. \
The 'old' string must match exactly (including whitespace). \
Only the first occurrence is replaced unless 'all' is set to true."
}
fn parameters_schema(&self) -> serde_json::Value {
serde_json::json!({
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Path to the file to edit"
},
"old": {
"type": "string",
"description": "The exact text to search for"
},
"new": {
"type": "string",
"description": "The replacement text"
},
"all": {
"type": "boolean",
"description": "If true, replace all occurrences. Default: false."
}
},
"required": ["path", "old", "new"]
})
}
fn execute(&self, args: &serde_json::Value) -> Result<ToolResult, AgentError> {
let path = args["path"].as_str().ok_or_else(|| AgentError::Tool {
tool: "edit".to_string(),
message: "Missing 'path' argument".to_string(),
})?;
let old = args["old"].as_str().ok_or_else(|| AgentError::Tool {
tool: "edit".to_string(),
message: "Missing 'old' argument".to_string(),
})?;
let new = args["new"].as_str().ok_or_else(|| AgentError::Tool {
tool: "edit".to_string(),
message: "Missing 'new' argument".to_string(),
})?;
let replace_all = args["all"].as_bool().unwrap_or(false);
let content = match std::fs::read_to_string(path) {
Ok(c) => c,
Err(e) => {
return Ok(ToolResult::err(format!(
"Failed to read '{}': {}",
path, e
)))
}
};
if !content.contains(old) {
return Ok(ToolResult::err(format!(
"Search string not found in '{}'. Make sure the 'old' text matches exactly (including whitespace and newlines).",
path
)));
}
let (new_content, count) = if replace_all {
let count = content.matches(old).count();
(content.replace(old, new), count)
} else {
(content.replacen(old, new, 1), 1)
};
match std::fs::write(path, &new_content) {
Ok(_) => Ok(ToolResult::ok(format!(
"Replaced {} occurrence(s) in '{}'",
count, path
))),
Err(e) => Ok(ToolResult::err(format!(
"Failed to write '{}': {}",
path, e
))),
}
}
fn requires_permission(&self) -> bool {
true
}
}