use std::sync::Arc;
use anyhow::Result;
use async_trait::async_trait;
use brainwires_agents::eval::{EvaluationCase, TrialResult, ndcg_at_k};
use brainwires_agents::reasoning::ComplexityScorer;
use brainwires_core::message::{ChatResponse, Message, StreamChunk};
use brainwires_core::provider::{ChatOptions, Provider};
use brainwires_core::tool::Tool;
use futures::stream::BoxStream;
struct StubProvider;
#[async_trait]
impl Provider for StubProvider {
fn name(&self) -> &str {
"stub"
}
async fn chat(
&self,
_messages: &[Message],
_tools: Option<&[Tool]>,
_options: &ChatOptions,
) -> Result<ChatResponse> {
unreachable!("StubProvider::chat — score_heuristic does not call the provider")
}
fn stream_chat<'a>(
&'a self,
_messages: &'a [Message],
_tools: Option<&'a [Tool]>,
_options: &'a ChatOptions,
) -> BoxStream<'a, Result<StreamChunk>> {
Box::pin(futures::stream::empty())
}
}
pub struct ComplexityHeuristicCase;
#[async_trait]
impl EvaluationCase for ComplexityHeuristicCase {
fn name(&self) -> &str {
"complexity_heuristic_ordering"
}
fn category(&self) -> &str {
"reasoning"
}
async fn run(&self, trial_id: usize) -> anyhow::Result<TrialResult> {
let start = std::time::Instant::now();
let scorer = ComplexityScorer::new(Arc::new(StubProvider), "stub");
let t1 = "Design a fully distributed concurrent async architecture with security validation across multiple components";
let t2 =
"Refactor and optimize the performance of multiple components carefully and thoroughly";
let t3 = "Fix the authentication bug found in the user login module";
let t4 = "Print hello";
let tasks = [t1, t2, t3, t4];
let ground_truth: Vec<usize> = vec![3, 2, 1, 0];
let scores: Vec<f64> = tasks
.iter()
.map(|t| scorer.score_heuristic(t).score as f64)
.collect();
let ndcg = ndcg_at_k(&scores, &ground_truth, 4);
let ms = start.elapsed().as_millis() as u64;
if ndcg >= 0.99 {
Ok(TrialResult::success(trial_id, ms)
.with_meta("ndcg", serde_json::json!(ndcg))
.with_meta("scores", serde_json::json!(scores)))
} else {
Ok(TrialResult::failure(
trial_id,
ms,
format!(
"ComplexityHeuristic NDCG@4={ndcg:.4} < 0.99 — \
heuristic does not correctly order tasks by complexity. \
scores={scores:?}"
),
)
.with_meta("ndcg", serde_json::json!(ndcg))
.with_meta("scores", serde_json::json!(scores)))
}
}
}
pub fn reasoning_eval_suite() -> Vec<Arc<dyn EvaluationCase>> {
vec![Arc::new(ComplexityHeuristicCase)]
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_complexity_heuristic_passes() {
let case = ComplexityHeuristicCase;
let result = case.run(0).await.unwrap();
assert!(
result.success,
"ComplexityHeuristicCase failed: {:?}",
result.error
);
}
}