elizaos_plugin_code/actions/
write_file.rs1use async_trait::async_trait;
2use serde_json::Value;
3
4use crate::service::CoderService;
5use crate::{Action, ActionExample, ActionResult};
6
7pub struct WriteFileAction;
8
9#[async_trait]
10impl Action for WriteFileAction {
11 fn name(&self) -> &str {
12 "WRITE_FILE"
13 }
14
15 fn similes(&self) -> Vec<&str> {
16 vec!["CREATE_FILE", "SAVE_FILE", "OUTPUT_FILE"]
17 }
18
19 fn description(&self) -> &str {
20 "Create or overwrite a file with given content."
21 }
22
23 async fn validate(&self, _message: &Value, _state: &Value) -> bool {
24 true
25 }
26
27 async fn handler(
28 &self,
29 message: &Value,
30 state: &Value,
31 service: Option<&mut CoderService>,
32 ) -> ActionResult {
33 let Some(svc) = service else {
34 return ActionResult {
35 success: false,
36 text: "Coder service is not available.".to_string(),
37 data: None,
38 error: Some("missing_service".to_string()),
39 };
40 };
41
42 let filepath = state.get("filepath").and_then(|v| v.as_str()).unwrap_or("");
43 let content = state.get("content").and_then(|v| v.as_str()).unwrap_or("");
44 if filepath.trim().is_empty() {
45 return ActionResult {
46 success: false,
47 text: "Missing filepath.".to_string(),
48 data: None,
49 error: Some("missing_filepath".to_string()),
50 };
51 }
52
53 let conv = message
54 .get("room_id")
55 .and_then(|v| v.as_str())
56 .or_else(|| message.get("agent_id").and_then(|v| v.as_str()))
57 .unwrap_or("default");
58
59 match svc.write_file(conv, filepath, content).await {
60 Ok(()) => ActionResult {
61 success: true,
62 text: format!("Wrote {} ({} chars)", filepath, content.len()),
63 data: None,
64 error: None,
65 },
66 Err(err) => ActionResult {
67 success: false,
68 text: err,
69 data: None,
70 error: Some("write_failed".to_string()),
71 },
72 }
73 }
74
75 fn examples(&self) -> Vec<ActionExample> {
76 vec![ActionExample {
77 user_message: "write README.md".to_string(),
78 agent_response: "Writing fileā¦".to_string(),
79 }]
80 }
81}