use super::super::{ArtifactType, DevelopmentStatus, FixStatus, SameAgentRetryReason};
use crate::agents::AgentDrain;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct ContinuationState {
pub previous_status: Option<DevelopmentStatus>,
pub previous_summary: Option<String>,
pub previous_files_changed: Option<Box<[String]>>,
pub previous_next_steps: Option<String>,
pub continuation_attempt: u32,
#[serde(default)]
pub invalid_output_attempts: u32,
#[serde(default)]
pub context_write_pending: bool,
#[serde(default)]
pub context_cleanup_pending: bool,
#[serde(default)]
pub xsd_retry_count: u32,
#[serde(default)]
pub xsd_retry_pending: bool,
#[serde(default)]
pub xsd_retry_session_reuse_pending: bool,
#[serde(default)]
pub last_xsd_error: Option<String>,
#[serde(default)]
pub last_review_xsd_error: Option<String>,
#[serde(default)]
pub last_fix_xsd_error: Option<String>,
#[serde(default)]
pub same_agent_retry_count: u32,
#[serde(default)]
pub same_agent_retry_pending: bool,
#[serde(default)]
pub same_agent_retry_reason: Option<SameAgentRetryReason>,
#[serde(default)]
pub continue_pending: bool,
#[serde(default)]
pub current_artifact: Option<ArtifactType>,
#[serde(default = "default_max_xsd_retry_count")]
pub max_xsd_retry_count: u32,
#[serde(default = "default_max_same_agent_retry_count")]
pub max_same_agent_retry_count: u32,
#[serde(default = "default_max_continue_count")]
pub max_continue_count: u32,
#[serde(default)]
pub fix_status: Option<FixStatus>,
#[serde(default)]
pub fix_previous_summary: Option<String>,
#[serde(default)]
pub fix_continuation_attempt: u32,
#[serde(default)]
pub fix_continue_pending: bool,
#[serde(default = "default_max_fix_continue_count")]
pub max_fix_continue_count: u32,
#[serde(default)]
pub last_effect_kind: Option<String>,
#[serde(default)]
pub consecutive_same_effect_count: u32,
#[serde(default = "default_max_consecutive_same_effect")]
pub max_consecutive_same_effect: u32,
#[serde(default)]
pub timeout_context_write_pending: bool,
#[serde(default)]
pub timeout_context_file_path: Option<String>,
}
const fn default_max_xsd_retry_count() -> u32 {
10
}
const fn default_max_same_agent_retry_count() -> u32 {
2
}
const fn default_max_continue_count() -> u32 {
3
}
const fn default_max_fix_continue_count() -> u32 {
10
}
pub const DEFAULT_LOOP_DETECTION_THRESHOLD: u32 = 100;
const fn default_max_consecutive_same_effect() -> u32 {
DEFAULT_LOOP_DETECTION_THRESHOLD
}
impl Default for ContinuationState {
fn default() -> Self {
Self {
previous_status: None,
previous_summary: None,
previous_files_changed: None,
previous_next_steps: None,
continuation_attempt: 0,
invalid_output_attempts: 0,
context_write_pending: false,
context_cleanup_pending: false,
xsd_retry_count: 0,
xsd_retry_pending: false,
xsd_retry_session_reuse_pending: false,
last_xsd_error: None,
last_review_xsd_error: None,
last_fix_xsd_error: None,
same_agent_retry_count: 0,
same_agent_retry_pending: false,
same_agent_retry_reason: None,
continue_pending: false,
current_artifact: None,
max_xsd_retry_count: default_max_xsd_retry_count(),
max_same_agent_retry_count: default_max_same_agent_retry_count(),
max_continue_count: default_max_continue_count(),
fix_status: None,
fix_previous_summary: None,
fix_continuation_attempt: 0,
fix_continue_pending: false,
max_fix_continue_count: default_max_fix_continue_count(),
last_effect_kind: None,
consecutive_same_effect_count: 0,
max_consecutive_same_effect: DEFAULT_LOOP_DETECTION_THRESHOLD,
timeout_context_write_pending: false,
timeout_context_file_path: None,
}
}
}
impl ContinuationState {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_limits(
max_xsd_retry_count: u32,
max_continue_count: u32,
max_same_agent_retry_count: u32,
) -> Self {
Self {
max_xsd_retry_count,
max_same_agent_retry_count,
max_continue_count,
max_fix_continue_count: default_max_fix_continue_count(),
..Self::default()
}
}
#[must_use]
pub fn with_max_xsd_retry(self, max_xsd_retry_count: u32) -> Self {
Self {
max_xsd_retry_count,
..self
}
}
#[must_use]
pub fn with_max_same_agent_retry(self, max_same_agent_retry_count: u32) -> Self {
Self {
max_same_agent_retry_count,
..self
}
}
#[must_use]
pub const fn is_continuation(&self) -> bool {
self.continuation_attempt > 0
}
#[must_use]
pub const fn pending_continuation_for_drain(&self, drain: AgentDrain) -> bool {
match drain {
AgentDrain::Development => self.continue_pending,
AgentDrain::Fix => self.fix_continue_pending,
AgentDrain::Planning
| AgentDrain::Review
| AgentDrain::Commit
| AgentDrain::Analysis => false,
}
}
#[must_use]
pub const fn continuation_exhausted_for_drain(&self, drain: AgentDrain) -> bool {
match drain {
AgentDrain::Development => self.continuation_attempt >= self.max_continue_count,
AgentDrain::Fix => self.fix_continuation_attempt >= self.max_fix_continue_count,
AgentDrain::Planning
| AgentDrain::Review
| AgentDrain::Commit
| AgentDrain::Analysis => false,
}
}
#[must_use]
pub fn reset(self) -> Self {
Self {
max_xsd_retry_count: self.max_xsd_retry_count,
max_same_agent_retry_count: self.max_same_agent_retry_count,
max_continue_count: self.max_continue_count,
max_fix_continue_count: self.max_fix_continue_count,
max_consecutive_same_effect: self.max_consecutive_same_effect,
..Self::default()
}
}
}