todo-52-agent-benchmark-runner.md 7.9 KB

Agent Benchmark Runner Implementation Plan

Status: done

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Build a packaged benchmark CLI that runs deterministic mock or live OpenAI-compatible comparisons for both invocation modes and writes secret-safe JSON/Markdown reports.

Architecture: Add a benchmark application module for config, case catalog, run models, timing and aggregation; a reporting infrastructure module for redaction/rendering/atomic writes; and a thin presentation CLI. Each run uses DebugRuntime.start_session() with a temporary SQLite store and timing chat-client wrapper.

Tech Stack: Python 3.11+, asyncio, Pydantic, argparse, httpx-based existing OpenAI-compatible client, SQLite, pytest, uv.


Task 1: Benchmark configuration and case catalog

Files:

  • Create: src/agent_lab/application/benchmark.py
  • Create: tests/test_benchmark_config.py
  • Modify: tests/test_tool_invocation_comparison.py

  • [x] Write failing tests for strict schema version, URL validation, known case/mode IDs, positive runs, and rejection of secret fields.

  • [x] Verify RED with uv run pytest tests/test_benchmark_config.py -q.

  • [x] Implement strict Pydantic models BenchmarkConfig, BenchmarkTarget, BenchmarkCase, BenchmarkExpectation, and immutable built-in case catalog.

  • [x] Implement build_benchmark_request(case, mode, model) using the existing DebugRunRequest, identical params, and built-in enabled tools.

  • [x] Expose deterministic mock rounds from the production case catalog and refactor the existing comparison test to reuse the catalog instead of duplicating prompts/expectations.

  • [x] Run config and comparison tests, then commit with feat: add benchmark case catalog.

Task 2: Timing wrapper and isolated benchmark runner

Files:

  • Modify: src/agent_lab/application/benchmark.py
  • Create: tests/test_benchmark_runner.py

  • [x] Write failing tests for provider TTFT versus visible TTFT, per-call elapsed/usage, persisted wall time, detected events/sources, tool/fallback counts, semantic failures, partial-failure continuation, and temporary-database isolation.

  • [x] Verify RED with uv run pytest tests/test_benchmark_runner.py -q.

  • [x] Implement TimingChatClient around the existing stream protocol, recording first item, first message delta, usage, elapsed, and fallback classification.

  • [x] Implement deterministic MockBenchmarkChatClient that never constructs HTTP transport and emits mode-correct streams for the six cases.

  • [x] Implement BenchmarkRunner.run() over case → mode → iteration, creating/closing one runtime, chat client, and temporary SQLite store per run.

  • [x] Implement semantic evaluation from output, audit, and usage ledgers and return ordered BenchmarkRunResult records without stopping after an individual failure.

  • [x] Run runner/config/comparison tests, then commit with feat: run isolated agent benchmarks.

Task 3: Aggregation, reporting, and CLI

Files:

  • Create: src/agent_lab/infrastructure/benchmark_reporting.py
  • Create: src/agent_lab/presentation/benchmark_cli.py
  • Create: tests/test_benchmark_reporting.py
  • Create: tests/test_benchmark_cli.py
  • Modify: pyproject.toml

  • [x] Write failing tests for linear-interpolated p50/p95, failed-sample exclusion, low-sample warnings, redaction, JSON/Markdown consistency, atomic writes, CLI overrides, mock/live API-key requirements, exit codes 0/1/2, and continued report writing after run failures.

  • [x] Verify RED with uv run pytest tests/test_benchmark_reporting.py tests/test_benchmark_cli.py -q.

  • [x] Implement aggregation into one typed BenchmarkReport model shared by JSON and Markdown.

  • [x] Implement centralized redaction and 2 KiB error truncation before any rendered output.

  • [x] Implement one atomically published report bundle containing matching report.json and report.md files.

  • [x] Implement argparse with --config, --base-url, --model, repeatable --case/--mode, --runs, --output-dir, and --mock; apply CLI > JSON and environment-only API key.

  • [x] Register agent-lab-benchmark = agent_lab.presentation.benchmark_cli:main and verify --help.

  • [x] Run reporting/CLI/runner tests, then commit with feat: add benchmark reports and cli.

Task 4: Examples, documentation, and final verification

Files:

  • Create: benchmarks/single-target.example.json
  • Modify: .gitignore
  • Modify: README.md
  • Modify: docs/plans/todo-52-agent-benchmark-runner.md
  • Modify: docs/plans/todos.md

  • [x] Add a secret-free example covering both modes and all six cases; ignore outputs/benchmarks/.

  • [x] Document .env, config copy/edit, mock command, live command, output fields, exit codes, fairness controls, and the limits of scripted/mock adapters.

  • [x] Run agent-lab-benchmark --config benchmarks/single-target.example.json --mock --output-dir /tmp/agent-lab-benchmark and inspect both reports.

  • [x] Run focused benchmark tests, uv run pytest, CLI help, app import, node --check, and git diff --check.

  • [x] Perform specification review then code-quality review; add Todo 52.x rows for post-execution fixes.

  • [x] Record evidence and Workflow Evolution findings, mark Todo 52 done, and commit with docs: close benchmark runner todo.

Final Evidence

Verified on 2026-07-14 (Asia/Shanghai):

  • benchmark suite: 196 passed in 1.19s;
  • full suite: 601 passed in 3.67s, with one existing Starlette/httpx deprecation warning;
  • agent-lab-benchmark --help: exit 0;
  • application import prints Agent Lab;
  • node --check src/agent_lab/presentation/static/app.js: exit 0;
  • git diff --check: exit 0;
  • zero-network mock CLI: 12 attempted / 12 passed / 0 failed;
  • final JSON: /tmp/agent-lab-benchmark-final-20260714/20260713T194850Z/report.json;
  • final Markdown: /tmp/agent-lab-benchmark-final-20260714/20260713T194850Z/report.md;
  • both parallel-mode runs report parallel_events_overlapped=true;
  • both web-search runs report two model calls and one tool execution;
  • no mock run has missing token usage.

Specification and code-quality reviews found no remaining Critical or Important issues after Todos 52.1-52.13. The remaining non-blocking risks are documented below.

Residual Risks and Limits

  • No live provider request was run because no real benchmark target or credential was supplied; live latency, usage support, semantic adherence, and provider tool-stream compatibility still require operator verification.
  • The example uses one run per case, so its 60 p95 warnings are expected and the mock percentile values are not suitable for ranking architectures.
  • Atomic bundle publication uses a relative directory symlink and is verified on macOS; Windows symlink behavior is not verified.
  • An interruption inside mkdtemp() may leave an empty hidden bundle directory. A close failure during a narrow consumer-pause cancellation window may be logged as a secondary async-generator exception. Neither case changes the primary cancellation result or exposes a mixed public report.

Workflow Evolution Update

The requirement loop exposed three durable workflow lessons:

  • paired filesystem artifacts need one explicit atomic publication boundary; repeated two-file rollback fixes were replaced by a single report bundle;
  • benchmark plans must define clock boundaries, missing-data semantics, and observable concurrency proof before implementation, not only metric names and event counts;
  • parallel subagents need shared-contract integration checks when one task changes an output layout consumed by another task's tests.

These lessons are recorded in this task report and the benchmark design. No AGENTS.md change was made because the repository's existing PAOU, todo-first, TDD, per-todo commit, and post-review follow-up rules already caused the issues to be found and corrected; adding more global workflow rules would duplicate the current core process.