use crate::agents::{AgentDrain, DrainMode};
use crate::reducer::effect::{ContinuationContextData, Effect};
use crate::reducer::event::CheckpointTrigger;
use crate::reducer::state::{DevelopmentStatus, PipelineState, PromptMode};
pub const REQUIRED_FILES: &[&str] = &[".agent/tmp/development_result.xml"];
pub(super) fn determine_development_effect(state: &PipelineState) -> Effect {
if state.continuation.context_write_pending {
let status = state
.continuation
.previous_status
.unwrap_or(DevelopmentStatus::Failed);
let summary = state
.continuation
.previous_summary
.clone()
.unwrap_or_default();
let files_changed = state.continuation.previous_files_changed.clone();
let next_steps = state.continuation.previous_next_steps.clone();
return Effect::WriteContinuationContext(ContinuationContextData {
iteration: state.iteration,
attempt: state.continuation.continuation_attempt,
status,
summary,
files_changed,
next_steps,
});
}
if state.agent_chain.agents.is_empty() {
return Effect::InitializeAgentChain {
drain: AgentDrain::Development,
};
}
let last_effect_was_dev_agent = state
.continuation
.last_effect_kind
.as_deref()
.is_some_and(|k| k.contains("InvokeDevelopmentAgent"));
let effective_agent_invoked = state.development_agent_invoked_iteration
== Some(state.iteration)
|| (last_effect_was_dev_agent
&& state.development_context_prepared_iteration == Some(state.iteration)
&& state.development_prompt_prepared_iteration == Some(state.iteration)
&& state.development_required_files_cleaned_iteration == Some(state.iteration)
&& state.agent_chain.current_drain == AgentDrain::Development
&& state.agent_chain.current_mode == DrainMode::Normal);
if !effective_agent_invoked && state.agent_chain.current_drain != AgentDrain::Development {
return Effect::InitializeAgentChain {
drain: AgentDrain::Development,
};
}
let consumer_signature_sha256 = state.agent_chain.consumer_signature_sha256();
let iteration_needs_work = state.iteration < state.total_iterations
|| (state.iteration == state.total_iterations && state.total_iterations > 0);
if iteration_needs_work {
if state.development_context_prepared_iteration != Some(state.iteration) {
return Effect::PrepareDevelopmentContext {
iteration: state.iteration,
};
}
if state.development_prompt_prepared_iteration != Some(state.iteration) {
let development_inputs_materialized_for_iteration =
state.prompt_inputs.development.as_ref().is_some_and(|p| {
p.iteration == state.iteration
&& p.prompt.consumer_signature_sha256 == consumer_signature_sha256
&& p.plan.consumer_signature_sha256 == consumer_signature_sha256
});
if !development_inputs_materialized_for_iteration {
return Effect::MaterializeDevelopmentInputs {
iteration: state.iteration,
};
}
let prompt_mode = if state.continuation.is_continuation() {
PromptMode::Continuation
} else {
PromptMode::Normal
};
return Effect::PrepareDevelopmentPrompt {
iteration: state.iteration,
prompt_mode,
};
}
if state.development_required_files_cleaned_iteration != Some(state.iteration) {
return Effect::CleanupRequiredFiles {
files: REQUIRED_FILES.iter().map(ToString::to_string).collect(),
};
}
if !effective_agent_invoked {
return Effect::InvokeDevelopmentAgent {
iteration: state.iteration,
};
}
if effective_agent_invoked
&& state.analysis_agent_invoked_iteration != Some(state.iteration)
{
if state.agent_chain.current_drain != AgentDrain::Analysis {
return Effect::InitializeAgentChain {
drain: AgentDrain::Analysis,
};
}
return Effect::InvokeAnalysisAgent {
iteration: state.iteration,
};
}
if state.development_xml_extracted_iteration != Some(state.iteration) {
return Effect::ExtractDevelopmentXml {
iteration: state.iteration,
};
}
let dev_validated_is_for_iteration = state
.development_validated_outcome
.as_ref()
.is_some_and(|o| o.iteration == state.iteration);
if !dev_validated_is_for_iteration {
return Effect::ValidateDevelopmentXml {
iteration: state.iteration,
};
}
if state.development_xml_archived_iteration != Some(state.iteration) {
return Effect::ArchiveDevelopmentXml {
iteration: state.iteration,
};
}
if crate::reducer::orchestration::is_recovery_state_active(state)
&& state.development_xml_archived_iteration == Some(state.iteration)
{
return Effect::EmitRecoverySuccess {
level: state.recovery_escalation_level,
total_attempts: state.dev_fix_attempt_count,
};
}
Effect::ApplyDevelopmentOutcome {
iteration: state.iteration,
}
} else {
Effect::SaveCheckpoint {
trigger: CheckpointTrigger::PhaseTransition,
}
}
}