1use crate::{EventId, StateError};
2use chrono::Utc;
3use serde::{Deserialize, Serialize};
4use serde_json::Value as JsonValue;
5
6pub const CURRENT_EVENT_SCHEMA_VERSION: u32 = 1;
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9pub struct ActorRef {
10 pub kind: String,
11 pub id: String,
12}
13
14impl ActorRef {
15 pub fn new(kind: impl Into<String>, id: impl Into<String>) -> Self {
16 Self {
17 kind: kind.into(),
18 id: id.into(),
19 }
20 }
21
22 pub fn agent(id: impl Into<String>) -> Self {
23 Self::new("agent", id)
24 }
25
26 pub fn user(id: impl Into<String>) -> Self {
27 Self::new("user", id)
28 }
29
30 pub fn system(id: impl Into<String>) -> Self {
31 Self::new("system", id)
32 }
33
34 pub fn tool(id: impl Into<String>) -> Self {
35 Self::new("tool", id)
36 }
37}
38
39#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
40pub struct Event {
41 pub id: EventId,
42 pub schema_version: u32,
43 pub ts_ms: i64,
44 pub actor: ActorRef,
45 pub kind: String,
46 pub payload: JsonValue,
47 pub causation_id: Option<EventId>,
48 pub correlation_id: Option<String>,
49}
50
51impl Event {
52 pub fn new(actor: ActorRef, kind: impl Into<String>, payload: JsonValue) -> Self {
53 Self {
54 id: EventId::generate(),
55 schema_version: CURRENT_EVENT_SCHEMA_VERSION,
56 ts_ms: now_ms(),
57 actor,
58 kind: kind.into(),
59 payload,
60 causation_id: None,
61 correlation_id: None,
62 }
63 }
64
65 pub fn with_causation(mut self, event_id: EventId) -> Self {
66 self.causation_id = Some(event_id);
67 self
68 }
69
70 pub fn with_correlation(mut self, correlation_id: impl Into<String>) -> Self {
71 self.correlation_id = Some(correlation_id.into());
72 self
73 }
74
75 pub fn payload_as<T>(&self) -> Result<T, StateError>
76 where
77 T: for<'de> Deserialize<'de>,
78 {
79 serde_json::from_value(self.payload.clone()).map_err(|source| {
80 StateError::InvalidEventPayload {
81 kind: self.kind.clone(),
82 source,
83 }
84 })
85 }
86}
87
88pub fn now_ms() -> i64 {
89 Utc::now().timestamp_millis()
90}