enact_core/kernel/
execution_state.rs1use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
13#[serde(rename_all = "PascalCase")]
14pub enum ExecutionState {
15 #[default]
17 Created,
18 Planning,
20 Running,
22 Paused,
24 Waiting(WaitReason),
26 Completed,
28 Failed,
30 Cancelled,
32}
33
34impl ExecutionState {
35 pub fn is_terminal(&self) -> bool {
37 matches!(self, Self::Completed | Self::Failed | Self::Cancelled)
38 }
39
40 pub fn can_resume(&self) -> bool {
42 matches!(self, Self::Paused | Self::Waiting(_))
43 }
44
45 pub fn is_active(&self) -> bool {
47 matches!(self, Self::Running | Self::Waiting(_))
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
57#[serde(rename_all = "snake_case")]
58pub enum WaitReason {
59 Approval,
61 UserInput,
63 RateLimit,
65 External,
67 Checkpoint,
69 CostThreshold,
71 MemoryPressure,
73 SubAgent,
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
79#[serde(rename_all = "PascalCase")]
80pub enum StepState {
81 #[default]
83 Pending,
84 Running,
86 Completed,
88 Failed,
90 Skipped,
92}
93
94impl StepState {
95 pub fn is_terminal(&self) -> bool {
97 matches!(self, Self::Completed | Self::Failed | Self::Skipped)
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn test_execution_state_terminal() {
107 assert!(!ExecutionState::Created.is_terminal());
108 assert!(!ExecutionState::Planning.is_terminal());
109 assert!(!ExecutionState::Running.is_terminal());
110 assert!(!ExecutionState::Paused.is_terminal());
111 assert!(ExecutionState::Completed.is_terminal());
112 assert!(ExecutionState::Failed.is_terminal());
113 assert!(ExecutionState::Cancelled.is_terminal());
114 }
115
116 #[test]
117 fn test_execution_state_can_resume() {
118 assert!(!ExecutionState::Created.can_resume());
119 assert!(!ExecutionState::Planning.can_resume());
120 assert!(!ExecutionState::Running.can_resume());
121 assert!(ExecutionState::Paused.can_resume());
122 assert!(ExecutionState::Waiting(WaitReason::Approval).can_resume());
123 }
124
125 #[test]
126 fn test_execution_state_is_active() {
127 assert!(!ExecutionState::Created.is_active());
128 assert!(!ExecutionState::Planning.is_active());
129 assert!(ExecutionState::Running.is_active());
130 assert!(!ExecutionState::Paused.is_active());
131 assert!(ExecutionState::Waiting(WaitReason::Approval).is_active());
132 assert!(ExecutionState::Waiting(WaitReason::External).is_active());
133 assert!(!ExecutionState::Completed.is_active());
134 assert!(!ExecutionState::Failed.is_active());
135 assert!(!ExecutionState::Cancelled.is_active());
136 }
137
138 #[test]
139 fn test_execution_state_serde() {
140 let states = vec![
142 ExecutionState::Created,
143 ExecutionState::Planning,
144 ExecutionState::Running,
145 ExecutionState::Paused,
146 ExecutionState::Waiting(WaitReason::Approval),
147 ExecutionState::Waiting(WaitReason::UserInput),
148 ExecutionState::Waiting(WaitReason::RateLimit),
149 ExecutionState::Waiting(WaitReason::External),
150 ExecutionState::Waiting(WaitReason::Checkpoint),
151 ExecutionState::Waiting(WaitReason::CostThreshold),
152 ExecutionState::Waiting(WaitReason::MemoryPressure),
153 ExecutionState::Waiting(WaitReason::SubAgent),
154 ExecutionState::Completed,
155 ExecutionState::Failed,
156 ExecutionState::Cancelled,
157 ];
158 for state in states {
159 let json = serde_json::to_string(&state).unwrap();
160 let parsed: ExecutionState = serde_json::from_str(&json).unwrap();
161 assert_eq!(state, parsed);
162 }
163 }
164
165 #[test]
166 fn test_step_state_terminal() {
167 assert!(!StepState::Pending.is_terminal());
168 assert!(!StepState::Running.is_terminal());
169 assert!(StepState::Completed.is_terminal());
170 assert!(StepState::Failed.is_terminal());
171 assert!(StepState::Skipped.is_terminal());
172 }
173
174 #[test]
175 fn test_step_state_serde() {
176 let states = vec![
177 StepState::Pending,
178 StepState::Running,
179 StepState::Completed,
180 StepState::Failed,
181 StepState::Skipped,
182 ];
183 for state in states {
184 let json = serde_json::to_string(&state).unwrap();
185 let parsed: StepState = serde_json::from_str(&json).unwrap();
186 assert_eq!(state, parsed);
187 }
188 }
189}