use crate::reducer::event::ErrorEvent;
use crate::reducer::event::PipelinePhase;
use crate::reducer::state::PipelineState;
fn compute_failed_phase_for_recovery(
state: &PipelineState,
explicit_failed_phase: Option<PipelinePhase>,
) -> PipelinePhase {
if let Some(phase) = explicit_failed_phase {
return phase;
}
if state.phase == PipelinePhase::AwaitingDevFix {
return state
.failed_phase_for_recovery
.or(state.previous_phase)
.unwrap_or(PipelinePhase::Development);
}
state.phase
}
fn route_to_awaiting_dev_fix(
state: &PipelineState,
explicit_failed_phase: Option<PipelinePhase>,
) -> PipelineState {
let failed_phase_for_recovery = compute_failed_phase_for_recovery(state, explicit_failed_phase);
let in_recovery_loop = state.phase == PipelinePhase::AwaitingDevFix
|| state.previous_phase == Some(PipelinePhase::AwaitingDevFix);
PipelineState {
previous_phase: Some(state.phase),
phase: PipelinePhase::AwaitingDevFix,
dev_fix_triggered: false,
failed_phase_for_recovery: Some(failed_phase_for_recovery),
dev_fix_attempt_count: if in_recovery_loop {
state.dev_fix_attempt_count
} else {
0
},
recovery_escalation_level: if in_recovery_loop {
state.recovery_escalation_level
} else {
0
},
..state.clone()
}
}
pub(super) fn reduce_error(state: &PipelineState, error: &ErrorEvent) -> PipelineState {
match error {
ErrorEvent::UserInterruptRequested => {
PipelineState {
previous_phase: Some(state.phase),
phase: PipelinePhase::Interrupted,
interrupted_by_user: true,
completion_marker_pending: false,
completion_marker_is_failure: false,
completion_marker_reason: None,
..state.clone()
}
}
ErrorEvent::PlanningContinuationNotSupported
| ErrorEvent::ReviewContinuationNotSupported
| ErrorEvent::FixContinuationNotSupported
| ErrorEvent::CommitContinuationNotSupported => {
route_to_awaiting_dev_fix(state, None)
}
ErrorEvent::ReviewInputsNotMaterialized { .. }
| ErrorEvent::PlanningInputsNotMaterialized { .. }
| ErrorEvent::DevelopmentInputsNotMaterialized { .. }
| ErrorEvent::CommitInputsNotMaterialized { .. }
| ErrorEvent::CommitAgentNotInitialized { .. }
| ErrorEvent::ValidatedPlanningMarkdownMissing { .. }
| ErrorEvent::ValidatedDevelopmentOutcomeMissing { .. }
| ErrorEvent::ValidatedReviewOutcomeMissing { .. }
| ErrorEvent::ValidatedFixOutcomeMissing { .. }
| ErrorEvent::ValidatedCommitOutcomeMissing { .. } => {
route_to_awaiting_dev_fix(state, None)
}
ErrorEvent::FixPromptMissing => PipelineState {
fix_prompt_prepared_pass: None,
..state.clone()
},
ErrorEvent::AgentNotFound { .. } => PipelineState {
agent_chain: state.agent_chain.switch_to_next_agent().clear_session_id(),
continuation: crate::reducer::state::ContinuationState {
xsd_retry_count: 0,
xsd_retry_pending: false,
xsd_retry_session_reuse_pending: false,
same_agent_retry_count: 0,
same_agent_retry_pending: false,
same_agent_retry_reason: None,
..state.continuation.clone()
},
..state.clone()
},
ErrorEvent::PlanningPromptMissing { .. } => PipelineState {
planning_prompt_prepared_iteration: None,
..state.clone()
},
ErrorEvent::DevelopmentPromptMissing { .. } => PipelineState {
development_prompt_prepared_iteration: None,
..state.clone()
},
ErrorEvent::ReviewPromptMissing { .. } => PipelineState {
review_prompt_prepared_pass: None,
..state.clone()
},
ErrorEvent::CommitPromptMissing { .. } => PipelineState {
commit_prompt_prepared: false,
..state.clone()
},
ErrorEvent::WorkspaceReadFailed { .. }
| ErrorEvent::WorkspaceWriteFailed { .. }
| ErrorEvent::WorkspaceCreateDirAllFailed { .. }
| ErrorEvent::WorkspaceRemoveFailed { .. }
| ErrorEvent::GitAddAllFailed { .. }
| ErrorEvent::GitAddSpecificFailed { .. }
| ErrorEvent::GitStatusFailed { .. } => route_to_awaiting_dev_fix(state, None),
ErrorEvent::AgentChainExhausted { phase, .. } => {
route_to_awaiting_dev_fix(state, Some(*phase))
}
}
}
#[cfg(test)]
#[path = "error/tests.rs"]
mod tests;