autoagents_core/
environment.rs1use crate::error::Error;
2use crate::protocol::{Event, RuntimeID};
3use crate::runtime::manager::RuntimeManager;
4use crate::runtime::{Runtime, RuntimeError};
5use crate::utils::BoxEventStream;
6use std::path::PathBuf;
7use std::sync::Arc;
8use tokio::task::JoinHandle;
9
10#[derive(Debug, thiserror::Error)]
12pub enum EnvironmentError {
13 #[error("Runtime not found: {0}")]
14 RuntimeNotFound(RuntimeID),
15
16 #[error("Runtime error: {0}")]
17 RuntimeError(#[from] RuntimeError),
18
19 #[error("Error when consuming receiver")]
20 EventError,
21}
22
23#[derive(Clone)]
25pub struct EnvironmentConfig {
26 pub working_dir: PathBuf,
27}
28
29impl Default for EnvironmentConfig {
30 fn default() -> Self {
31 Self {
32 working_dir: std::env::current_dir().unwrap_or_default(),
33 }
34 }
35}
36
37pub struct Environment {
41 config: EnvironmentConfig,
42 runtime_manager: Arc<RuntimeManager>,
43 default_runtime: Option<RuntimeID>,
44 handle: Option<JoinHandle<Result<(), RuntimeError>>>,
45}
46
47impl Environment {
48 pub fn new(config: Option<EnvironmentConfig>) -> Self {
50 let config = config.unwrap_or_default();
51 let runtime_manager = Arc::new(RuntimeManager::new());
52
53 Self {
54 config,
55 runtime_manager,
56 default_runtime: None,
57 handle: None,
58 }
59 }
60
61 pub async fn register_runtime(&mut self, runtime: Arc<dyn Runtime>) -> Result<(), Error> {
64 self.runtime_manager
65 .register_runtime(runtime.clone())
66 .await?;
67 if self.default_runtime.is_none() {
68 self.default_runtime = Some(runtime.id());
69 }
70 Ok(())
71 }
72
73 pub fn config(&self) -> &EnvironmentConfig {
75 &self.config
76 }
77
78 pub async fn get_runtime(&self, runtime_id: &RuntimeID) -> Option<Arc<dyn Runtime>> {
80 self.runtime_manager.get_runtime(runtime_id).await
81 }
82
83 pub async fn get_runtime_or_default(
85 &self,
86 runtime_id: Option<RuntimeID>,
87 ) -> Result<Arc<dyn Runtime>, Error> {
88 let rid = runtime_id.unwrap_or(self.default_runtime.unwrap());
89 self.get_runtime(&rid)
90 .await
91 .ok_or_else(|| EnvironmentError::RuntimeNotFound(rid).into())
92 }
93
94 pub fn run(&mut self) -> JoinHandle<Result<(), RuntimeError>> {
97 let manager = self.runtime_manager.clone();
98 let handle = tokio::spawn(async move { manager.run().await });
100 handle
101 }
102
103 pub async fn run_background(&mut self) -> Result<(), RuntimeError> {
106 let manager = self.runtime_manager.clone();
107 manager.run_background().await
109 }
110
111 pub async fn take_event_receiver(
114 &mut self,
115 runtime_id: Option<RuntimeID>,
116 ) -> Result<BoxEventStream<Event>, EnvironmentError> {
117 if let Ok(runtime) = self.get_runtime_or_default(runtime_id).await {
118 runtime
119 .take_event_receiver()
120 .await
121 .ok_or_else(|| EnvironmentError::EventError)
122 } else {
123 Err(EnvironmentError::RuntimeNotFound(runtime_id.unwrap()))
124 }
125 }
126
127 pub async fn shutdown(&mut self) {
129 let _ = self.runtime_manager.stop().await;
130
131 if let Some(handle) = self.handle.take() {
132 let _ = handle.await;
133 }
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use crate::runtime::SingleThreadedRuntime;
140
141 use super::*;
142 use uuid::Uuid;
143
144 #[test]
145 fn test_environment_config_default() {
146 let config = EnvironmentConfig::default();
147 assert_eq!(
148 config.working_dir,
149 std::env::current_dir().unwrap_or_default()
150 );
151 }
152
153 #[test]
154 fn test_environment_config_custom() {
155 let config = EnvironmentConfig {
156 working_dir: std::path::PathBuf::from("/tmp"),
157 };
158 assert_eq!(config.working_dir, std::path::PathBuf::from("/tmp"));
159 }
160
161 #[tokio::test]
162 async fn test_environment_get_runtime() {
163 let mut env = Environment::new(None);
164 let runtime = SingleThreadedRuntime::new(None);
165 let runtime_id = runtime.id;
166 env.register_runtime(runtime).await.unwrap();
167
168 let runtime = env.get_runtime(&runtime_id).await;
170
171 assert!(runtime.is_some());
172
173 let non_existent_id = Uuid::new_v4();
175 let runtime = env.get_runtime(&non_existent_id).await;
176 assert!(runtime.is_none());
177 }
178
179 #[tokio::test]
180 async fn test_environment_take_event_receiver() {
181 let mut env = Environment::new(None);
182 let runtime = SingleThreadedRuntime::new(None);
183 let _ = runtime.id;
184 env.register_runtime(runtime).await.unwrap();
185 let receiver = env.take_event_receiver(None).await;
186 assert!(receiver.is_ok());
187
188 let receiver2 = env.take_event_receiver(None).await;
190 assert!(receiver2.is_err());
191 }
192
193 #[tokio::test]
194 async fn test_environment_shutdown() {
195 let mut env = Environment::new(None);
196 env.shutdown().await;
197 }
199
200 #[tokio::test]
201 async fn test_environment_error_runtime_not_found() {
202 let mut env = Environment::new(None);
203 let runtime = SingleThreadedRuntime::new(None);
204 let _ = runtime.id;
205 env.register_runtime(runtime).await.unwrap();
206 let non_existent_id = Uuid::new_v4();
207
208 let result = env.get_runtime_or_default(Some(non_existent_id)).await;
209 assert!(result.is_err());
210
211 assert!(result.is_err());
212 assert!(result.is_err());
214 }
215
216 #[test]
217 fn test_environment_error_display() {
218 let runtime_id = Uuid::new_v4();
219 let error = EnvironmentError::RuntimeNotFound(runtime_id);
220 assert!(error.to_string().contains("Runtime not found"));
221 assert!(error.to_string().contains(&runtime_id.to_string()));
222 }
223}