1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//! Concurrent Benchmark Harness
//!
//! High-throughput benchmark runner for evaluating LLM performance with
//! bounded concurrency. Designed for local vLLM/sglang endpoints that can
//! handle 32+ concurrent streams.
//!
//! # Architecture
//!
//! ```text
//! ┌────────────┐ ┌──────────────┐ ┌───────────────┐
//! │ BenchTask │────►│ HarnessRunner│────►│ HarnessReport │
//! │ + Evaluator│ │ (semaphore- │ │ (latency p50/ │
//! │ │ │ bounded I/O)│ │ p95/p99, pass│
//! └────────────┘ └──────────────┘ │ rate, tok/s) │
//! │ └───────────────┘
//! HarnessConfig
//! (endpoint, model,
//! concurrency, timeout)
//! ```
//!
//! - [`HarnessConfig`]: Endpoint URL, model name, concurrency limit, and
//! per-request timeout.
//! - [`BenchTask`] + [`TaskEvaluator`]: Each task carries a prompt and an
//! evaluator that scores the response. Evaluators are pluggable -- implement
//! the trait or use a built-in.
//! - [`HarnessRunner`]: Sends all tasks concurrently (bounded by a tokio
//! semaphore), collects streaming responses, and runs evaluators.
//! - [`HarnessReport`]: Aggregated results -- throughput (tokens/sec), latency
//! percentiles (p50/p95/p99), per-task pass/fail with [`EvalDetail`]s.
//! Can be serialized to JSON and written to disk.
//!
//! # Built-in evaluators
//!
//! - [`KeywordEvaluator`]: Passes if all specified keywords appear in the response.
//! - [`JsonEvaluator`]: Passes if the response is valid JSON containing required fields.
//! - [`NoopEvaluator`]: Always passes -- useful for throughput-only benchmarks.
//!
//! # Example
//!
//! ```ignore
//! use selfware::bench_harness::*;
//!
//! let config = HarnessConfig::new("http://localhost:8000/v1", "qwen3.5-27b");
//! let runner = HarnessRunner::new(config)?;
//!
//! let tasks = vec![
//! BenchTask {
//! id: "simple".into(),
//! description: "Basic math".into(),
//! messages: vec![Message::user("What is 2+2?")],
//! evaluator: Box::new(KeywordEvaluator::new(vec!["4".into()])),
//! },
//! ];
//!
//! let report = runner.run(tasks).await?;
//! println!("Pass rate: {:.1}%", report.pass_rate() * 100.0);
//! report.write_to_dir(Path::new("bench_results"))?;
//! ```
pub use HarnessConfig;
pub use HarnessReport;
pub use HarnessRunner;
pub use ;