Skip to content

chore: add v1 end-to-end eval test suite - #1609

Merged
mikasenghaas merged 11 commits into
feat/nano-as-v1from
chore/v1-e2e-tests
Jun 10, 2026
Merged

chore: add v1 end-to-end eval test suite#1609
mikasenghaas merged 11 commits into
feat/nano-as-v1from
chore/v1-e2e-tests

Conversation

@mikasenghaas

@mikasenghaas mikasenghaas commented Jun 10, 2026

Copy link
Copy Markdown
Member

Summary

End-to-end tests for the v1 stack under tests/v1/real eval runs (the same path as uv run eval) with the smallest settings that still exercise it, asserting on the resulting Trace, rather than unit-testing components. Also folds in the framework fixes the suite surfaced (user-simulator placement/reachability, a SUPPORTS_USER_SIM capability flag).

Tests

  • test_e2e.py — reward-1 runs on trivial tasksets across the harness × runtime matrix (harness × runtime fixtures): built-in harnesses (default, rlm) × runtimes (subprocess/docker/prime; modal excluded).
    • single-turn (echo), multi-turn (echo-multi, user-sim), multi-turn + tools (glossary), agentic (echo-agentic, bash).
    • capability-gated: the tools test expects a harness without SUPPORTS_TASK_TOOLS (rlm) to be rejected (raise); the multi-turn test skips a harness without SUPPORTS_USER_SIM (rlm).
    • server-runtime matrix: test_task_tools_own_runtime / test_user_own_runtime run a tool server / the user-sim in its own runtime (subprocess/docker/prime), agent on subprocess.
  • test_legacy.py — v0 backwards-compat: echo-v0 (single) + echo-multi-v0 (multi) run through the legacy bridge and match a native v1 run's output shape.
  • test_configs.py — every root configs/*.toml parses into EvalConfig.
  • tests/v1/fixtures/ — deterministic, self-contained fixture tasksets/envs (no dataset/Dockerfile/install), resolved by id via pytest's pythonpath: echo-v1, echo-multi-v1 (container-safe user-sim), echo-agentic-v1 (bash writes a file, verified in the runtime), echo-v0, echo-multi-v0.

Running the tests

These are real eval runs, so they need a model API key (PRIME_API_KEY / OPENAI_API_KEY); without one the e2e-marked tests skip (config parsing still runs).

# Fast (default tier): default harness × subprocess + v0 legacy + config parsing (~20s)
uv run pytest tests/v1 -m "not slow" -n auto

# Full matrix: adds docker + prime runtimes, the rlm harness, and own-runtime tool/user-sim servers
# (docker needs the daemon — if you're not in the `docker` group, wrap it: sg docker -c '...')
sg docker -c 'uv run pytest tests/v1 -n auto'

# Slices
uv run pytest tests/v1/test_configs.py          # config parsing only (no API key needed)
uv run pytest tests/v1 -m prime                 # only the prime-runtime variants
uv run pytest tests/v1 -k single_turn -n auto   # one task across the matrix

-n auto runs in parallel (pytest-xdist). Markers: e2e (needs a model key), slow (docker/prime/rlm), prime (prime-runtime variants).

Framework changes folded in

  • SUPPORTS_USER_SIM — a Harness capability flag (default harness opts in; rlm can't drive a user-sim — single-instruction interface, no message history).
  • User-simulator runs in its own runtime, reached host-side. It's driven by the framework on the host, so it ran colocated in the agent's runtime with a localhost URL — unreachable when the agent is a remote prime sandbox (ConnectError / 421). Now serve_user runs it in its own runtime (host subprocess by default, or its own sandbox via TasksetConfig.user.runtime) and publishes the port back to the host (serve_tools host_reachable: a remote sandbox's public_url, else localhost).
  • UserConfig(runtime) on TasksetConfig; serve_tools host_reachable.
  • New pytest markers: e2e, prime.

Notes

  • harbor hello-world can't be used here — it ships a Dockerfile, and harbor_v1 refuses to build Dockerfiles; the echo-agentic fixture covers the agentic case instead.
  • A tool/user-sim in its own prime sandbox needs a region that supports port exposure; the default doesn't, so those server-runtime cases skip (skip_if_unexposable) with a TODO at prime.public_url to lift the limit.

Verification

  • Full matrix (subprocess/docker/prime, all tasks): 34 passed, 3 skipped (rlm user-sim), 0 failed (~40s, -n auto).
  • docker server-runtime cases pass; prime server-runtime cases skip (port-exposure region). ruff check + ruff format --check clean.

Note

Medium Risk
Rollout/user-sim wiring changes affect multi-turn evals on remote runtimes; new e2e tests need API keys and optional docker/prime infra but do not alter production eval configs by default.

Overview
Adds tests/v1/ end-to-end coverage that runs real evals (same path as uv run eval) on tiny fixture tasksets and asserts on Trace outcomes, plus pytest wiring (pythonpath for fixtures, e2e / prime markers, API-key skip).

Framework fixes the suite drove: user simulators no longer run colocated in the agent runtime—they use TasksetConfig.user.runtime (default host subprocess), with serve_tools(..., host_reachable=True) so the host can reach them when the agent is remote. Adds harness SUPPORTS_USER_SIM (default harness opts in). Rollout passes config.user.runtime into serve_user.

E2E matrix spans harness × runtime (single/multi-turn, tools, bash agentic, tool/user in own runtime); legacy bridge shape tests and root EvalConfig TOML parsing included.

Reviewed by Cursor Bugbot for commit c4f8300. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add v1 end-to-end eval test suite with configurable user simulator runtimes

  • Adds a comprehensive e2e test suite under tests/v1/ covering single-turn, multi-turn, agentic, and legacy v0-bridge scenarios using parameterized runtimes and harnesses.
  • Introduces fixture tasksets (echo_v1, echo_multi_v1, echo_agentic_v1) and legacy v0 environments (echo_v0, echo_multi_v0) used as test targets.
  • Changes serve_user in user.py to accept a RuntimeConfig and spin up a dedicated runtime for the user simulator, rather than colocating it with the agent runtime.
  • Adds UserConfig to TasksetConfig in taskset.py so tasksets can declare a separate user runtime (defaults to subprocess).
  • Behavioral Change: user simulators now run in their own runtime and are exposed via a host-reachable URL; previously they ran inside the agent runtime.

Macroscope summarized c4f8300.

mikasenghaas and others added 11 commits June 10, 2026 20:45
- e2e reward-1 runs across the runtime matrix (subprocess/docker/prime, modal excluded): single-turn (echo), multi-turn (alphabet-sort), multi-turn + tools (glossary), agentic (agentic-echo: bash writes a file, verified in the runtime)
- v0 backwards-compat: reverse_text + alphabet_sort bridged, shape parity vs a v1 run
- test_configs: every root configs/*.toml parses as EvalConfig
- echo + agentic-echo fixture tasksets (deterministic, no dataset/Dockerfile)
- conftest: run_v1/run_v0 helpers (greedy temperature=0, generous caps), runtime fixture, e2e + prime markers, skip-without-API-key, on-demand v0 install

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ess tests

- move echo-v1 + agentic-echo-v1 out of the test dir into tests/v1/fixtures, resolved by id via pytest's pythonpath ini (drops the conftest sys.path insert)
- test_harnesses.py: run echo (single-turn) and glossary (multi-turn + tools) under default + compact; assert rlm (no task-tool support) is rejected when paired with a tools taskset

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…RTS_TASK_TOOLS

- fold test_harnesses into test_e2e: the trivial tasks fan across the harness x runtime matrix (built-in default + rlm; compact is an example harness, excluded; rlm marked slow as it installs an agent binary)
- the tools test reads each harness's SUPPORTS_TASK_TOOLS to expect a raise (rlm) vs a run (default), instead of a separate hardcoded test
- alphabet-sort: similarity_power=1 (drop power scaling) so a near-perfect sort isn't sharply penalized

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…un helpers

- add v0 echo fixtures (echo-v0 SingleTurnEnv, echo-multi-v0 MultiTurnEnv); the legacy tests use them instead of example envs, so the v0 path is exercised deterministically
- drop ensure_v0: the legacy bridge imports a fixture by id off pythonpath (no runtime uv pip install, no environments/ dependency), same as the v1 fixtures
- inline the run_v1/run_v0 helpers into their fixtures

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-> nodes)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…user-sim fixture

- add SUPPORTS_USER_SIM ClassVar on Harness (default False; the default harness opts in) - a user simulator is a distinct capability from task MCP tools (rlm supports neither: it takes a single instruction, no message history)
- e2e: container-safe echo-multi-v1 user-sim fixture (vf.User shipped as a uv script, staged + run via uv in any runtime); the multi-turn test is gated by SUPPORTS_USER_SIM (skips rlm)
- generalize the test capability lookup to harness_supports(id, flag)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The user simulator is driven by the framework on the host (connect_user), not by the model. It was served colocated in the agent's runtime with a localhost URL, which the host can't reach when the agent runs in a remote prime sandbox (ConnectError; via the agent tunnel, a 421). Now serve_user runs it in its OWN runtime (host subprocess by default, or its own sandbox via TasksetConfig.user.runtime) and publishes the port back to the host (serve_tools host_reachable: a remote sandbox's public_url, else localhost).

- add UserConfig(runtime) to TasksetConfig; serve_tools gains host_reachable for a host-consumed colocated server
- e2e: the multi-turn user-sim test now passes on prime; add a test for the user-sim in its own (docker) sandbox

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- server_runtime fixture + test_task_tools_own_runtime / test_user_own_runtime: a tool/user-sim server in its OWN runtime (subprocess/docker/prime), agent on subprocess
- skip_if_unexposable: skip the prime server case when the sandbox region can't publish a port (a known prime infra limit, surfaced by the matrix)
- TODO in prime.public_url to lift that limit (then drop the skip)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mikasenghaas
mikasenghaas marked this pull request as ready for review June 10, 2026 22:28
@mikasenghaas
mikasenghaas merged commit 5268e28 into feat/nano-as-v1 Jun 10, 2026
4 checks passed
@macroscopeapp

macroscopeapp Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

While labeled as adding a test suite, this PR includes production changes that fundamentally alter how user simulators are hosted - they now run in their own isolated runtime rather than being colocated with the agent. This new runtime isolation capability and the associated configuration changes (UserConfig, host_reachable parameter) warrant human review to verify the architectural design.

You can customize Macroscope's approvability policy. Learn more.

pull Bot pushed a commit to Stars1233/verifiers that referenced this pull request Jun 23, 2026
* chore(v1): add end-to-end eval test suite under tests/v1

- e2e reward-1 runs across the runtime matrix (subprocess/docker/prime, modal excluded): single-turn (echo), multi-turn (alphabet-sort), multi-turn + tools (glossary), agentic (agentic-echo: bash writes a file, verified in the runtime)
- v0 backwards-compat: reverse_text + alphabet_sort bridged, shape parity vs a v1 run
- test_configs: every root configs/*.toml parses as EvalConfig
- echo + agentic-echo fixture tasksets (deterministic, no dataset/Dockerfile)
- conftest: run_v1/run_v0 helpers (greedy temperature=0, generous caps), runtime fixture, e2e + prime markers, skip-without-API-key, on-demand v0 install

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(v1): move fixture tasksets to tests/v1/fixtures; add cross-harness tests

- move echo-v1 + agentic-echo-v1 out of the test dir into tests/v1/fixtures, resolved by id via pytest's pythonpath ini (drops the conftest sys.path insert)
- test_harnesses.py: run echo (single-turn) and glossary (multi-turn + tools) under default + compact; assert rlm (no task-tool support) is rejected when paired with a tools taskset

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(v1): satisfy ruff (E731 lambda -> def, ruff format)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(v1): merge harness+runtime into one matrix; gate tools on SUPPORTS_TASK_TOOLS

- fold test_harnesses into test_e2e: the trivial tasks fan across the harness x runtime matrix (built-in default + rlm; compact is an example harness, excluded; rlm marked slow as it installs an agent binary)
- the tools test reads each harness's SUPPORTS_TASK_TOOLS to expect a raise (rlm) vs a run (default), instead of a separate hardcoded test
- alphabet-sort: similarity_power=1 (drop power scaling) so a near-perfect sort isn't sharply penalized

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(v1): self-contained v0 legacy tests via echo fixtures; inline run helpers

- add v0 echo fixtures (echo-v0 SingleTurnEnv, echo-multi-v0 MultiTurnEnv); the legacy tests use them instead of example envs, so the v0 path is exercised deterministically
- drop ensure_v0: the legacy bridge imports a fixture by id off pythonpath (no runtime uv pip install, no environments/ dependency), same as the v1 fixtures
- inline the run_v1/run_v0 helpers into their fixtures

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(v1): adapt legacy shape test to PrimeIntellect-ai#1606 message-graph (trajectory -> nodes)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(v1): SUPPORTS_USER_SIM harness flag + container-safe multi-turn user-sim fixture

- add SUPPORTS_USER_SIM ClassVar on Harness (default False; the default harness opts in) - a user simulator is a distinct capability from task MCP tools (rlm supports neither: it takes a single instruction, no message history)
- e2e: container-safe echo-multi-v1 user-sim fixture (vf.User shipped as a uv script, staged + run via uv in any runtime); the multi-turn test is gated by SUPPORTS_USER_SIM (skips rlm)
- generalize the test capability lookup to harness_supports(id, flag)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(v1): run the user simulator in its own runtime, reached host-side

The user simulator is driven by the framework on the host (connect_user), not by the model. It was served colocated in the agent's runtime with a localhost URL, which the host can't reach when the agent runs in a remote prime sandbox (ConnectError; via the agent tunnel, a 421). Now serve_user runs it in its OWN runtime (host subprocess by default, or its own sandbox via TasksetConfig.user.runtime) and publishes the port back to the host (serve_tools host_reachable: a remote sandbox's public_url, else localhost).

- add UserConfig(runtime) to TasksetConfig; serve_tools gains host_reachable for a host-consumed colocated server
- e2e: the multi-turn user-sim test now passes on prime; add a test for the user-sim in its own (docker) sandbox

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(v1): matrix task-tools + user-sim across server runtimes

- server_runtime fixture + test_task_tools_own_runtime / test_user_own_runtime: a tool/user-sim server in its OWN runtime (subprocess/docker/prime), agent on subprocess
- skip_if_unexposable: skip the prime server case when the sandbox region can't publish a port (a known prime infra limit, surfaced by the matrix)
- TODO in prime.public_url to lift that limit (then drop the skip)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(v1): rename agentic-echo fixture -> echo-agentic-v1 (echo_* naming)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant