rs_adk/code_executors/
unsafe_local.rs1use async_trait::async_trait;
10
11use super::base::{CodeExecutor, CodeExecutorError};
12use super::types::{CodeExecutionInput, CodeExecutionResult};
13
14#[derive(Debug, Clone, Default)]
22pub struct UnsafeLocalCodeExecutor {
23 timeout_secs: u64,
25}
26
27impl UnsafeLocalCodeExecutor {
28 pub fn new() -> Self {
30 Self { timeout_secs: 30 }
31 }
32
33 pub fn with_timeout(mut self, timeout_secs: u64) -> Self {
35 self.timeout_secs = timeout_secs;
36 self
37 }
38}
39
40#[async_trait]
41impl CodeExecutor for UnsafeLocalCodeExecutor {
42 async fn execute_code(
43 &self,
44 input: CodeExecutionInput,
45 ) -> Result<CodeExecutionResult, CodeExecutorError> {
46 let output = tokio::time::timeout(
47 std::time::Duration::from_secs(self.timeout_secs),
48 tokio::process::Command::new("python3")
49 .arg("-c")
50 .arg(&input.code)
51 .output(),
52 )
53 .await
54 .map_err(|_| CodeExecutorError::Timeout(self.timeout_secs))?
55 .map_err(|e| CodeExecutorError::ExecutionFailed(format!("Local execution failed: {e}")))?;
56
57 Ok(CodeExecutionResult {
58 stdout: String::from_utf8_lossy(&output.stdout).to_string(),
59 stderr: String::from_utf8_lossy(&output.stderr).to_string(),
60 output_files: vec![],
61 })
62 }
63
64 fn stateful(&self) -> bool {
65 false
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn default_timeout() {
75 let exec = UnsafeLocalCodeExecutor::new();
76 assert_eq!(exec.timeout_secs, 30);
77 }
78
79 #[test]
80 fn custom_timeout() {
81 let exec = UnsafeLocalCodeExecutor::new().with_timeout(60);
82 assert_eq!(exec.timeout_secs, 60);
83 }
84
85 #[test]
86 fn not_stateful() {
87 let exec = UnsafeLocalCodeExecutor::new();
88 assert!(!exec.stateful());
89 }
90}