1#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
6pub struct ReviewValidatedOutcome {
7 pub pass: u32,
8 pub issues_found: bool,
9 pub clean_no_issues: bool,
10 #[serde(default)]
11 pub issues: Vec<String>,
12 #[serde(default)]
13 pub no_issues_found: Option<String>,
14}
15
16#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
17pub struct PlanningValidatedOutcome {
18 pub iteration: u32,
19 pub valid: bool,
20 #[serde(default)]
21 pub markdown: Option<String>,
22}
23
24#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
25pub struct DevelopmentValidatedOutcome {
26 pub iteration: u32,
27 pub status: DevelopmentStatus,
28 pub summary: String,
29 pub files_changed: Option<Vec<String>>,
30 pub next_steps: Option<String>,
31}
32
33#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
34pub struct FixValidatedOutcome {
35 pub pass: u32,
36 pub status: FixStatus,
37 pub summary: Option<String>,
38}
39
40#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
41pub struct CommitValidatedOutcome {
42 pub attempt: u32,
43 pub message: Option<String>,
44 pub reason: Option<String>,
45}
46
47#[derive(Clone, Serialize, Deserialize, Debug, Default)]
48pub struct PromptInputsState {
49 #[serde(default)]
50 pub planning: Option<MaterializedPlanningInputs>,
51 #[serde(default)]
52 pub development: Option<MaterializedDevelopmentInputs>,
53 #[serde(default)]
54 pub review: Option<MaterializedReviewInputs>,
55 #[serde(default)]
56 pub commit: Option<MaterializedCommitInputs>,
57 #[serde(default)]
61 pub xsd_retry_last_output: Option<MaterializedXsdRetryLastOutput>,
62}
63
64#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
65pub struct MaterializedPlanningInputs {
66 pub iteration: u32,
67 pub prompt: MaterializedPromptInput,
68}
69
70#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
71pub struct MaterializedDevelopmentInputs {
72 pub iteration: u32,
73 pub prompt: MaterializedPromptInput,
74 pub plan: MaterializedPromptInput,
75}
76
77#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
78pub struct MaterializedReviewInputs {
79 pub pass: u32,
80 pub plan: MaterializedPromptInput,
81 pub diff: MaterializedPromptInput,
82}
83
84#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
85pub struct MaterializedCommitInputs {
86 pub attempt: u32,
87 pub diff: MaterializedPromptInput,
88}
89
90#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
91pub struct MaterializedXsdRetryLastOutput {
92 pub phase: PipelinePhase,
93 pub scope_id: u32,
94 pub last_output: MaterializedPromptInput,
95}
96
97#[derive(Clone, Serialize, Deserialize, Debug)]
115pub struct PipelineState {
116 pub phase: PipelinePhase,
117 pub previous_phase: Option<PipelinePhase>,
118 pub iteration: u32,
119 pub total_iterations: u32,
120 pub reviewer_pass: u32,
121 pub total_reviewer_passes: u32,
122 pub review_issues_found: bool,
123 #[serde(default)]
125 pub planning_prompt_prepared_iteration: Option<u32>,
126 #[serde(default)]
128 pub planning_xml_cleaned_iteration: Option<u32>,
129 #[serde(default)]
131 pub planning_agent_invoked_iteration: Option<u32>,
132 #[serde(default)]
134 pub planning_xml_extracted_iteration: Option<u32>,
135 #[serde(default)]
137 pub planning_validated_outcome: Option<PlanningValidatedOutcome>,
138 #[serde(default)]
140 pub planning_markdown_written_iteration: Option<u32>,
141 #[serde(default)]
143 pub planning_xml_archived_iteration: Option<u32>,
144 #[serde(default)]
148 pub development_context_prepared_iteration: Option<u32>,
149 #[serde(default)]
151 pub development_prompt_prepared_iteration: Option<u32>,
152 #[serde(default)]
154 pub development_xml_cleaned_iteration: Option<u32>,
155 #[serde(default)]
157 pub development_agent_invoked_iteration: Option<u32>,
158 #[serde(default)]
164 pub analysis_agent_invoked_iteration: Option<u32>,
165 #[serde(default)]
167 pub development_xml_extracted_iteration: Option<u32>,
168 #[serde(default)]
170 pub development_validated_outcome: Option<DevelopmentValidatedOutcome>,
171 #[serde(default)]
173 pub development_xml_archived_iteration: Option<u32>,
174 #[serde(default)]
178 pub review_context_prepared_pass: Option<u32>,
179 #[serde(default)]
181 pub review_prompt_prepared_pass: Option<u32>,
182 #[serde(default)]
184 pub review_issues_xml_cleaned_pass: Option<u32>,
185 #[serde(default)]
187 pub review_agent_invoked_pass: Option<u32>,
188 #[serde(default)]
190 pub review_issues_xml_extracted_pass: Option<u32>,
191 #[serde(default)]
196 pub review_validated_outcome: Option<ReviewValidatedOutcome>,
197 #[serde(default)]
199 pub review_issues_markdown_written_pass: Option<u32>,
200 #[serde(default)]
202 pub review_issue_snippets_extracted_pass: Option<u32>,
203 #[serde(default)]
204 pub review_issues_xml_archived_pass: Option<u32>,
205
206 #[serde(default)]
207 pub fix_prompt_prepared_pass: Option<u32>,
208
209 #[serde(default)]
210 pub fix_result_xml_cleaned_pass: Option<u32>,
211
212 #[serde(default)]
213 pub fix_agent_invoked_pass: Option<u32>,
214
215 #[serde(default)]
216 pub fix_result_xml_extracted_pass: Option<u32>,
217
218 #[serde(default)]
219 pub fix_validated_outcome: Option<FixValidatedOutcome>,
220
221 #[serde(default)]
222 pub fix_result_xml_archived_pass: Option<u32>,
223 #[serde(default)]
225 pub commit_prompt_prepared: bool,
226 #[serde(default)]
228 pub commit_diff_prepared: bool,
229 #[serde(default)]
231 pub commit_diff_empty: bool,
232 #[serde(default)]
238 pub commit_diff_content_id_sha256: Option<String>,
239 #[serde(default)]
241 pub commit_agent_invoked: bool,
242 #[serde(default)]
244 pub commit_xml_cleaned: bool,
245 #[serde(default)]
247 pub commit_xml_extracted: bool,
248 #[serde(default)]
250 pub commit_validated_outcome: Option<CommitValidatedOutcome>,
251 #[serde(default)]
253 pub commit_xml_archived: bool,
254 pub context_cleaned: bool,
255 pub agent_chain: AgentChainState,
256 pub rebase: RebaseState,
257 pub commit: CommitState,
258 pub execution_history: Vec<ExecutionStep>,
259 #[serde(default)]
264 pub checkpoint_saved_count: u32,
265 #[serde(default)]
270 pub continuation: ContinuationState,
271
272 #[serde(default)]
277 pub metrics: RunMetrics,
278
279 #[serde(default)]
286 pub dev_fix_triggered: bool,
287
288 #[serde(default)]
295 pub prompt_inputs: PromptInputsState,
296}
297
298impl PipelineState {
299 pub fn initial(developer_iters: u32, reviewer_reviews: u32) -> Self {
300 Self::initial_with_continuation(developer_iters, reviewer_reviews, ContinuationState::new())
301 }
302
303 pub fn initial_with_continuation(
319 developer_iters: u32,
320 reviewer_reviews: u32,
321 continuation: ContinuationState,
322 ) -> Self {
323 let initial_phase = if developer_iters == 0 {
325 if reviewer_reviews == 0 {
327 PipelinePhase::CommitMessage
329 } else {
330 PipelinePhase::Review
331 }
332 } else {
333 PipelinePhase::Planning
334 };
335
336 Self {
337 phase: initial_phase,
338 previous_phase: None,
339 iteration: 0,
340 total_iterations: developer_iters,
341 reviewer_pass: 0,
342 total_reviewer_passes: reviewer_reviews,
343 review_issues_found: false,
344 planning_prompt_prepared_iteration: None,
345 planning_xml_cleaned_iteration: None,
346 planning_agent_invoked_iteration: None,
347 planning_xml_extracted_iteration: None,
348 planning_validated_outcome: None,
349 planning_markdown_written_iteration: None,
350 planning_xml_archived_iteration: None,
351 development_context_prepared_iteration: None,
352 development_prompt_prepared_iteration: None,
353 development_xml_cleaned_iteration: None,
354 development_agent_invoked_iteration: None,
355 analysis_agent_invoked_iteration: None,
356 development_xml_extracted_iteration: None,
357 development_validated_outcome: None,
358 development_xml_archived_iteration: None,
359 review_context_prepared_pass: None,
360 review_prompt_prepared_pass: None,
361 review_issues_xml_cleaned_pass: None,
362 review_agent_invoked_pass: None,
363 review_issues_xml_extracted_pass: None,
364 review_validated_outcome: None,
365 review_issues_markdown_written_pass: None,
366 review_issue_snippets_extracted_pass: None,
367 review_issues_xml_archived_pass: None,
368 fix_prompt_prepared_pass: None,
369 fix_result_xml_cleaned_pass: None,
370 fix_agent_invoked_pass: None,
371 fix_result_xml_extracted_pass: None,
372 fix_validated_outcome: None,
373 fix_result_xml_archived_pass: None,
374 commit_prompt_prepared: false,
375 commit_diff_prepared: false,
376 commit_diff_empty: false,
377 commit_diff_content_id_sha256: None,
378 commit_agent_invoked: false,
379 commit_xml_cleaned: false,
380 commit_xml_extracted: false,
381 commit_validated_outcome: None,
382 commit_xml_archived: false,
383 context_cleaned: false,
384 agent_chain: AgentChainState::initial(),
385 rebase: RebaseState::NotStarted,
386 commit: CommitState::NotStarted,
387 execution_history: Vec::new(),
388 checkpoint_saved_count: 0,
389 continuation: continuation.clone(),
390 dev_fix_triggered: false,
391 prompt_inputs: PromptInputsState::default(),
392 metrics: RunMetrics::new(developer_iters, reviewer_reviews, &continuation),
393 }
394 }
395
396 pub fn is_complete(&self) -> bool {
436 matches!(self.phase, PipelinePhase::Complete)
437 || (matches!(self.phase, PipelinePhase::Interrupted)
438 && (self.checkpoint_saved_count > 0
439 || matches!(self.previous_phase, Some(PipelinePhase::AwaitingDevFix))))
444 }
445
446 pub fn current_head(&self) -> String {
447 self.rebase
448 .current_head()
449 .unwrap_or_else(|| "HEAD".to_string())
450 }
451}
452
453impl From<PipelineCheckpoint> for PipelineState {
454 fn from(checkpoint: PipelineCheckpoint) -> Self {
455 let rebase_state = map_checkpoint_rebase_state(&checkpoint.rebase_state);
456 let agent_chain = AgentChainState::initial();
457
458 PipelineState {
459 phase: map_checkpoint_phase(checkpoint.phase),
460 previous_phase: None,
461 iteration: checkpoint.iteration,
462 total_iterations: checkpoint.total_iterations,
463 reviewer_pass: checkpoint.reviewer_pass,
464 total_reviewer_passes: checkpoint.total_reviewer_passes,
465 review_issues_found: false,
466 planning_prompt_prepared_iteration: None,
467 planning_xml_cleaned_iteration: None,
468 planning_agent_invoked_iteration: None,
469 planning_xml_extracted_iteration: None,
470 planning_validated_outcome: None,
471 planning_markdown_written_iteration: None,
472 planning_xml_archived_iteration: None,
473 development_context_prepared_iteration: None,
474 development_prompt_prepared_iteration: None,
475 development_xml_cleaned_iteration: None,
476 development_agent_invoked_iteration: None,
477 analysis_agent_invoked_iteration: None,
478 development_xml_extracted_iteration: None,
479 development_validated_outcome: None,
480 development_xml_archived_iteration: None,
481 review_context_prepared_pass: None,
482 review_prompt_prepared_pass: None,
483 review_issues_xml_cleaned_pass: None,
484 review_agent_invoked_pass: None,
485 review_issues_xml_extracted_pass: None,
486 review_validated_outcome: None,
487 review_issues_markdown_written_pass: None,
488 review_issue_snippets_extracted_pass: None,
489 review_issues_xml_archived_pass: None,
490 fix_prompt_prepared_pass: None,
491 fix_result_xml_cleaned_pass: None,
492 fix_agent_invoked_pass: None,
493 fix_result_xml_extracted_pass: None,
494 fix_validated_outcome: None,
495 fix_result_xml_archived_pass: None,
496 commit_prompt_prepared: false,
497 commit_diff_prepared: false,
498 commit_diff_empty: false,
499 commit_diff_content_id_sha256: None,
500 commit_agent_invoked: false,
501 commit_xml_cleaned: false,
502 commit_xml_extracted: false,
503 commit_validated_outcome: None,
504 commit_xml_archived: false,
505 context_cleaned: false,
506 agent_chain,
507 rebase: rebase_state,
508 commit: CommitState::NotStarted,
509 execution_history: checkpoint
510 .execution_history
511 .map(|h| h.steps)
512 .unwrap_or_default(),
513 checkpoint_saved_count: 0,
514 continuation: ContinuationState::new(),
515 dev_fix_triggered: false,
516 prompt_inputs: checkpoint.prompt_inputs.unwrap_or_default(),
517 metrics: {
518 let continuation = ContinuationState::new();
519 RunMetrics {
520 dev_iterations_completed: checkpoint.actual_developer_runs,
521 review_passes_completed: checkpoint.actual_reviewer_runs,
522 max_dev_iterations: checkpoint.total_iterations,
523 max_review_passes: checkpoint.total_reviewer_passes,
524 max_xsd_retry_count: continuation.max_xsd_retry_count,
525 max_dev_continuation_count: continuation.max_continue_count,
526 max_fix_continuation_count: continuation.max_fix_continue_count,
527 max_same_agent_retry_count: continuation.max_same_agent_retry_count,
528 ..RunMetrics::default()
529 }
530 },
531 }
532 }
533}
534
535fn map_checkpoint_phase(phase: CheckpointPhase) -> PipelinePhase {
536 match phase {
537 CheckpointPhase::Rebase => PipelinePhase::Planning,
538 CheckpointPhase::Planning => PipelinePhase::Planning,
539 CheckpointPhase::Development => PipelinePhase::Development,
540 CheckpointPhase::Review => PipelinePhase::Review,
541 CheckpointPhase::CommitMessage => PipelinePhase::CommitMessage,
542 CheckpointPhase::FinalValidation => PipelinePhase::FinalValidation,
543 CheckpointPhase::Complete => PipelinePhase::Complete,
544 CheckpointPhase::PreRebase => PipelinePhase::Planning,
545 CheckpointPhase::PreRebaseConflict => PipelinePhase::Planning,
546 CheckpointPhase::PostRebase => PipelinePhase::CommitMessage,
547 CheckpointPhase::PostRebaseConflict => PipelinePhase::CommitMessage,
548 CheckpointPhase::AwaitingDevFix => PipelinePhase::AwaitingDevFix,
549 CheckpointPhase::Interrupted => PipelinePhase::Interrupted,
550 }
551}
552
553fn map_checkpoint_rebase_state(rebase_state: &CheckpointRebaseState) -> RebaseState {
554 match rebase_state {
555 CheckpointRebaseState::NotStarted => RebaseState::NotStarted,
556 CheckpointRebaseState::PreRebaseInProgress { upstream_branch } => RebaseState::InProgress {
557 original_head: "HEAD".to_string(),
558 target_branch: upstream_branch.clone(),
559 },
560 CheckpointRebaseState::PreRebaseCompleted { commit_oid } => RebaseState::Completed {
561 new_head: commit_oid.clone(),
562 },
563 CheckpointRebaseState::PostRebaseInProgress { upstream_branch } => {
564 RebaseState::InProgress {
565 original_head: "HEAD".to_string(),
566 target_branch: upstream_branch.clone(),
567 }
568 }
569 CheckpointRebaseState::PostRebaseCompleted { commit_oid } => RebaseState::Completed {
570 new_head: commit_oid.clone(),
571 },
572 CheckpointRebaseState::HasConflicts { files } => RebaseState::Conflicted {
573 original_head: "HEAD".to_string(),
574 target_branch: "main".to_string(),
575 files: files.iter().map(PathBuf::from).collect(),
576 resolution_attempts: 0,
577 },
578 CheckpointRebaseState::Failed { .. } => RebaseState::Skipped,
579 }
580}