elizaos_plugin_code/actions/
search_files.rs1use async_trait::async_trait;
2use serde_json::Value;
3
4use crate::service::CoderService;
5use crate::{Action, ActionExample, ActionResult};
6
7pub struct SearchFilesAction;
8
9#[async_trait]
10impl Action for SearchFilesAction {
11 fn name(&self) -> &str {
12 "SEARCH_FILES"
13 }
14
15 fn similes(&self) -> Vec<&str> {
16 vec!["GREP", "RG", "FIND_IN_FILES", "SEARCH"]
17 }
18
19 fn description(&self) -> &str {
20 "Search for text across files under a directory."
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 pattern = state
43 .get("pattern")
44 .and_then(|v| v.as_str())
45 .unwrap_or("")
46 .to_string();
47 let dirpath = state
48 .get("path")
49 .and_then(|v| v.as_str())
50 .unwrap_or(".")
51 .to_string();
52 let max_matches = state
53 .get("max_matches")
54 .and_then(|v| v.as_u64())
55 .unwrap_or(50) as usize;
56 if pattern.trim().is_empty() {
57 return ActionResult {
58 success: false,
59 text: "Missing pattern.".to_string(),
60 data: None,
61 error: Some("missing_pattern".to_string()),
62 };
63 }
64
65 let conv = message
66 .get("room_id")
67 .and_then(|v| v.as_str())
68 .or_else(|| message.get("agent_id").and_then(|v| v.as_str()))
69 .unwrap_or("default");
70
71 match svc
72 .search_files(conv, &pattern, &dirpath, max_matches)
73 .await
74 {
75 Ok(matches) => {
76 let text = if matches.is_empty() {
77 format!("No matches for \"{}\".", pattern)
78 } else {
79 matches
80 .iter()
81 .map(|(f, l, c)| format!("{}:L{}: {}", f, l, c))
82 .collect::<Vec<String>>()
83 .join("\n")
84 };
85 ActionResult {
86 success: true,
87 text,
88 data: None,
89 error: None,
90 }
91 }
92 Err(err) => ActionResult {
93 success: false,
94 text: err,
95 data: None,
96 error: Some("search_failed".to_string()),
97 },
98 }
99 }
100
101 fn examples(&self) -> Vec<ActionExample> {
102 vec![ActionExample {
103 user_message: "search files".to_string(),
104 agent_response: "Searching…".to_string(),
105 }]
106 }
107}