use eval_core::{EvalCase, Harness, RunArtifacts, Scorer, ToolCall, run_eval};
#[derive(Debug, Default)]
struct World {
actions: Vec<String>,
}
#[derive(Debug, Default, serde::Deserialize)]
struct Setup {
seed: String,
}
#[derive(Debug, serde::Deserialize)]
struct Expect {
contains: String,
}
struct DemoHarness;
impl Harness for DemoHarness {
type World = World;
type Setup = Setup;
fn setup(&self, setup: &Self::Setup) -> Self::World {
World {
actions: vec![setup.seed.clone()],
}
}
fn run(&self, instruction: &str, world: &mut Self::World) -> anyhow::Result<RunArtifacts> {
world.actions.push(format!("did:{instruction}"));
world.actions.push("cleanup".to_owned());
Ok(RunArtifacts::new()
.with_tool_calls(vec![
ToolCall::new("perform", serde_json::json!({ "instruction": instruction })),
ToolCall::new("cleanup", serde_json::json!({})),
])
.with_final_text(format!("done: {instruction}"))
.with_tokens(42))
}
}
struct DemoScorer;
impl Scorer for DemoScorer {
type World = World;
type Expect = Expect;
fn score(
&self,
expect: &Self::Expect,
_artifacts: &RunArtifacts,
world: &Self::World,
) -> (String, bool) {
let passed = world.actions.iter().any(|a| a.contains(&expect.contains));
(format!("contains({:?})", expect.contains), passed)
}
}
fn expect(contains: &str) -> Expect {
Expect {
contains: contains.to_owned(),
}
}
fn main() {
let cases: Vec<EvalCase<Setup, Expect>> = vec![
EvalCase {
name: "passing".to_owned(),
instruction: "build a wall".to_owned(),
setup: Setup {
seed: "ready".to_owned(),
},
expect: vec![expect("did:build a wall"), expect("ready")],
},
EvalCase {
name: "failing".to_owned(),
instruction: "dig a hole".to_owned(),
setup: Setup::default(),
expect: vec![expect("did:dig a hole"), expect("teleport")],
},
];
let report = run_eval(&DemoHarness, &DemoScorer, &cases);
println!("{report}");
assert_eq!(report.total(), 2, "ran both cases");
assert_eq!(report.passed(), 1, "exactly one case passed");
let passing = &report.outcomes[0];
assert!(passing.passed, "the first case should pass");
assert_eq!(passing.predicates.len(), 2);
assert!(passing.predicates.iter().all(|(_, p)| *p));
assert_eq!(
passing.tokens,
Some(42),
"harness-reported token count flows through"
);
assert_eq!(passing.tool_calls.len(), 2);
let failing = &report.outcomes[1];
assert!(!failing.passed, "the second case should fail");
assert!(failing.predicates[0].1, "did:dig a hole was recorded");
assert!(!failing.predicates[1].1, "teleport was never recorded");
println!("\nminimal example OK: 1 passed, 1 failed as expected");
}