Skip to main content

atomr_agents_workflow/
event.rs

1use 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/// Events appended to the workflow's journal. State is rebuilt by
10/// folding these in order.
11#[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/// Pluggable journal abstraction. Phase 6 ships the in-memory
40/// implementation; production setups plug in a journal backed by
41/// `atomr-persistence`.
42#[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}