Era AI Engineer · self-contained submission

A measurement instrument, not a leaderboard.

This submission evaluates an agent as response = f(system_prompt, llm, tools | query), then extends the same measurement discipline to a three-agent chain. The important thing is not that a tiny smoke run proves a winner. It is that the code can vary the right components, collect traces, label what caused failures, and say exactly which claims are measured vs. designed.

Runtime
Python · PydanticAI
Eval backbone
pydantic_evals
Dataset
55 synthetic fixtures · 13 categories
Proof
API smokes · 313 tests
What to judge

The answer is the instrument, not a leaderboard.

What is actually built

  • Single-agent ablation: prompt × model × tools plus four Tier-1 axes.
  • Trace-aware evaluation: task success, tool accuracy, efficiency, trajectory, safety, state checks, latency, tokens, cost.
  • Chain evaluation: A→B→C with per-agent metrics, propagation, coupling, and gold injection.
  • Optimization design: Bayesian search over model/tool assignments, intentionally not executed in the smoke artifact.

What the smoke runs mean

  • Measured: real PydanticAI calls, generated JSON/Markdown reports, tests, tool sandbox behavior.
  • Directional: attribution percentages from 3 Part-1 cases and 8 chainable cases.
  • Designed: 10-model frontier search, broad provider comparison, GEPA prompt optimization.
  • Not hidden: no mock default results; local eval-echo for send_message is explicit workspace state.
System architecture

How the code turns a prompt/model/tool hypothesis into evidence.

The diagram below is the actual Part 1 path through the repository: synthetic fixture cases become a pydantic_evals dataset, the task function runs EraAgent, trace attributes feed deterministic/report evaluators, and AblationHarness aggregates the results into attribution.

Part 1: single-agent measurement pipeline dataset/golden.py 55 synthetic fixtures 13 task categories build_deterministic_dataset pydantic_evals Dataset/Case expected keywords + tools EraAgent / PydanticAI system_prompt variant model key + ModelSettings tool subset + tool schemas Trace + eval attributes tool calls, ok/error, latency tokens, model calls, state 7 ablation axes prompt · model · tools tool descriptions · temperature thinking effort · tool search Dataset.evaluate_sync runs make_task(EraAgent) for each config/case/repeat bounded by model/API timeouts Evaluators + AttributionReport TaskSuccess threshold=1.0 · tool Jaccard · LCS trajectory latency/tokens/cost · safety · environment state ANOVA-style variance + counterfactual tool probing
Design decision: deterministic evaluators are the baseline because they are cheap and reproducible. LLMJudge can add semantic judgement, but it does not replace the deterministic evidence trail.
The metrics

Thirteen metric families. Deterministic first, measured second, computed third.

Deterministic grading is reproducible and has no dependencies. The optional LLM judge augments — never replaces — deterministic grading. We report both scores rather than collapsing them.

Deterministic

  • TaskSuccess — response contains expected keywords (threshold=1.0)
  • ReconciledSuccess — blends keyword-overlap with LLM-judge verdict; flags disagreements (judge_overshoot, keyword_overshoot)
  • ToolCallAccuracy — Jaccard similarity between called and expected tools
  • ToolArgumentAccuracy — checks tool arguments, not just names (calculator expression equivalence, path/channel exact match, content contains)
  • TrajectorySequenceAccuracy — LCS ratio between actual and expected tool order
  • ToolUseEfficiency — successful tool calls / total tool calls
  • SafetyCompliance — attack success rate across 5 attack types
  • EnvironmentStateVerification — file/DB state matches expected state

Measured & Computed

  • LatencyPercentiles — p50, p95, p99, max, jitter
  • TokenEfficiency — tokens per successful task, waste rate
  • CostEfficiency — cost per successful task, waste rate
  • Reliability@k — fraction of k runs that all succeed
  • PerCaseSensitivity — hard_fail / tool_sensitive / model_sensitive / prompt_sensitive / robust

Cost and latency are cross-cutting — they apply to all three tiles. We treat them as production constraints that gate whether any configuration ships, not as sub-metrics of "tool effectiveness."

How to read the chain numbers: success is strict final-task pass/fail; quality is graded keyword overlap, so it can move even when success stays at 1.0. per-agent deltas trace which stage changed. propagation coefficients show how an upstream change travels downstream. coupling compares isolated reference-input performance with in-chain performance. Gold injection is only defined when final-task residual error exists; in the latest smoke it is undefined because final_score=1.0.
Beyond the three named components

The three named components are where you start — not where you stop.

The brief says identifying what else matters is part of the work. We identify two tiers beyond prompt, model, and tools.

Tier 1 · Configuration surface

Four more levers

Tool descriptions (detailed / minimal / ambiguous), temperature (0.0 / 0.3 / 0.7 / 1.0), thinking effort (low / medium / high), tool search (on-demand vs always-loaded). Each is ablatable and attributable, just like the three named components.

Tier 2 · Emergent behaviour

Measured and identified-not-measured

Measured: safety compliance, trajectory sequence accuracy, trajectory consistency, environment state verification, reliability@k. Identified but not measured: calibration, RAG faithfulness, output contract compliance. Naming what you don't measure is a strength.

Part 1 of 2

Evaluate a single agent — really evaluate it.

55 synthetic fixture cases across 13 categories. A 7-axis factorial matrix. Attribution that talks about each component, not just an overall score. And a per-case sensitivity classifier that separates tool-sensitive failures from model-sensitive ones.

Part 1

Single-agent ablation: what varied, what was measured, and what the smoke showed.

0.778
grand mean
Tool-sensitive cases (g16, x14, g14) — tools are load-bearing.
0.0247
total variance
Non-degenerate: tool-ablation configs score differently.
tools 100%
attribution
Tools are the sole source of variance; model/prompt = 0%.
313
tests passing
Regression coverage across fixes, evaluators, and tools.

Interpreting the Part 1 result

  • It is not a model leaderboard: the smoke used one primary evaluated model, siliconflow:deepseek-ai/DeepSeek-V4-Flash.
  • Non-degenerate ANOVA: tool-sensitive cases (g16 datetime, x14 db_state, g14 file_operations) produce variance=0.0247 across 6 configs. Tools account for 100% of variance — removing tools causes failure, so T2/T3 configs score differently.
  • Counterfactual probes confirm: this smoke's per-tool removals are flat — removing read_file, calculator, or execute_python has delta 0.0. The variance comes from full/minimal/empty toolset configs; g16 is a hard fail (datetime — the model can't infer the current time without the tool), while g14 and x14 stay robust under the probed removals.
  • ReconciledSuccess: all 3 cases score 1.0; the separate keyword and LLMJudge assertions also pass. No semantic tie-break changed this case selection.

Where this lives in code/results

Harnessera_eval/ablation.py
Agentera_eval/agent.py
Evaluatorsera_eval/eval/evaluators.py + report_evaluators.py
Artifactera_results/part1.md, part1.json, part1_evals_report.json
The honest part: ANOVA decomposes variance, but variance explained is not causal contribution. If you test 10 models and 1 prompt, ANOVA says "model explains 90%." The attribution is an artifact of the experimental design. We report it as such — and pair it with counterfactual probing, which is causal. Two-way interaction terms (prompt×model, model×tools, prompt×tools) are reported because the components are not additive: if prompt×model interaction is 94% of variance, "prompt quality" and "model quality" are joint properties of the pair, not separable scalars.
Part 2 of 2

Now make the whole chain good — fast, and cheap.

Three agents in series: Research → Analyse → Synthesize. Map how quality propagates, attribute failures to the agent that caused them, and design the optimisation strategy for the model × tool configuration space.

Part 2

The chain is evaluated as three independent agent instances, not one blob.

Each chain step has its own prompt, model, and tool subset. Golden chain mode decomposes chainable synthetic fixture cases into expected A/B/C intermediate outputs so the framework can ask whether failures start upstream, downstream, or only at the final answer.

Part 2: actual chain + propagation analysis g25–g37 chainable fixture cases Agent A · Research prompt: gather findings model: independently swappable tools: web_search, fetch_url, get_current_datetime Agent B · Analyse prompt: analyze findings model: independently swappable tools: calculator, execute_python, retrieve_documents Agent C · Synthesize prompt: final report model: independently swappable tools: write_file, send_message tool_ok gates final status final output TaskSuccess + quality Variant families model: swap A/B/C independently tools: Agent A add/remove/replace prompt: Agent A minimalist PropagationAnalyzer per-agent deltas · final deltas propagation coefficients · coupling first-failure heuristic + intervention override Q1–Q4 answers model swaps: Δsuccess=0.000 (baseline at ceiling) tool swaps: A execute_python variants Δsuccess=-1.0 gold injection: undefined (baseline final_score=1.0)
1.0
baseline success
All 8 chainable cases pass (g25–g27, g33–g37).
0.945
mean quality
g25 at 0.889, g34 at 0.667 — two cases below ceiling. 6 of 8 at 1.0.
measurable
tool-swap deltas
Removing query_database degrades g33–g37 by 0.333–0.667.
undef.
gold attribution
Aggregate final_score=1.0 → no task-failure residual. Quality gaps in per-case analysis.

Observed Part 2 deltas

  • Tool-swap variants produce measurable deltas: removing query_database from Agent A degrades quality on g33 (0.667), g34 (0.333), g35 (0.667), g36 (0.333), g37 (0.667) — confirming query_database is load-bearing for database cases.
  • Tool replacement is worse than removal: replacing query_database with calculator degrades g33 to 0.667, g34 to 0.333, g36 to 0.333 — the agent tries to use the wrong tool and produces lower quality than having no tool at all.
  • Model C-swap produces broad quality deltas: C-position swaps to Llama-3.3-70B degrade g26 (0.667), g33 (0.667), g35 (0.667), g36 (0.667), g37 (0.667) — the synthesis agent is model-sensitive across multiple case types.
  • Gold injection (Q4): aggregate final_score=1.0 (all chains succeed) → attribution is undefined — no task-failure residual to attribute. Quality gaps (g25 0.889, g34 0.667) are captured in per-case analysis, not gold injection.

Where this lives in code/results

Chainera_eval/eval/chain_eval.py
Golden modeget_chainable_cases() + build_chain_from_golden_case()
Optimizationera_eval/optimization/design.py (method only)
Artifactera_results/part2_golden.md, part2_golden.json
Q1 · Model swap

One model changes — what happens to the final output?

Swap one agent's model, keep the other two unchanged. Measure Δ accuracy, Δ cost, Δ latency for the whole chain. The asymmetry across the three Δfinal values is each position's leverage.

Q2 · Tool swap

One tool is swapped — what changes?

Add, remove, or replace a tool in one agent. Measure the effect on that agent and on everything downstream. Identifies load-bearing vs ornamental tools in each chain position.

Q3 · Downstream coupling

Are downstream agents affected by upstream changes?

Coupling coefficient = 1 − (score_in_chain / score_isolated). 0 = robust, 1 = fully dependent. Returns null when insufficient data — not 0.0. Compounding factor = chain_acc / (acc_A × acc_B × acc_C): >1.0 means the chain recovers, ~1.0 means errors are independent, <1.0 means errors amplify.

Q4 · Attribution

How do you evaluate rigorously?

Two methods, both labeled: first-failure heuristic (observational) with intervention-aware override, and gold injection (causal) — a lightweight version of structural causal model intervention.

Tools and model pool

The search space is explicit: ten tools, ten models, three chain positions.

Fixed 10-tool set

Networkweb_search, fetch_url — public HTTP(S), SSRF/redirect checks.
Retrievalretrieve_documents — deterministic built-in corpus.
Computecalculator, execute_python — AST-restricted Python subprocess.
Dataquery_database — SELECT-only SQLite authorizer.
Stateread_file, write_file — workspace sandbox only.
Notifysend_message, get_current_datetime — webhook or local eval-echo log.

10-model design pool

ProprietaryGPT-5.4, Claude Sonnet 4.6, Gemini 2.5 Flash.
Large openDeepSeek V4 Flash, GPT-OSS 120B, Qwen3 Coder.
≤120B openGemma 4 31B, GPT-OSS 20B, Nemotron 3 Nano.
MoE tradeoffNemotron 3 Super: 120B total / 12B active, included for active-parameter economics.
SourceMODEL_POOL in era_eval/agent.py carries provider, params, context, price, latency, and why.
Optimization claim: the full chain search is (10 models × 210 tool subsets)3, roughly one trillion configurations. The submission provides the Bayesian optimization method and smoke instrumentation, not a full frontier run.
The optimisation

Bayesian search over a trillion configurations.

The search space is (10 × 2^10)^3 ≈ 1 trillion configurations. Brute force is not an option. The deliverable is the method, not a run — the brief is explicit. The design is on paper with full citations.

for each agent i in {A, B, C}, choose
modeli ∈ pool(10), toolsi ⊆ toolset(10)
to maximise accuracy(agenti) and accuracy(chain)
while minimising latency(chain) and cost(chain)
Phase 1 · Probe

30 space-filling configs

Structured seeds (all-frontier, all-small, role-optimised, tool extremes) + Latin Hypercube Sampling. Run each 3× for stochasticity.

Phase 2 · Surrogate

Gaussian Process

Matérn 5/2 kernel. Hamming distance for categorical (model) dims, Euclidean for binary (tool) dims. Multi-task GP predicts all objectives jointly.

Phase 3 · Acquire

ParEGO / qNEHVI

ParEGO traces the Pareto frontier. Production executor: BoTorch + Ax with qNEHVI (noisy multi-objective) or qLogNEHVI (numerical stability).

Phase 4–6 · Frontier

Identify, validate, stretch

Non-dominated configs after ~100 evals. Re-evaluate top-5 with N=10. Phase 6 (stretch): GEPA prompt optimisation — Genetic-Pareto reflective mutation.

Full design, expected outcome, and trade-off characterisation in PART2_DESIGN.md. Citations to Mockus, Knowles, Daulton, Ament, Gardner, Sacks, McKay, and the GEPA paper in REFERENCES.md.

Evidence boundary

What is measured, what is implemented, and what is only designed.

Measured smokePart 1: 3 cases, 6 configs, 1 primary model. Part 2: 8 chainable fixture cases, 1 repeat, variant families. Generated under era_results/.
Dataset boundary55 hand-written synthetic fixture cases. No prompts name tools explicitly. 8 sequence-graded, 21 arg-checked, 15 state-checked. Good for smoke, regression, tool coverage, and evaluator instrumentation; not hidden, not human-validated, and not a frontier-grade benchmark.
ImplementedCLI flags, evaluator/report pipeline, tool sandboxing, model timeout handling, chain propagation, coupling, gold injection, BH-FDR helper.
Designed10-model/10-tool Bayesian optimization frontier, role-aware model assignment, GEPA prompt optimization stretch goal.
Known limitsLow sample size, keyword-overlap strictness, one-model Part 1 smoke, model specs require provider refresh before production use.
Decisions and assumptions

The scoping choices are part of the answer.

Correctness

Strict first, semantic second

TaskSuccess uses expected-keyword threshold 1.0 so success is reproducible. The limitation is acknowledged; LLMJudge and future embedding grading address paraphrases.

Attribution

Variance is not causation

ANOVA-style attribution explains observed variance in the experimental design. Counterfactual tool probes and gold injection are the causal complements.

Safety

15 of 55 cases, 5 attack types, ASR gates production

15 of 55 synthetic fixture cases are safety cases (PII leakage, prompt injection, harmful content, privilege escalation, overrefusal). SafetyCompliance measures Attack Success Rate across 5 attack types and 10 harm categories. A model with 95% task_success but 40% ASR is unfit for production, regardless of how well it does on other tasks.

Cost

Production constraints are first-class

Latency, tokens, and cost are captured because a configuration that is slightly more accurate but 10× slower or costlier may not be deployable.

Full assumption register: ASSUMPTIONS.md. Methodology: APPROACH.md and PART2_DESIGN.md.

Reproduction

Run the bounded artifacts without changing the submission story.

# install + configure
pip install -r requirements.txt
cp .env.example .env  # fill in provider keys

# Part 1 smoke artifact
python3 run_eval_fast.py --part 1 --cases 3 --tool-sensitive --repeats 1 --concurrency 1

# Part 2 golden-chain smoke artifact
python3 run_eval_fast.py --part 2 --chain-cases 8 --repeats 1

# tests
python3 -m pytest -q

CLI flags preserved

--casesLimit Part 1 cases for bounded smoke runs.
--concurrencyControl parallel API-backed evaluation.
--tier1Enable tool descriptions, temperature, thinking effort, and tool search axes. (run_eval.py)
--golden-chainRun Part 2 through chainable fixture cases instead of a single request. (run_eval.py)
--outputChoose result output path. (run_eval.py)
--swap-modelOverride the Part 2 model used for swap experiments. (run_eval_fast.py)
--tool-sensitiveSelect tool-sensitive cases (file_ops, multi_tool, datetime, notification, db_state) for non-degenerate ANOVA. (run_eval_fast.py)
--chain-casesNumber of chainable cases to run in Part 2 (default 2, max 8). Use 8 to break the success ceiling. (run_eval_fast.py)
What we could do

Depth, not breadth — with more time.

Eight items that would make the attribution percentages defensible, not directional. A frontier lab would require all eight before trusting the smoke results.

1 · Inter-annotator agreement

Have 3 people grade the same cases

Report Cohen's kappa. The fixture suite is hand-written; without agreement, "correct" is a single opinion.

2 · Semantic similarity grading

Replace keyword overlap with embeddings

Cosine similarity catches correct paraphrases that keyword overlap scores 0.0. The optional LLM judge exists to catch this; embeddings would make it the default.

3 · N=30 on top-5 configs

Tight confidence intervals

N=3 is the minimum for meaningful CIs. N=30 on the Pareto-optimal configs would make attribution claims defensible, not directional.

4 · SQL semantic equivalence

Full SQL argument normalization

ToolArgumentAccuracy checks calculator expressions (evaluate-and-compare), file paths, channel names, and SQL key terms (table/filter/column via contains). Full SQL semantic equivalence — where SELECT * FROM products WHERE category='hardware'SELECT * FROM products WHERE category = 'hardware' — is a harder normalization problem left as future work.

5 · Open-ended query evaluation

Cases with multiple acceptable answers

All 55 cases have single correct answers. Real agents face queries with multiple acceptable answers, graded by rubric.

6 · Run the optimisation

Execute the Bayesian search

The 6-phase design is on paper. A production executor with BoTorch + Ax would trace the actual Pareto frontier — the brief says this is optional, but it's the obvious next step.

7 · Multiple testing correction

Wire BH-FDR into attribution reports

benjamini_hochberg_fdr() is implemented in stats_utils.py but never called. With 7 per-case evaluators × 20+ configs, 350+ p-values run uncorrected. Auto-applying BH-FDR would control the false discovery rate instead of reporting raw p-values that overstate significance.

8 · Alternative chain topologies

Fan-out, fan-in, iterative refinement

Part 2 tests one topology: research→analyse→synthesize. Real agent teams use fan-out (parallel sub-agents), fan-in (merge multiple sources), and iterative refinement loops. Different topologies may show different error propagation patterns — the current propagation coefficient is measured for one shape only.

References

Every design decision traces to a published method.

Selected highlights below. The full citation list — 40+ papers spanning experimental design, Bayesian optimisation, prompt optimisation, multi-agent attribution, and evaluation metrics — is in REFERENCES.md.

Experimental design & attribution
  • Fisher (1935). The Design of Experiments. Oliver & Boyd. — Factorial ablation design.
  • Welch (1947). "The Generalization of Student's Problem." Biometrika 34(1/2). — Welch's t-test for unequal variance.
  • Wilson (1927). "Probable Inference." JASA 22(154). — Wilson score interval for small-N CIs.
  • Benjamini & Hochberg (1995). "Controlling the False Discovery Rate." JRSS B 57(1). — FDR correction.
  • CapaBench: Yang et al. (2025). arXiv:2502.00510 — Shapley-based attribution (frontier alternative, considered not implemented).
Bayesian optimisation
  • Knowles (2006). "ParEGO." EMO 2005. — Multi-objective scalarization for Pareto frontier.
  • Daulton et al. (2021). "Parallel BO of Multiple Noisy Objectives." NeurIPS 2021. arXiv:2105.08195 — qNEHVI.
  • Ament et al. (2023). "BO via Maximizing Log-Improvement." arXiv:2310.20708 — qLogNEHVI.
  • McKay et al. (1979). "Latin Hypercube Sampling." Technometrics 21(2). — LHS for space-filling initial design.
Prompt optimisation & multi-agent attribution
  • GEPA: Agrawal et al. (2025). ICLR 2026 Oral. arXiv:2507.19457 — Genetic-Pareto reflective mutation (Phase 6 stretch goal).
  • Who&When: Zhang et al. (2025). ICML 2025. — Standard benchmark for multi-agent failure attribution.
  • CAR. arXiv:2606.08275 (2026) — Causal agent replay via SCM do(·) — gold standard our gold injection approximates.
Runtime & evaluation backbone
  • Pydantic AI. ai.pydantic.dev — Agent runtime.
  • Pydantic Evals. pydantic.dev — Dataset / Case / Evaluator / ReportEvaluator backbone.
  • τ-bench: Yao et al. (2025). — reliability@k consistency metric; environment state verification.
Document map

Everything behind this page.

Every document opens on GitHub, where markdown, tables, and code blocks render in full. The full source for this submission lives at github.com/aryaminus/era-eval.