mofa_kernel/agent/types/
event.rs1use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct GlobalEvent {
34 pub event_id: String,
36
37 pub event_type: String,
41
42 pub source: String,
44
45 pub timestamp: u64,
47
48 pub data: serde_json::Value,
50
51 pub metadata: HashMap<String, String>,
53}
54
55impl GlobalEvent {
56 pub fn new(event_type: impl Into<String>, source: impl Into<String>) -> Self {
58 let timestamp = std::time::SystemTime::now()
59 .duration_since(std::time::UNIX_EPOCH)
60 .unwrap()
61 .as_millis() as u64;
62
63 Self {
64 event_id: uuid::Uuid::new_v4().to_string(),
65 event_type: event_type.into(),
66 source: source.into(),
67 timestamp,
68 data: serde_json::Value::Null,
69 metadata: HashMap::new(),
70 }
71 }
72
73 pub fn with_data(mut self, data: impl Into<serde_json::Value>) -> Self {
75 self.data = data.into();
76 self
77 }
78
79 pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
81 self.metadata.insert(key.into(), value.into());
82 self
83 }
84
85 pub fn get_data<T: for<'de> Deserialize<'de>>(&self) -> Option<T> {
87 serde_json::from_value(self.data.clone()).ok()
88 }
89
90 pub fn is_type(&self, event_type: &str) -> bool {
92 self.event_type == event_type
93 }
94
95 pub fn is_from(&self, source: &str) -> bool {
97 self.source == source
98 }
99
100 pub fn matches_prefix(&self, prefix: &str) -> bool {
102 self.event_type.starts_with(prefix)
103 }
104}
105
106pub struct EventBuilder {
114 event: GlobalEvent,
115}
116
117impl EventBuilder {
118 pub fn new(event_type: impl Into<String>, source: impl Into<String>) -> Self {
120 Self {
121 event: GlobalEvent::new(event_type, source),
122 }
123 }
124
125 pub fn id(mut self, id: impl Into<String>) -> Self {
127 self.event.event_id = id.into();
128 self
129 }
130
131 pub fn data(mut self, data: impl Into<serde_json::Value>) -> Self {
133 self.event.data = data.into();
134 self
135 }
136
137 pub fn metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
139 self.event.metadata.insert(key.into(), value.into());
140 self
141 }
142
143 pub fn timestamp(mut self, timestamp: u64) -> Self {
145 self.event.timestamp = timestamp;
146 self
147 }
148
149 pub fn build(self) -> GlobalEvent {
151 self.event
152 }
153}
154
155pub mod lifecycle {
161 pub const CREATED: &str = "lifecycle:created";
162 pub const INITIALIZED: &str = "lifecycle:initialized";
163 pub const STARTED: &str = "lifecycle:started";
164 pub const STOPPED: &str = "lifecycle:stopped";
165 pub const SHUTDOWN: &str = "lifecycle:shutdown";
166 pub const DESTROYED: &str = "lifecycle:destroyed";
167}
168
169pub mod execution {
171 pub const STARTED: &str = "execution:started";
172 pub const COMPLETED: &str = "execution:completed";
173 pub const FAILED: &str = "execution:failed";
174 pub const INTERRUPTED: &str = "execution:interrupted";
175 pub const TIMEOUT: &str = "execution:timeout";
176}
177
178pub mod message {
180 pub const SENT: &str = "message:sent";
181 pub const RECEIVED: &str = "message:received";
182 pub const DELIVERED: &str = "message:delivered";
183 pub const FAILED: &str = "message:failed";
184}
185
186pub mod plugin {
188 pub const LOADED: &str = "plugin:loaded";
189 pub const UNLOADED: &str = "plugin:unloaded";
190 pub const ERROR: &str = "plugin:error";
191}
192
193pub mod state {
195 pub const CHANGED: &str = "state:changed";
196 pub const ERROR: &str = "state:error";
197 pub const PAUSED: &str = "state:paused";
198 pub const RESUMED: &str = "state:resumed";
199}
200
201pub fn lifecycle_event(event_type: &str, source: &str) -> GlobalEvent {
207 GlobalEvent::new(event_type, source)
208}
209
210pub fn execution_event(event_type: &str, source: &str, data: serde_json::Value) -> GlobalEvent {
212 GlobalEvent::new(event_type, source).with_data(data)
213}
214
215pub fn state_changed_event(source: &str, old_state: &str, new_state: &str) -> GlobalEvent {
217 GlobalEvent::new(state::CHANGED, source).with_data(serde_json::json!({
218 "old_state": old_state,
219 "new_state": new_state
220 }))
221}
222
223pub fn error_event(source: &str, error: &str) -> GlobalEvent {
225 GlobalEvent::new("error", source).with_data(serde_json::json!({
226 "error": error
227 }))
228}
229
230#[cfg(test)]
235mod tests {
236 use super::*;
237
238 #[test]
239 fn test_event_creation() {
240 let event = GlobalEvent::new("test:event", "agent1");
241 assert_eq!(event.event_type, "test:event");
242 assert_eq!(event.source, "agent1");
243 assert!(!event.event_id.is_empty());
244 }
245
246 #[test]
247 fn test_event_with_data() {
248 let data = serde_json::json!({ "key": "value" });
249 let event = GlobalEvent::new("test:event", "agent1").with_data(data.clone());
250
251 assert_eq!(event.data, data);
252 }
253
254 #[test]
255 fn test_event_builder() {
256 let event = EventBuilder::new("test:event", "agent1")
257 .id("custom-id")
258 .data(serde_json::json!({ "test": true }))
259 .metadata("meta1", "value1")
260 .timestamp(12345)
261 .build();
262
263 assert_eq!(event.event_id, "custom-id");
264 assert_eq!(event.timestamp, 12345);
265 assert_eq!(event.metadata.get("meta1"), Some(&"value1".to_string()));
266 }
267
268 #[test]
269 fn test_event_type_checks() {
270 let event = GlobalEvent::new("lifecycle:initialized", "agent1");
271
272 assert!(event.is_type("lifecycle:initialized"));
273 assert!(event.is_from("agent1"));
274 assert!(event.matches_prefix("lifecycle:"));
275 assert!(!event.matches_prefix("execution:"));
276 }
277
278 #[test]
279 fn test_helper_functions() {
280 let event = state_changed_event("agent1", "ready", "executing");
281
282 assert!(event.is_type(state::CHANGED));
283 assert_eq!(event.source, "agent1");
284
285 let data: serde_json::Value = event.data;
286 assert_eq!(data["old_state"], "ready");
287 assert_eq!(data["new_state"], "executing");
288 }
289}