ralph_workflow/interrupt/
checkpoint.rs1use crate::workspace::Workspace;
8
9#[derive(Clone)]
14pub struct InterruptContext {
15 pub phase: crate::checkpoint::PipelinePhase,
17 pub iteration: u32,
19 pub total_iterations: u32,
21 pub reviewer_pass: u32,
23 pub total_reviewer_passes: u32,
25 pub run_context: crate::checkpoint::RunContext,
27 pub execution_history: crate::checkpoint::ExecutionHistory,
29 pub prompt_history: std::collections::HashMap<String, crate::prompts::PromptHistoryEntry>,
31 pub workspace: std::sync::Arc<dyn Workspace>,
33}
34
35pub(super) fn save_interrupt_checkpoint(context: &InterruptContext) -> anyhow::Result<()> {
47 use crate::checkpoint::state::{
48 calculate_file_checksum_with_workspace, AgentConfigSnapshot, CheckpointParams,
49 CliArgsSnapshotBuilder, PipelineCheckpoint, RebaseState,
50 };
51 use crate::checkpoint::{load_checkpoint_with_workspace, save_checkpoint_with_workspace};
52 use std::path::Path;
53
54 if let Ok(Some(checkpoint)) = load_checkpoint_with_workspace(&*context.workspace) {
56 let checkpoint = PipelineCheckpoint {
58 phase: context.phase,
59 iteration: context.iteration,
60 total_iterations: context.total_iterations,
61 reviewer_pass: context.reviewer_pass,
62 total_reviewer_passes: context.total_reviewer_passes,
63 actual_developer_runs: context.run_context.actual_developer_runs,
64 actual_reviewer_runs: context.run_context.actual_reviewer_runs,
65 execution_history: Some(context.execution_history.clone()),
66 prompt_history: Some(context.prompt_history.clone()),
67 interrupted_by_user: true,
68 ..checkpoint
69 };
70
71 save_checkpoint_with_workspace(&*context.workspace, &checkpoint)?;
72 } else {
73 let prompt_md_checksum =
81 calculate_file_checksum_with_workspace(&*context.workspace, Path::new("PROMPT.md"))
82 .or_else(|| Some("unknown".to_string()));
83
84 let cli_args = CliArgsSnapshotBuilder::new(
85 context.total_iterations,
86 context.total_reviewer_passes,
87 None,
88 true,
89 )
90 .build();
91
92 let developer_agent = "unknown";
93 let reviewer_agent = "unknown";
94 let developer_agent_config = AgentConfigSnapshot::new(
95 developer_agent.to_string(),
96 "unknown".to_string(),
97 "-o".to_string(),
98 None,
99 true,
100 );
101 let reviewer_agent_config = AgentConfigSnapshot::new(
102 reviewer_agent.to_string(),
103 "unknown".to_string(),
104 "-o".to_string(),
105 None,
106 true,
107 );
108
109 let working_dir = context.workspace.root().to_string_lossy().to_string();
110 let base_checkpoint = PipelineCheckpoint::from_params(CheckpointParams {
111 phase: context.phase,
112 iteration: context.iteration,
113 total_iterations: context.total_iterations,
114 reviewer_pass: context.reviewer_pass,
115 total_reviewer_passes: context.total_reviewer_passes,
116 developer_agent,
117 reviewer_agent,
118 cli_args,
119 developer_agent_config,
120 reviewer_agent_config,
121 rebase_state: RebaseState::default(),
122 git_user_name: None,
123 git_user_email: None,
124 run_id: &context.run_context.run_id,
125 parent_run_id: context.run_context.parent_run_id.as_deref(),
126 resume_count: context.run_context.resume_count,
127 actual_developer_runs: context.run_context.actual_developer_runs,
128 actual_reviewer_runs: context.run_context.actual_reviewer_runs,
129 working_dir,
130 prompt_md_checksum,
131 config_path: None,
132 config_checksum: None,
133 });
134
135 let checkpoint = PipelineCheckpoint {
136 execution_history: Some(context.execution_history.clone()),
137 prompt_history: Some(context.prompt_history.clone()),
138 interrupted_by_user: true,
139 ..base_checkpoint
140 };
141
142 save_checkpoint_with_workspace(&*context.workspace, &checkpoint)?;
143 }
144
145 Ok(())
146}