1use serde::{Deserialize, Serialize};
2use uuid::Uuid;
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
5pub struct AgentEvent {
6 pub id: Uuid,
7 pub agent_id: String,
8 pub thread_id: Option<String>,
9 pub run_id: Option<String>,
10 pub parent_event_id: Option<Uuid>,
11 pub event_type: EventType,
12 pub payload: serde_json::Value,
13 pub trace_id: Option<String>,
15 pub span_id: Option<String>,
16 pub model: Option<String>,
17 pub tokens_input: Option<i64>,
18 pub tokens_output: Option<i64>,
19 pub latency_ms: Option<i64>,
20 pub cost_usd: Option<f64>,
21 pub timestamp: String,
23 pub logical_clock: i64,
24 pub content_hash: Vec<u8>,
26 pub prev_hash: Option<Vec<u8>>,
27 pub embedding: Option<Vec<f32>>,
29}
30
31impl AgentEvent {
32 pub fn new(
34 agent_id: String,
35 event_type: EventType,
36 payload: serde_json::Value,
37 timestamp: String,
38 content_hash: Vec<u8>,
39 ) -> Self {
40 Self {
41 id: Uuid::now_v7(),
42 agent_id,
43 thread_id: None,
44 run_id: None,
45 parent_event_id: None,
46 event_type,
47 payload,
48 trace_id: None,
49 span_id: None,
50 model: None,
51 tokens_input: None,
52 tokens_output: None,
53 latency_ms: None,
54 cost_usd: None,
55 timestamp,
56 logical_clock: 0,
57 content_hash,
58 prev_hash: None,
59 embedding: None,
60 }
61 }
62
63 #[allow(clippy::too_many_arguments)]
66 pub fn from_parts(
67 id: Uuid,
68 agent_id: String,
69 thread_id: Option<String>,
70 run_id: Option<String>,
71 parent_event_id: Option<Uuid>,
72 event_type: EventType,
73 payload: serde_json::Value,
74 trace_id: Option<String>,
75 span_id: Option<String>,
76 model: Option<String>,
77 tokens_input: Option<i64>,
78 tokens_output: Option<i64>,
79 latency_ms: Option<i64>,
80 cost_usd: Option<f64>,
81 timestamp: String,
82 logical_clock: i64,
83 content_hash: Vec<u8>,
84 prev_hash: Option<Vec<u8>>,
85 embedding: Option<Vec<f32>>,
86 ) -> Self {
87 Self {
88 id,
89 agent_id,
90 thread_id,
91 run_id,
92 parent_event_id,
93 event_type,
94 payload,
95 trace_id,
96 span_id,
97 model,
98 tokens_input,
99 tokens_output,
100 latency_ms,
101 cost_usd,
102 timestamp,
103 logical_clock,
104 content_hash,
105 prev_hash,
106 embedding,
107 }
108 }
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
112#[serde(rename_all = "snake_case")]
113pub enum EventType {
114 MemoryWrite,
115 MemoryRead,
116 MemoryDelete,
117 MemoryShare,
118 MemoryExpired,
119 MemoryRedact,
120 Checkpoint,
121 Branch,
122 Merge,
123 UserMessage,
124 AssistantMessage,
125 ToolCall,
126 ToolResult,
127 Error,
128 RetrievalQuery,
129 RetrievalResult,
130 Decision,
131 ReflectionCompleted,
135 DreamReportIngested,
138}
139
140impl std::fmt::Display for EventType {
141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142 match self {
143 EventType::MemoryWrite => write!(f, "memory_write"),
144 EventType::MemoryRead => write!(f, "memory_read"),
145 EventType::MemoryDelete => write!(f, "memory_delete"),
146 EventType::MemoryShare => write!(f, "memory_share"),
147 EventType::MemoryExpired => write!(f, "memory_expired"),
148 EventType::MemoryRedact => write!(f, "memory_redact"),
149 EventType::Checkpoint => write!(f, "checkpoint"),
150 EventType::Branch => write!(f, "branch"),
151 EventType::Merge => write!(f, "merge"),
152 EventType::UserMessage => write!(f, "user_message"),
153 EventType::AssistantMessage => write!(f, "assistant_message"),
154 EventType::ToolCall => write!(f, "tool_call"),
155 EventType::ToolResult => write!(f, "tool_result"),
156 EventType::Error => write!(f, "error"),
157 EventType::RetrievalQuery => write!(f, "retrieval_query"),
158 EventType::RetrievalResult => write!(f, "retrieval_result"),
159 EventType::Decision => write!(f, "decision"),
160 EventType::ReflectionCompleted => write!(f, "reflection_completed"),
161 EventType::DreamReportIngested => write!(f, "dream_report_ingested"),
162 }
163 }
164}
165
166impl std::str::FromStr for EventType {
167 type Err = crate::error::Error;
168 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
169 match s {
170 "memory_write" => Ok(EventType::MemoryWrite),
171 "memory_read" => Ok(EventType::MemoryRead),
172 "memory_delete" => Ok(EventType::MemoryDelete),
173 "memory_share" => Ok(EventType::MemoryShare),
174 "memory_expired" => Ok(EventType::MemoryExpired),
175 "memory_redact" => Ok(EventType::MemoryRedact),
176 "checkpoint" => Ok(EventType::Checkpoint),
177 "branch" => Ok(EventType::Branch),
178 "merge" => Ok(EventType::Merge),
179 "user_message" => Ok(EventType::UserMessage),
180 "assistant_message" => Ok(EventType::AssistantMessage),
181 "tool_call" => Ok(EventType::ToolCall),
182 "tool_result" => Ok(EventType::ToolResult),
183 "error" => Ok(EventType::Error),
184 "retrieval_query" => Ok(EventType::RetrievalQuery),
185 "retrieval_result" => Ok(EventType::RetrievalResult),
186 "decision" => Ok(EventType::Decision),
187 "reflection_completed" => Ok(EventType::ReflectionCompleted),
188 "dream_report_ingested" => Ok(EventType::DreamReportIngested),
189 _ => Err(crate::error::Error::Validation(format!(
190 "invalid event type: {s}"
191 ))),
192 }
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn test_agent_event_serde() {
202 let event = AgentEvent {
203 id: Uuid::now_v7(),
204 agent_id: "agent-1".to_string(),
205 thread_id: Some("thread-1".to_string()),
206 run_id: None,
207 parent_event_id: None,
208 event_type: EventType::MemoryWrite,
209 payload: serde_json::json!({"memory_id": "abc"}),
210 trace_id: None,
211 span_id: None,
212 model: None,
213 tokens_input: None,
214 tokens_output: None,
215 latency_ms: None,
216 cost_usd: None,
217 timestamp: "2025-01-01T00:00:00Z".to_string(),
218 logical_clock: 1,
219 content_hash: vec![1, 2, 3],
220 prev_hash: None,
221 embedding: None,
222 };
223 let json = serde_json::to_string(&event).unwrap();
224 let deserialized: AgentEvent = serde_json::from_str(&json).unwrap();
225 assert_eq!(event, deserialized);
226 }
227
228 #[test]
229 fn test_event_type_display_fromstr() {
230 assert_eq!(EventType::MemoryWrite.to_string(), "memory_write");
231 assert_eq!(
232 "memory_read".parse::<EventType>().unwrap(),
233 EventType::MemoryRead
234 );
235 assert_eq!(
236 "checkpoint".parse::<EventType>().unwrap(),
237 EventType::Checkpoint
238 );
239 assert_eq!("error".parse::<EventType>().unwrap(), EventType::Error);
240 assert!("invalid".parse::<EventType>().is_err());
241 }
242}