Skip to main content

elizaos_plugin_code/actions/
write_file.rs

1use 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}