use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "UPPERCASE")]
pub enum GoalVerdict {
Done,
Continue,
}
impl GoalVerdict {
pub fn from_str_lossy(s: &str) -> Self {
match s.trim().to_uppercase().as_str() {
"DONE" => Self::Done,
_ => Self::Continue,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JudgeDecision {
pub verdict: GoalVerdict,
pub reason: String,
#[serde(default)]
pub corrections: Option<String>,
}
impl JudgeDecision {
pub fn parse_or_continue(raw: &str) -> Self {
match serde_json::from_str::<JudgeDecision>(raw) {
Ok(decision) => decision,
Err(e) => {
tracing::warn!(
"Goal judge returned unparseable JSON: {} — \
defaulting to CONTINUE (fail-open). Raw: {}",
e,
&raw[..raw.len().min(200)]
);
JudgeDecision {
verdict: GoalVerdict::Continue,
reason: format!("judge parse error: {}", e),
corrections: None,
}
}
}
}
}
#[derive(Debug, Clone)]
pub enum GoalDecision {
Done { reason: String },
Continue {
continuation_prompt: String,
corrections: Option<String>,
},
Paused { reason: String },
}
pub const MAX_PARSE_FAILURES: u32 = 3;
pub const DEFAULT_MAX_TURNS: u32 = 20;