pub mod matchers;
pub mod model;
use crate::errors::diagnostic::Diagnostic;
use crate::storage::Store;
pub struct EpisodeGraph {
pub episode_id: String,
pub steps: Vec<crate::storage::rows::StepRow>,
pub tool_calls: Vec<crate::storage::rows::ToolCallRow>,
}
pub fn verify_assertions(
store: &Store,
run_id: i64,
test_id: &str,
assertions: &[model::TraceAssertion],
) -> anyhow::Result<Vec<Diagnostic>> {
let graph_res = store.get_episode_graph(run_id, test_id);
match graph_res {
Ok(graph) => matchers::evaluate(&graph, assertions),
Err(e) => {
let is_unit_test = assertions.iter().all(|a| match a {
model::TraceAssertion::ArgsValid { test_args, .. } => test_args.is_some(),
model::TraceAssertion::SequenceValid {
test_trace,
test_trace_raw,
..
} => test_trace.is_some() || test_trace_raw.is_some(),
model::TraceAssertion::ToolBlocklist {
test_tool_calls, ..
} => test_tool_calls.is_some(),
_ => false,
});
if is_unit_test {
let dummy = EpisodeGraph {
episode_id: "unit_test_mock".into(),
steps: vec![],
tool_calls: vec![],
};
return matchers::evaluate(&dummy, assertions);
}
if e.to_string().contains("E_TRACE_EPISODE_MISSING") {
match store.get_latest_episode_graph_by_test_id(test_id) {
Ok(latest_graph) => return matchers::evaluate(&latest_graph, assertions),
Err(fallback_err) => {
return Err(anyhow::anyhow!("E_TRACE_EPISODE_MISSING: Primary query failed ({}), Fallback failed: {}", e, fallback_err));
}
}
}
Err(e)
}
}
}