feat: consolidate eval cli - #3471
Conversation
Make `uv run evals` the one eval entrypoint: a flat config ([[source]], [client], [concurrency], num_examples, group_size), the single-source shorthands `<taskset> --env.<field> <value> -n -r -c -m -o`, a run directory under output_dir/run.name with clean/dry-run/resume, cursor checkpoints on by default (keep_last prunes old cursors), a log file for standalone runs, dashboard auto-start, and platform upload via monitors.prime (one evaluation per source, uploaded when its epoch ends). The SFT online-eval sidecar becomes its own `online-evals` entrypoint with OnlineEvalsConfig (the sft [eval] block plus the run-level fields); both share EvalRunner. The orchestrator EvalConfig splits into EvalSourcesConfig + EvalConfig so the interval knobs stay training-only. The shorthands rewrite argv into one JSON --source flag because pydantic-config has no list-index paths (--source.0.x does not parse). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`uv run eval` replaces `uv run evals` so verifiers users keep their command; the sidecar is `online-eval`. Modules, configs (EvalConfig, OnlineEvalConfig, SFTEvalConfig; the orchestrator's interval block is ScheduledEvalConfig), log files and resolved-config names follow. examples/eval/ gains TOMLs for the CLI usage verifiers used to document (best-of-n, wiki-search, terminal-bench-2 with retries, rlm in docker with sampling) and a README. A GPU integration test runs `uv run eval` against a local vLLM server from configs/ci/integration. The verifiers submodule points at the branch that removes its `eval` console script, so the shared venv has one `eval`; re-pin to main once PrimeIntellect-ai/verifiers#2512 lands. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The platform sample format and credentials move from verifiers into prime_rl.monitors.platform, shared by the train and eval monitors (the next step is one prime monitor for both). Credentials come from the environment, then the prime CLI config. `uv run eval` loses the `-o` short flag; `--output-dir` stays. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The orchestrator's inference metrics parse vLLM's /metrics with prometheus_client, which only came in through vllm (the gpu extra). The eval entrypoint imports that module, so a slim install (macOS, no gpu extra) failed on it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`uv run eval gsm8k -n 2 -r 2 -c 2` works out of the box: the default client is Prime Inference with deepseek/deepseek-v4-flash, and a PRIME_API_KEY-keyed client falls back to the prime CLI config for the key, as the verifiers client does. The launcher prints the start line, log paths and dashboard URL, then raises the console to results and warnings; logs/latest/eval.log keeps the full log. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Main moved the prime monitor onto prime-runs (#3459) and renamed the admin clients to AdminPlane (#3472). The eval monitor now opens one prime-runs eval run per finished epoch instead of posting to /evaluations by hand, which retires prime_rl.monitors.platform: the SDK's projection and metrics modules own the sample format and the run aggregates. The eval runner takes the AdminPlane rename and the error-rate line from #3462. The swe example stays under examples/eval (main had moved it to configs/evals for `uv run evals`), and the verifiers submodule follows feat/remove-eval-cli's merge of main. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Default the eval model to deepseek/deepseek-v4.1-flash. The SFT online-eval sidecar is no longer a console script: the sft launcher spawns `python -m prime_rl.eval.online`, and its config is the sft [eval] block itself (SFTOnlineEvalConfig, run-level fields filled by the launcher). Both eval processes log to eval.log. The orchestrator's [orchestrator.eval] block is RLOnlineEvalConfig. Monitor configs split by what they log: TrainMonitorsConfig with PrimeTrainMonitorConfig, EvalMonitorsConfig with PrimeEvalMonitorConfig. examples/eval/ is gone; the basic examples ship an eval.toml next to sft.toml/rl.toml, and Prime Inference smoke configs live in configs/debug/eval/. New docs/eval.md and skills/eval; the training docs and skills point at them. The eval integration test runs against Prime Inference in the CPU workflow instead of a local vLLM server on the GPU matrix. The unrelated docs/configuration.md hunk is reverted. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Software components of a training run's evals keep the "online" prefix (config class, module, process name, W&B label). Artifacts do not: the resolved config sits next to eval.log as configs/attempt_N/resolved/eval.json. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
External inference APIs expose no vLLM /metrics, so the adaptive band had nothing to follow and the startup probe refused to run without -c. EvalConfig now pins min_inflight = max_inflight = 128; -c N repins, and min_inflight < max_inflight in [concurrency] restores the adaptive band against a vLLM server. Training-side evals keep the adaptive default. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
single-turn (gsm8k, null harness), multi-turn (terminal-bench-2 fix-git in a sandbox), resume (low pinned concurrency to interrupt and --resume), and multi-env (both), all against Prime Inference. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Like the rl/sft launchers, `uv run eval` prints the start block and dashboard URL, stays quiet while the eval runs (only errors surface), and ends with the success line and the dashboard URL again; results live in the dashboard and eval.log. The multi-turn debug config runs 16 fix-git rollouts against a local dp=2 vLLM deployment with the adaptive band starting at 2 in flight. Admin traffic targets the engine: the router's /v1/models fails with two workers on one URL. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
An eval ships metrics at epoch end and its first episode can take minutes, so the run summary had no start and went stale while running. The launch time is the start until a metrics row says otherwise, and the attempt's log files count as liveness. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Env servers now stream each trace turn by turn (verifiers 40b00b24c). The dispatcher keeps every in-flight episode's streamed assembly and publishes a live view twice a second through a new monitor hook: the file monitor writes monitors/file/inflight.json, one row per live trace with its phase, turns, tokens, cost, elapsed time and last message. The eval progress line counts in-flight rollouts by phase and the dashboard's metrics tab renders the rows as a live table. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
One primitive for a rollout's progress: the env server's delta (verifiers b963fb2b6). Env.run(on_delta) relays each delta to the dispatcher, which forwards it to the monitors stamped with the dispatch identity and keeps only a phase and turn count per live trace for its progress line. The file monitor appends the deltas to traces/live/<trace_id>.jsonl and deletes the file when the episode finishes, is cancelled or dropped, so the directory is exactly the in-flight set and finished traces stay in the stream. The dashboard folds the same files: the traces tab lists live traces above the finished ones with a phase badge and opens them in the viewer as they grow. `python -m prime_rl.monitors.file.traces <run_dir> [<trace_id>]` prints the live rows or one assembled trace. The inflight.json snapshot is gone. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The newest node of a tool-using rollout is a tool result, which read as an empty last message. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Every entrypoint derived env-server addresses as tcp://127.0.0.1:5000 + index, so two runs on one host raced for the same ports: the second either failed to bind or answered the wrong run's tasks. A launcher- managed env server now binds an OS-assigned port and writes it to configs/attempt_N/resolved/envs/<split>/<name>.address; the env clients wait for that file when a source has no explicit serve.address. env_server_base_port is gone. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Every launcher (rl, sft, eval) now prints its "Starting ..." line first, then where the launch's configs are - the command as typed, the launch TOML when one was given, and each component's resolved JSON - then the Logs block and the dashboard URL. The eval console no longer repeats the dashboard banner after the finish line. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The env, model and provider were an arbitrary subset of the config; the Configs block and the dashboard carry all of it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A rollout whose first trace has not streamed yet was invisible; the dispatcher now publishes a pending placeholder at dispatch (removed by the first delta or by retirement) and the live rows carry the dispatch time, shown as a "dispatched" column. A live trace open in the viewer keeps its scroll position across refreshes. verifiers f321f896: replayed OpenRouter reasoning details dedup onto their committed node, so a DeepSeek terminal-bench-2 rollout is one branch again instead of one per turn. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The traces tab shows in-flight rollouts as tinted rows of the episode table: dispatch time where finished episodes show arrival, a phase badge, turn/token/branch counts that grow with the stream, reward n/a, a status filter (all / in flight / finished). Reward moves to the last column. The logs tab's components menu lists every env server under "all envs" so one env's log can be toggled into its own pane. The eval console lists env servers individually in its Configs and Logs blocks. CI: the eval smoke is gsm8k with the bash harness in a subprocess runtime, asserting reward and one branch per rollout; the reverse-text eval test is gone. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The eval.log of an sft run's online evals and of a standalone eval are the same artifact; the Logs block names it the same way. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The env servers' logs live under envs/<split>/; the formatter takes that mapping instead of one parameter per split, and cuts long names in the Configs block the way the Logs block does. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A run whose first episode has not landed has no stream, and the traces tab's error path wiped the in-flight rows it had just drawn. The page and its assets now send Cache-Control: no-cache so a reload revalidates them, and the traces tab polls the live rows once a second. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The viewer's sidebar lists in-flight rollouts ahead of the finished episodes with their phase and turn count; prev/next and the arrow keys step across both. An open live trace pins its transcript to the newest turn on every refresh unless the reader scrolled up. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The total cost is a summary tile; a per-episode cost plot below the token strips repeated it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Deleting the file monitor's directory before the restored episodes were back in the fresh stream let a resume that died during setup lose the whole epoch. The directory is now renamed to file.previous, a later resume reads both streams and keeps each episode once, and it goes only after the epoch has the restored episodes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit db514fd. Configure here.
The file monitor directory a resume finds becomes monitors/file.attempt_N and stays; the resumed attempt writes a fresh one and a later resume reads every attempt's stream, each episode once. Nothing is deleted and no release step is needed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A team's internal models are served only under its X-Prime-Team-ID. Like the verifiers client, a Prime Inference client without one gets the team from $PRIME_TEAM_ID or the prime CLI config. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
It reaches Prime Inference like the other integration tests, from the runners that hold the team credentials. A model listing that fails now raises with the status and body instead of a KeyError. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
hallerite
left a comment
There was a problem hiding this comment.
Thanks for addressing the first round. I checked the updated stack: the eval runner now imports without torch, server ownership is fixed, and resume restores landed episodes and the full epoch count. I found two remaining resume correctness issues and a concurrency issue in the live dashboard cache, detailed inline.
Validation: 27 targeted prime-rl tests and 99 verifiers non-live tests passed, plus local reproductions of the issues below.
A resume validated against the latest attempt's resolved config, which a rejected or dry attempt also writes, so repeating a rejected command passed. Each attempt now stamps its config beside the episodes it produces (monitors/file/eval.json) and a resume validates against that. Owed rollouts of a task opened a fresh group next to the landed one, so pass@k and the dashboard saw two groups for one task; they now join the group the landed rollouts carry. The dashboard's list and single-trace endpoints fold live files from one cache on a thread pool; the fold now runs under a lock and callers get a snapshot, so an appended delta folds exactly once. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
## Summary - Served episodes stream turn by turn over the env-serve wire (`verifiers/v1/serve/delta.py`). `Trace.notify` fires at every phase change and after every recorded turn; the worker's `DeltaStreamer` diffs the run's live traces against what it already sent and ships the new part (header once, appended nodes/calls/errors, semantic links, changed scalars), so every byte crosses the wire once. A cursor advances only after its delta is on the wire. `EnvClient.run` assembles the episode from the deltas (`EpisodeAssembly`, which copies the nodes it keeps so a later link never mutates a delta the caller holds), validates it once, and takes `on_delta` so a caller can relay or persist the stream; the client's receive loop survives a malformed frame. - `pending` preview: the interception server hands each model request's uncommitted tail (tool results, user turns) to `Trace.preview`, so a watcher sees a tool result before the model has answered; the committed turn replaces it and the finished record never carries it. - The eval CLI is `uv run vf-eval` and runs in-process only. Serving an env to many consumers is prime-rl's job (its `uv run eval` runs env servers and consumes this stream), so the CLI keeps the quick local path and never assembles deltas; its TUI footer and console log point at prime-rl's `eval`. The env-server e2e fixture drives a worker pool through `EnvClient` directly. Based on `main`; the eval CLI stays for a transition period (#2610 removes it later). prime-rl PrimeIntellect-ai/prime-rl#3471 consumes the stream for its live traces. ## Breaking - Env-serve wire: replies are 4 frames (`client_id, request_id, kind, data`) with `kind` = `delta` | `reply`; `RunResponse` carries the episode head and per-trace counts instead of the traces. A client and server must be on the same side of this change. - Every console script is prefixed: `vf-eval`, `vf-validate`, `vf-debug`, `vf-replay`, `vf-init`, `vf-gepa`. Generic names collide with the scripts of a workspace that installs verifiers as a dependency (prime-rl's `eval`), and the winner is whichever package was installed last. `vf-eval` has no `[serve]` / `--serve.*` / `--no-serve`: rollouts always run in-process; use prime-rl's `uv run eval` for env-server runs. Existing venvs: `uv sync --reinstall-package verifiers --reinstall-package prime-rl` regenerates the scripts. - `Env.run_slot` takes `on_trace`; `Trace` gains `watch`/`notify`/`preview`/`clear_preview`. ## Verification - `tests/v1/test_serve_delta.py`: turns, a link onto an earlier node, a retried attempt and the final reward round-trip through `DeltaStreamer` → `EpisodeAssembly` → `WireEpisode`; a refused send is diffed again; the pending preview streams, is replaced by the committed turn and never reaches the record; assembling never mutates a delta; the field lists cover every serialized `Trace` field. - `uv run pytest tests/v1 -m "not e2e"` green apart from the config-parse cases of tasksets not installed in the venv; ruff clean. - End to end through prime-rl: gsm8k single turn, terminal-bench-2 fix-git with bash and with the rlm harness delegating to a sub-agent (semantic links `subagent_call`/`subagent_return`), kuhn-poker two-seat episodes, 5-step reverse-text RL runs with token ids and logprobs, including router replay plus sampling replay on a MoE; no assembly mismatch. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- Macroscope's pull request summary starts here --> <!-- Macroscope will only edit the content between these invisible markers, and the markers themselves will not be visible in the GitHub rendered markdown. --> <!-- If you delete either of the start / end markers from your PR's description, Macroscope will append its summary at the bottom of the description. --> > [!NOTE] > ### Stream served episodes turn by turn with delta frames > - Adds `DeltaStreamer` in [delta.py](https://github.com/PrimeIntellect-ai/verifiers/pull/2512/files#diff-106a565d15f6f5c86f7357854d512768b3f8a4775026a0eae32c69b828f5da31) that watches trace changes during `run_slot` and sends incremental deltas; the client `EpisodeAssembly` reconstructs a `WireEpisode` from those deltas plus a final episode head and `TraceSummary` counts. > - Changes the wire protocol to three-frame messages (request ID, kind, data). Delta frames are relayed by the pool and client without closing the request; reply frames close it. Updated in [server.py](https://github.com/PrimeIntellect-ai/verifiers/pull/2512/files#diff-64422f6a8749fcc024415b2756129bc98000e830e74b3b5245de50a555480a22), [pool.py](https://github.com/PrimeIntellect-ai/verifiers/pull/2512/files#diff-0c9c59578214be2580d340bc524321e352f48038207a68945637d00fc399600c), and [client.py](https://github.com/PrimeIntellect-ai/verifiers/pull/2512/files#diff-ef98a21052536967b8f8723e36022f69e539f4e8b13794791e8254434ac4696e). > - Adds a trace watcher/preview API in [trace.py](https://github.com/PrimeIntellect-ai/verifiers/pull/2512/files#diff-834820c3aa80d87ee1c1c57fb54c74f09c66ac727036d964e6005c8613c00b5e). `Env.run_slot` gains an `on_trace` callback; `Rollout.open`/`close` and `InterceptionServer` notify the trace on phase changes and pending turn previews. > - `PendingTurn.commit`/`commit_prompt` now clear the trace's pending preview after committing. > - Risk: `RunResponse` in [types.py](https://github.com/PrimeIntellect-ai/verifiers/pull/2512/files#diff-8e290c0dfc583c92b20ee9f20fa2ecd0df82459ad63f8e819e87aa856de97cf4) removes the serialized `WireEpisode` field and replaces it with an episode head and `TraceSummary` list — any out-of-tree consumer expecting the full episode in the run response will break. > > <!-- Macroscope's changelog starts here --> > #### Changes since #2512 opened > > - Renamed console script entry points in `pyproject.toml` and updated all documentation and usage strings to use `vf-` prefixed command names [02a6eff] > - Refactored trace preview system from unkeyed to keyed architecture [55500a3] > - Updated all trace preview and clear operations to use keyed API with PendingTurn instances as keys [55500a3] > - Added abandon mechanism for cleaning up previews when turns fail or are cancelled [55500a3] > - Changed `verifiers.v1.trace.Trace` to store preview entries by `id()` of the key object rather than by the key object itself [73d602d] > - Updated `PRIME_RL_HINT` constant in the `hint.py` module [fc7e45b] > <!-- Macroscope's changelog ends here --> > > <!-- Macroscope's review summary starts here --> > > <sup><a href="https://app.macroscope.com">Macroscope</a> summarized fe771d8.</sup> > <!-- Macroscope's review summary ends here --> > <!-- Macroscope's pull request summary ends here --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **High Risk** > Breaking env-serve wire protocol and `RunResponse` shape require matching client/server versions; CLI renames and removal of eval’s serve path change how users run evaluations. > > **Overview** > This PR **streams env-server episodes incrementally** instead of returning one fat `RunResponse`. Workers use **`DeltaStreamer`** to diff live traces on `Trace.notify()` and send **`delta`** frames; clients **`EpisodeAssembly`** rebuilds traces and validate once against a final **head + `TraceSummary` counts**. The wire format is now **`[request_id, kind, data]`** with `kind` = `delta` | `reply`; the pool relays deltas without closing the request. > > **`Trace`** gains **`watch` / `notify` / keyed `preview` / `clear_preview`**; rollouts and the interception server fire notifications (including **pending tool/user tails** before commit). **`Env.run_slot`** adds **`on_trace`** so the server can subscribe traces to the streamer. > > **`vf-eval` is renamed and narrowed**: console scripts are **`vf-*`** to avoid clashing with prime-rl’s **`eval`**, docs/config comments follow suit, and **`vf-eval` always runs in-process**—**`[serve]` / `--no-serve` are removed** from eval config—with dashboard/log hints to use **prime-rl** for env-server scale and live dashboards. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit fc7e45b. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Summary
Migrates the eval CLI from verifiers into the prime-rl ecosystem:
uv run evalis prime-rl's entrypoint for evaluating any model on any environment, standalone or as the online evals of a training run.Why:
rl,sft,eval)prime-envssubmodule)Important:
uv run vf-evalso prime-rl ownseval(feat: remove the eval CLI verifiers#2610 removes it later); env servers and their streamed traces (feat: stream served episodes turn by turn verifiers#2512, merged; the submodule points at verifiersmain) are consumed here onlyeval,sft,rl) owns them--resumecontinues an interrupted run from its trace stream: landed episodes rejoin the epoch, only the owed rollouts run;num_examples/group_sizemay change, the model, sampling and env config may not[[source]]blocks); the single-env command shorthands are preserved/metrics); against an API, concurrency is pinned viamin_inflight = max_inflight(the default pins 128)uv sync --all-packages--monitors.prime,--monitors.wandb, the file monitor)Examples:
Breaking
uv run evalsisuv run eval(EvalsConfig→EvalConfig); config shape:[eval.client]→[client],[eval.concurrency]→[concurrency],[[eval.source]]→[[source]],eval.num_examples/eval.group_size→ top level.[online]is gone: online evals are spawned bysft.evalhas no[ckpt]block;--resumeis a switch that reads the run's trace stream.uv run sftwith an[eval]block spawns it);logs/attempt_N/evals.log→eval.log,evals.json→eval.json, W&B labelonline-eval;EvalsEvalConfig→SFTOnlineEvalConfig.ratiois accepted on training sources only,intervalon online eval sources only; a standalone eval's[[source]]takes neither.orchestrator.env_server_base_portand the eval entrypoint'senv_server_base_portare removed: launcher-managed env servers bind an OS-assigned port and publish it (configs/attempt_N/resolved/envs/<split>/<name>.address);serve.addresspins one.uv run env-serverwithoutserve.addressbinds an OS-assigned port (address_filepublishes it).configs/evals/swe.tomlis removed (uv run eval swebench-verified --env.agent.harness.id bash).Verification
uv run pytest tests/unitgreen (configs, orchestrator, eval, monitors incl. the live reader).group_sizeruns only the extra rollouts; resuming with another model is refused.uv syncwithout extras) runsuv run eval; an SFT run with online evals starts one env server per source.--monitors.primeon a two-rollout fix-git eval opened the evaluation 9 s after launch, streamed both rollouts and closed it; the dashboard linked to it throughout.🤖 Generated with Claude Code
Note
Medium Risk
Breaking CLI and config renames affect existing scripts; env-server address discovery replaces fixed ports across
rl,sft, andevallaunch paths.Overview
Replaces
uv run evalswithuv run evalas the standalone evaluation entrypoint, sharing the orchestrator eval pipeline (per-source env servers, adaptive or pinned concurrency, file/W&B/Prime monitors). Config is flattened ([[source]],[client],[concurrency]at top level);--resumecontinues from the trace stream instead of a[ckpt]cursor; SFT online eval is renamed and typed asSFTOnlineEvalConfig(no public[online]block).Env server wiring changes: fixed
env_server_base_portranges are removed—launcher-managed servers bind OS-assigned loopback ports and publish addresses viaaddress_file/configs/.../envs/<split>/<name>.address. Trainingratioand online-evalintervalare scoped to the right source types only.Docs and examples add
docs/eval.md, per-exampleeval.tomlfiles, andconfigs/debug/eval/*smokes;configs/evals/swe.tomlis deleted. CI adds a gsm8k eval integration test on VM runners.Dashboard gains live rollout APIs and eval-centric metrics (plan-driven progress, platform links, eval run status), renames
evals.log→eval.log, and tightens static asset revalidation.Reviewed by Cursor Bugbot for commit 82f2f0e. Bugbot is set up for automated code reviews on this repo. Configure here.