use super::detected_context::DetectedContext;
use super::env_context::EnvContext;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ExecutionContext {
Env(EnvContext),
Detected(DetectedContext),
}
impl ExecutionContext {
pub fn is_env(&self) -> bool {
matches!(self, ExecutionContext::Env(_))
}
pub fn is_detected(&self) -> bool {
matches!(self, ExecutionContext::Detected(_))
}
pub fn as_env(&self) -> Option<&EnvContext> {
match self {
ExecutionContext::Env(env) => Some(env),
_ => None,
}
}
pub fn as_detected(&self) -> Option<&DetectedContext> {
match self {
ExecutionContext::Detected(detected) => Some(detected),
_ => None,
}
}
pub fn into_env(self) -> Option<EnvContext> {
match self {
ExecutionContext::Env(env) => Some(env),
_ => None,
}
}
pub fn into_detected(self) -> Option<DetectedContext> {
match self {
ExecutionContext::Detected(detected) => Some(detected),
_ => None,
}
}
}
pub trait ExecutionContextExt {
fn latest_env(&self) -> Option<&EnvContext>;
fn latest_detected(&self) -> Option<&DetectedContext>;
fn all_envs(&self) -> Vec<&EnvContext>;
fn all_detected(&self) -> Vec<&DetectedContext>;
}
impl ExecutionContextExt for Vec<ExecutionContext> {
fn latest_env(&self) -> Option<&EnvContext> {
self.iter().rev().find_map(|ctx| ctx.as_env())
}
fn latest_detected(&self) -> Option<&DetectedContext> {
self.iter().rev().find_map(|ctx| ctx.as_detected())
}
fn all_envs(&self) -> Vec<&EnvContext> {
self.iter().filter_map(|ctx| ctx.as_env()).collect()
}
fn all_detected(&self) -> Vec<&DetectedContext> {
self.iter().filter_map(|ctx| ctx.as_detected()).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::agent::env_context::StepInfo;
use crate::context::TaskHealth;
#[test]
fn test_execution_context_variants() {
let env = EnvContext::new().with_redesign_count(2);
let detected = DetectedContext::new()
.with_task_health(TaskHealth::AtRisk)
.detected_by("Test");
let ctx_env = ExecutionContext::Env(env.clone());
let ctx_detected = ExecutionContext::Detected(detected.clone());
assert!(ctx_env.is_env());
assert!(!ctx_env.is_detected());
assert!(ctx_detected.is_detected());
assert!(!ctx_detected.is_env());
assert_eq!(ctx_env.as_env(), Some(&env));
assert_eq!(ctx_detected.as_detected(), Some(&detected));
}
#[test]
fn test_execution_context_ext() {
let contexts = vec![
ExecutionContext::Env(EnvContext::new().with_redesign_count(1)),
ExecutionContext::Detected(
DetectedContext::new()
.with_task_health(TaskHealth::AtRisk)
.detected_by("Layer1"),
),
ExecutionContext::Env(EnvContext::new().with_redesign_count(3)),
ExecutionContext::Detected(
DetectedContext::new()
.with_user_state("confused")
.detected_by("Layer2"),
),
];
assert_eq!(contexts.latest_env().unwrap().redesign_count, 3);
assert_eq!(
contexts.latest_detected().unwrap().detected_by,
vec!["Layer2"]
);
assert_eq!(contexts.all_envs().len(), 2);
assert_eq!(contexts.all_detected().len(), 2);
}
#[test]
fn test_timeline_chronological_order() {
let contexts = vec![
ExecutionContext::Env(
EnvContext::new().with_step_info(StepInfo::new("step_1", "First", "Agent1")),
),
ExecutionContext::Detected(DetectedContext::new().detected_by("Detector1")),
ExecutionContext::Detected(DetectedContext::new().detected_by("Detector2")),
];
let detected_list = contexts.all_detected();
assert_eq!(detected_list[0].detected_by, vec!["Detector1"]);
assert_eq!(detected_list[1].detected_by, vec!["Detector2"]);
}
}