machi_runtime/
lifecycle.rs1use machi_types::{ErrorCode, MachiError, RunId};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum TurnAbortReason {
10 Cancelled,
12 Deadline,
14 MaxSteps,
16 Stationarity,
18 Error {
20 code: ErrorCode,
22 message: String,
24 },
25}
26
27impl TurnAbortReason {
28 #[must_use]
30 pub fn from_error(err: &MachiError) -> Self {
31 match err.code() {
32 ErrorCode::RuntimeCancelled | ErrorCode::LlmCancelled | ErrorCode::HostCancelled => {
33 Self::Cancelled
34 }
35 ErrorCode::RuntimeDeadline => Self::Deadline,
36 ErrorCode::RuntimeMaxSteps => Self::MaxSteps,
37 ErrorCode::RuntimeStationarity => Self::Stationarity,
38 code => Self::Error {
39 code,
40 message: err.message().to_owned(),
41 },
42 }
43 }
44}
45
46pub trait TurnLifecycleContributor: Send + Sync {
48 fn on_turn_start(&self, _run_id: &RunId) {}
50 fn on_turn_done(&self, _run_id: &RunId, _steps: usize) {}
52 fn on_turn_abort(&self, _run_id: &RunId, _reason: &TurnAbortReason) {}
54 fn on_turn_error(&self, _run_id: &RunId, _err: &MachiError) {}
56}
57
58#[derive(Debug, Default, Clone, Copy)]
60pub struct NoopLifecycle;
61
62impl TurnLifecycleContributor for NoopLifecycle {}
63
64#[derive(Default)]
66pub struct LifecycleFanout {
67 contributors: Vec<std::sync::Arc<dyn TurnLifecycleContributor>>,
68}
69
70impl std::fmt::Debug for LifecycleFanout {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 f.debug_struct("LifecycleFanout")
73 .field("contributors", &self.contributors.len())
74 .finish()
75 }
76}
77
78impl LifecycleFanout {
79 #[must_use]
81 pub fn new() -> Self {
82 Self::default()
83 }
84
85 #[must_use]
87 pub fn push(mut self, c: std::sync::Arc<dyn TurnLifecycleContributor>) -> Self {
88 self.contributors.push(c);
89 self
90 }
91}
92
93impl TurnLifecycleContributor for LifecycleFanout {
94 fn on_turn_start(&self, run_id: &RunId) {
95 for c in &self.contributors {
96 c.on_turn_start(run_id);
97 }
98 }
99
100 fn on_turn_done(&self, run_id: &RunId, steps: usize) {
101 for c in &self.contributors {
102 c.on_turn_done(run_id, steps);
103 }
104 }
105
106 fn on_turn_abort(&self, run_id: &RunId, reason: &TurnAbortReason) {
107 for c in &self.contributors {
108 c.on_turn_abort(run_id, reason);
109 }
110 }
111
112 fn on_turn_error(&self, run_id: &RunId, err: &MachiError) {
113 for c in &self.contributors {
114 c.on_turn_error(run_id, err);
115 }
116 }
117}