ralph_workflow/prompts/
resume_note.rs1use crate::checkpoint::execution_history::StepOutcome;
7use crate::checkpoint::restore::ResumeContext;
8use crate::checkpoint::state::PipelinePhase;
9
10pub fn generate_resume_note(context: &ResumeContext) -> String {
21 let mut note = String::from("SESSION RESUME CONTEXT\n");
22 note.push_str("====================\n\n");
23
24 match context.phase {
26 PipelinePhase::Development => {
27 note.push_str(&format!(
28 "Resuming DEVELOPMENT phase (iteration {} of {})\n",
29 context.iteration + 1,
30 context.total_iterations
31 ));
32 }
33 PipelinePhase::Review => {
34 note.push_str(&format!(
35 "Resuming REVIEW phase (pass {} of {})\n",
36 context.reviewer_pass + 1,
37 context.total_reviewer_passes
38 ));
39 }
40 _ => {
41 note.push_str(&format!("Resuming from phase: {}\n", context.phase_name()));
42 }
43 }
44
45 if context.resume_count > 0 {
47 note.push_str(&format!(
48 "This session has been resumed {} time(s)\n",
49 context.resume_count
50 ));
51 }
52
53 if !matches!(
55 context.rebase_state,
56 crate::checkpoint::state::RebaseState::NotStarted
57 ) {
58 note.push_str(&format!("Rebase state: {:?}\n", context.rebase_state));
59 }
60
61 note.push('\n');
62
63 if let Some(ref history) = context.execution_history {
65 if !history.steps.is_empty() {
66 note.push_str("RECENT ACTIVITY:\n");
67 note.push_str("----------------\n");
68
69 let recent_steps: Vec<_> = history
71 .steps
72 .iter()
73 .rev()
74 .take(5)
75 .collect::<Vec<_>>()
76 .into_iter()
77 .rev()
78 .collect();
79
80 for step in &recent_steps {
81 note.push_str(&format!(
82 "- [{}] {} (iteration {}): {}\n",
83 step.step_type,
84 step.phase,
85 step.iteration,
86 step.outcome.brief_description()
87 ));
88
89 if let Some(ref detail) = step.modified_files_detail {
91 let total_files =
92 detail.added.len() + detail.modified.len() + detail.deleted.len();
93 if total_files > 0 {
94 note.push_str(&format!(" Files: {} changed", total_files));
95 if !detail.added.is_empty() {
96 note.push_str(&format!(" ({} added)", detail.added.len()));
97 }
98 if !detail.modified.is_empty() {
99 note.push_str(&format!(" ({} modified)", detail.modified.len()));
100 }
101 if !detail.deleted.is_empty() {
102 note.push_str(&format!(" ({} deleted)", detail.deleted.len()));
103 }
104 note.push('\n');
105 }
106 }
107
108 if let Some(ref issues) = step.issues_summary {
110 if issues.found > 0 || issues.fixed > 0 {
111 note.push_str(&format!(
112 " Issues: {} found, {} fixed",
113 issues.found, issues.fixed
114 ));
115 if let Some(ref desc) = issues.description {
116 note.push_str(&format!(" ({})", desc));
117 }
118 note.push('\n');
119 }
120 }
121
122 if let Some(ref oid) = step.git_commit_oid {
124 note.push_str(&format!(" Commit: {}\n", oid));
125 }
126 }
127
128 note.push('\n');
129 }
130 }
131
132 note.push_str("Previous progress is preserved in git history.\n");
133
134 note.push_str("\nGUIDANCE:\n");
136 note.push_str("--------\n");
137 match context.phase {
138 PipelinePhase::Development => {
139 note.push_str("Continue working on the implementation tasks from your plan.\n");
140 }
141 PipelinePhase::Review => {
142 note.push_str("Review the code changes and provide feedback.\n");
143 }
144 _ => {}
145 }
146
147 note.push('\n');
148 note
149}
150
151pub trait BriefDescription {
153 fn brief_description(&self) -> String;
154}
155
156impl BriefDescription for StepOutcome {
157 fn brief_description(&self) -> String {
158 match self {
159 Self::Success {
160 files_modified,
161 output,
162 ..
163 } => {
164 if let Some(ref out) = output {
165 if !out.is_empty() {
166 format!("Success - {}", out.lines().next().unwrap_or(""))
167 } else if !files_modified.is_empty() {
168 format!("Success - {} files modified", files_modified.len())
169 } else {
170 "Success".to_string()
171 }
172 } else if !files_modified.is_empty() {
173 format!("Success - {} files modified", files_modified.len())
174 } else {
175 "Success".to_string()
176 }
177 }
178 Self::Failure {
179 error, recoverable, ..
180 } => {
181 if *recoverable {
182 format!("Recoverable error - {}", error.lines().next().unwrap_or(""))
183 } else {
184 format!("Failed - {}", error.lines().next().unwrap_or(""))
185 }
186 }
187 Self::Partial {
188 completed,
189 remaining,
190 ..
191 } => {
192 format!("Partial - {} done, {}", completed, remaining)
193 }
194 Self::Skipped { reason } => {
195 format!("Skipped - {}", reason)
196 }
197 }
198 }
199}