atomr_agents_workflow/
event.rs1use std::sync::Arc;
2
3use atomr_agents_core::{Result, Value, WorkflowId};
4use parking_lot::RwLock;
5use serde::{Deserialize, Serialize};
6
7use crate::dag::StepId;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
12#[serde(tag = "kind", rename_all = "snake_case")]
13pub enum WorkflowEvent {
14 StepStarted {
15 step_id: StepId,
16 idempotency_key: String,
17 },
18 StepCompleted {
19 step_id: StepId,
20 output: Value,
21 },
22 StepFailed {
23 step_id: StepId,
24 error: String,
25 },
26 BranchTaken {
27 step_id: StepId,
28 chosen: StepId,
29 },
30 HumanApproved {
31 step_id: StepId,
32 approver: String,
33 },
34 Terminated {
35 ok: bool,
36 },
37}
38
39#[async_trait::async_trait]
43pub trait Journal: Send + Sync + 'static {
44 async fn append(&self, workflow_id: &WorkflowId, event: WorkflowEvent) -> Result<()>;
45 async fn replay(&self, workflow_id: &WorkflowId) -> Result<Vec<WorkflowEvent>>;
46}
47
48#[derive(Default, Clone)]
49pub struct InMemoryJournal {
50 inner: Arc<RwLock<Vec<(WorkflowId, WorkflowEvent)>>>,
51}
52
53impl InMemoryJournal {
54 pub fn new() -> Self {
55 Self::default()
56 }
57}
58
59#[async_trait::async_trait]
60impl Journal for InMemoryJournal {
61 async fn append(&self, workflow_id: &WorkflowId, event: WorkflowEvent) -> Result<()> {
62 self.inner.write().push((workflow_id.clone(), event));
63 Ok(())
64 }
65
66 async fn replay(&self, workflow_id: &WorkflowId) -> Result<Vec<WorkflowEvent>> {
67 Ok(self
68 .inner
69 .read()
70 .iter()
71 .filter(|(id, _)| id.as_str() == workflow_id.as_str())
72 .map(|(_, e)| e.clone())
73 .collect())
74 }
75}