1use async_trait::async_trait;
2use serde_json::{json, Value};
3use tokio::fs;
4
5use crate::types::{AgentTool, AgentToolResult};
6
7pub struct WriteTool;
8
9#[async_trait]
10impl AgentTool for WriteTool {
11 fn name(&self) -> &str {
12 "write"
13 }
14 fn requires_permission(&self) -> bool {
15 true
16 }
17 fn description(&self) -> &str {
18 "Write the given content to the path, replacing any existing file. Creates parent directories as needed."
19 }
20 fn parameters(&self) -> Value {
21 json!({
22 "type": "object",
23 "properties": {
24 "path": {"type": "string"},
25 "content": {"type": "string"}
26 },
27 "required": ["path", "content"]
28 })
29 }
30 async fn execute(&self, _id: &str, args: Value) -> Result<AgentToolResult, String> {
31 let path = args
32 .get("path")
33 .and_then(|v| v.as_str())
34 .ok_or("missing 'path'")?;
35 let content = args
36 .get("content")
37 .and_then(|v| v.as_str())
38 .ok_or("missing 'content'")?;
39 if let Some(parent) = std::path::Path::new(path).parent() {
40 if !parent.as_os_str().is_empty() {
41 fs::create_dir_all(parent).await.ok();
42 }
43 }
44 fs::write(path, content)
45 .await
46 .map_err(|e| format!("write {path}: {e}"))?;
47 Ok(AgentToolResult::text(format!(
48 "wrote {} bytes to {}",
49 content.len(),
50 path
51 )))
52 }
53}