1use super::{ContinueReason, StopReason};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub(super) enum NextAction {
5 Continue {
6 prompt: String,
7 reason: ContinueReason,
8 },
9 Stop {
10 reason: NextActionStopReason,
11 },
12}
13
14pub(super) type NextActionStopReason = StopReason;
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub(super) struct RuntimeEvidence {
17 pub(super) repeated_action: bool,
18 pub(super) execution_stop_reason: Option<NextActionStopReason>,
19 pub(super) work_completed: bool,
20 pub(super) execution_debt: bool,
21 pub(super) execution_evidence: bool,
22 pub(super) planning_only_progress: bool,
23}
24
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub(super) struct ManaEvidence {
27 pub(super) stop_reason: Option<NextActionStopReason>,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub(super) struct TextFallbackEvidence {
32 pub(super) planner_stop_reason: Option<NextActionStopReason>,
33 pub(super) execution_stop_reason: Option<NextActionStopReason>,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub(super) struct ContinueRecommendation {
38 pub(super) prompt: String,
39 pub(super) reason: ContinueReason,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct NextActionAssessment {
44 pub runtime: NextActionRuntimeEvidence,
45 pub mana: NextActionManaEvidence,
46 pub text_fallback: NextActionTextFallbackEvidence,
47 pub continue_recommendation: Option<NextActionContinueRecommendation>,
48 pub chosen_action: NextActionDebugView,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct NextActionRuntimeEvidence {
53 pub repeated_action: bool,
54 pub execution_stop_reason: Option<String>,
55 pub work_completed: bool,
56 pub execution_debt: bool,
57 pub execution_evidence: bool,
58 pub planning_only_progress: bool,
59}
60
61#[derive(Debug, Clone, PartialEq, Eq)]
62pub struct NextActionManaEvidence {
63 pub stop_reason: Option<String>,
64}
65
66#[derive(Debug, Clone, PartialEq, Eq)]
67pub struct NextActionTextFallbackEvidence {
68 pub planner_stop_reason: Option<String>,
69 pub execution_stop_reason: Option<String>,
70}
71
72#[derive(Debug, Clone, PartialEq, Eq)]
73pub struct NextActionContinueRecommendation {
74 pub prompt: String,
75 pub reason: String,
76}
77
78#[derive(Debug, Clone, PartialEq, Eq)]
79pub enum NextActionDebugView {
80 Continue { prompt: String, reason: String },
81 Stop { reason: String },
82}
83
84#[derive(Debug, Clone, PartialEq, Eq)]
85pub(super) struct PostTurnAssessment {
86 pub(super) runtime: RuntimeEvidence,
87 pub(super) mana: ManaEvidence,
88 pub(super) text_fallback: TextFallbackEvidence,
89 pub(super) continue_recommendation: Option<ContinueRecommendation>,
90}
91
92impl PostTurnAssessment {
93 pub(super) fn into_next_action(self) -> NextAction {
94 if self.runtime.repeated_action {
95 return NextAction::Stop {
96 reason: NextActionStopReason::RepeatedAction,
97 };
98 }
99
100 if let Some(reason) = self.runtime.execution_stop_reason {
101 return NextAction::Stop { reason };
102 }
103
104 if self.runtime.work_completed {
105 return NextAction::Stop {
106 reason: NextActionStopReason::WorkCompleted,
107 };
108 }
109
110 if let Some(reason) = self.mana.stop_reason {
111 return NextAction::Stop { reason };
112 }
113
114 if let Some(reason) = self.text_fallback.planner_stop_reason {
115 return NextAction::Stop { reason };
116 }
117
118 if let Some(reason) = self.text_fallback.execution_stop_reason {
119 return NextAction::Stop { reason };
120 }
121
122 if let Some(continue_recommendation) = self.continue_recommendation {
123 return NextAction::Continue {
124 prompt: continue_recommendation.prompt,
125 reason: continue_recommendation.reason,
126 };
127 }
128
129 if self.runtime.planning_only_progress {
130 return NextAction::Stop {
131 reason: NextActionStopReason::NoProgress,
132 };
133 }
134
135 NextAction::Stop {
136 reason: NextActionStopReason::NoAutomaticFollowUp,
137 }
138 }
139
140 pub(super) fn debug_view(&self) -> NextActionAssessment {
141 let chosen_action = match self.clone().into_next_action() {
142 NextAction::Continue { prompt, reason } => NextActionDebugView::Continue {
143 prompt,
144 reason: reason.as_str().to_string(),
145 },
146 NextAction::Stop { reason } => NextActionDebugView::Stop {
147 reason: reason.as_str().to_string(),
148 },
149 };
150
151 NextActionAssessment {
152 runtime: NextActionRuntimeEvidence {
153 repeated_action: self.runtime.repeated_action,
154 execution_stop_reason: self
155 .runtime
156 .execution_stop_reason
157 .map(|reason| reason.as_str().to_string()),
158 work_completed: self.runtime.work_completed,
159 execution_debt: self.runtime.execution_debt,
160 execution_evidence: self.runtime.execution_evidence,
161 planning_only_progress: self.runtime.planning_only_progress,
162 },
163 mana: NextActionManaEvidence {
164 stop_reason: self
165 .mana
166 .stop_reason
167 .map(|reason| reason.as_str().to_string()),
168 },
169 text_fallback: NextActionTextFallbackEvidence {
170 planner_stop_reason: self
171 .text_fallback
172 .planner_stop_reason
173 .map(|reason| reason.as_str().to_string()),
174 execution_stop_reason: self
175 .text_fallback
176 .execution_stop_reason
177 .map(|reason| reason.as_str().to_string()),
178 },
179 continue_recommendation: self.continue_recommendation.clone().map(|recommendation| {
180 NextActionContinueRecommendation {
181 prompt: recommendation.prompt,
182 reason: recommendation.reason.as_str().to_string(),
183 }
184 }),
185 chosen_action,
186 }
187 }
188}