1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use anyhow::Result;
use async_trait::async_trait;
use serde_json::{Value, json};
use super::{Tool, ToolDefinition};
use crate::approval::RiskLevel;
pub struct WriteTool;
#[async_trait]
impl Tool for WriteTool {
fn definition(&self) -> ToolDefinition {
ToolDefinition {
name: "write".to_string(),
description: "向文件写入内容,若文件不存在则创建".to_string(),
parameters: json!({
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "要写入的文件路径"
},
"content": {
"type": "string",
"description": "要写入的内容"
}
},
"required": ["path", "content"]
}),
}
}
async fn execute(&self, params: Value) -> Result<String> {
let path = params["path"]
.as_str()
.ok_or_else(|| anyhow::anyhow!("missing 'path'"))?;
let content = params["content"]
.as_str()
.ok_or_else(|| anyhow::anyhow!("missing 'content'"))?;
// Create spinner immediately at the start to fill the gap before actual operation
// let mut spinner = ToolSpinner::new(&format!("preparing write to {}", path));
// Create parent directories if needed
if let Some(parent) = std::path::Path::new(path).parent() {
tokio::fs::create_dir_all(parent).await?;
}
let total_bytes = content.len();
// Update spinner message for the actual write operation
// spinner.set_message(&format!("writing to {}", path));
// Write the file
tokio::fs::write(path, content).await?;
// spinner.finish_success(&format!("wrote {} bytes", total_bytes));
Ok(format!(
"Successfully wrote {} bytes to {}",
total_bytes, path
))
}
fn risk_level(&self) -> RiskLevel {
RiskLevel::Mutating
}
}