Repository navigation
feat: remove the eval's platform push and the prime-runs dependency - #3046
Merged
Merged
Conversation
vf-eval no longer opens a run on the platform or streams episodes to it. Hosted evaluations run prime-rl's eval, which owns platform uploads, so verifiers drops prime-runs (and with it prime-traces). The run id is minted locally. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mikasenghaas
marked this pull request as ready for review
November 3, 2026 00:16
hallerite
approved these changes
Nov 3, 2026
Contributor
ApprovabilityVerdict: Needs Human Approval Macroscope's review found this PR requires human approval — Evaluations become local-only, and existing push/attach flags and saved configs lose compatibility. Human judgment is needed on the migration and release plan, including preventing hosted deployments from selecting the removed attachment path. You can add or adjust custom eligibility rules. Learn more. |
mikasenghaas
added a commit
to PrimeIntellect-ai/prime-rl
that referenced
this pull request
Nov 3, 2026
…ime (#4366) ## Summary Companion to PrimeIntellect-ai/verifiers#3042 and PrimeIntellect-ai/prime#1140 (released in `prime-runs` 0.1.6). The file monitor and the Prime monitor encode each episode in short steps, so a large episode no longer stalls the orchestrator's event loop for as long as encoding it takes. - **Pins.** - The verifiers submodule moves to verifiers main, which includes verifiers#3042: `to_json` encodes one node at a time and releases the GIL every millisecond, and `record_run` records the run on every trace. - `prime-runs` 0.1.6, already on main, contains prime#1140: the SDK uploads `episode.to_json()` as it is when the episode and its traces name the upload's run. The dispatcher's `record_run` makes that true for RL episodes. - Verifiers main also includes PrimeIntellect-ai/verifiers#3046, which removes `vf-eval`'s platform push and verifiers' `prime-runs` dependency. In `uv.lock` (uv 0.12.0), only the verifiers metadata changes. - **The file monitor writes `episode.to_json()`.** - The stream line is byte for byte what `orjson.dumps(episode.to_record())` gave before. - The index row comes from `index_record(episode)`. It dumps everything but the nodes' payloads, one trace at a time, and gives the same row. - `ChunkedJsonl.append` takes a line in parts, so the newline is written without copying a long line. - **The load test's lag limits drop** from p99 100 ms and max 250 ms to 25 ms and 100 ms, so a regression shows. Across runs at production sizes, the highest values were a p99 of 12.5 ms and a max of 22 ms. - **A hosted orchestrator stamps the platform's run id.** A hosted launch sets only `$RUN_ID`, not `$PRL_RUN_ID`, so the orchestrator stamped episodes with a random id, and the SDK re-stamped every upload. It now falls back to `$RUN_ID`, the Prime run id. ## Verification **Headline: event-loop lag at 1,000 production-sized episodes (~8 GB of JSON)**, monitor load test, dev box: | | Main (before) | This PR | |---|---|---| | prime: lag p99 / max | 14 / 17 ms | **3.1 / 3.5 ms** | | file: lag p99 / max | 47 / 93 ms | **4.8 / 15 ms** | | file: `log()` max | 177 ms | 195 ms | - **A second run:** inside the full unit suite, with more load on the box, it measured prime 11 / 18 ms, file 5.2 / 22 ms, and file `log()` max 224 ms. - **Why the GIL release matters:** encoding node by node without it left the file monitor at 15–18 / 31–66 ms, varying from run to run. A busy encoder thread keeps the GIL until CPython's 5 ms switch interval forces a handoff, and the event loop waits that out several times per wakeup. **The stall no longer grows with the episode.** One thread encodes episodes of 10 to 10,000 turns (1,000 tokens per turn) while a 5 ms ticker on the event loop records the worst stall. Medians of 5 runs, under the orchestrator's GC policy: | Turns | Episode | Encode CPU, before / after | Worst stall, before | Worst stall, after | |---|---|---|---|---| | 10 | 0.2 MB | 0.4 / 0.5 ms | 5.5 ms | 5.2 ms | | 100 | 2.2 MB | 4.0 / 4.5 ms | 8.0 ms | 1.6 ms | | 1,000 | 22 MB | 50 / 51 ms | 40 ms | 3.1 ms | | 3,000 | 65 MB | 152 / 167 ms | 100 ms | 5.2 ms | | 10,000 | 217 MB | 508 / 571 ms | 326 ms | 15 ms | - **Before:** the stall grows linearly with the episode. - **After:** it stays around 2–5 ms up to 3,000 turns, about the GIL switch interval. The 10-turn case is that interval alone, since each episode encodes in under a millisecond. - **The rest at 10,000 turns:** the trace header's pydantic dump, which holds every model call (one per turn). Alone it stalls 4.4 / 8.4 / 15 ms at 1,000 / 3,000 / 10,000 turns. Agentic episodes in production have a few hundred turns, so this part stays small. Encoding the calls one at a time, like the nodes, would remove it. - **CPU:** encoding costs up to ~12% more, from the extra calls and GIL releases. **Encoding:** `test_received_episode_encodes_as_its_record_did` sends a two-trace episode over the real delta wire into a `WireEpisode`. Then: - the file monitor's stream line equals `orjson.dumps(to_record())`, byte for byte; - its index row equals the row from the full record; - after `record_run`, the SDK takes the episode's own `to_json()`, which carries the same record as the old stamped line. **Tests:** `pytest tests/unit -m "not gpu"`: 1,077 passed, 7 failed. The same 7 fail on main on this dev box: an attention kernel without sm_120 support, and no ninja for the CPU Adam extension. **CI:** on the CI runner, the file monitor at 1,000 production-sized episodes measured event-loop lag p99 6.0 ms and max 12 ms, against 63 / 152 ms on main. Its slowest `log()` was 382 ms, under the 1 s limit. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes affect how every episode is persisted and indexed and how run identity is chosen on hosted launches; behavior is contract-tested but touches high-volume I/O on the training path. > > **Overview** > Large episodes no longer block the orchestrator event loop during trace logging. The **file monitor** writes stream lines with **`episode.to_json()`** (incremental, GIL-friendly encoding from verifiers) instead of a single **`orjson.dumps(to_record())`**, and builds index rows via new **`index_record()`** so summarization skips heavy node payloads without materializing the full record first. **`ChunkedJsonl.append`** accepts **byte parts** so the newline is appended without copying megabyte-scale lines. > > The orchestrator **`run_id`** now falls back to **`$RUN_ID`** when **`$PRL_RUN_ID`** is unset, so hosted runs align with the platform id and Prime uploads are not re-stamped with a random id. > > Monitor load tests use **stricter event-loop lag thresholds** to catch regressions. A new unit test asserts on-disk bytes and SDK upload JSON still match the legacy **`to_record()`** encoding. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit f83e849. 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 Opus 5.5 <noreply@anthropic.com>
earakely-scale
added a commit
to scaleapi/agentenv-framework
that referenced
this pull request
Nov 3, 2026
verifiers main removed the eval's platform push (PrimeIntellect-ai/verifiers#3046), and with it the --no-push flag, which its config now rejects as an extra input. 0.4.0 still pushes by default, so the taskset test passes --no-push only when vf-eval --help lists it: both the pinned and the main jobs run the same test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
vf-evalno longer pushes runs to the Prime Intellect platform, and verifiers no longer depends onprime-runs. Platform uploads belong to prime-rl'seval. Hosted evaluations already use it: production and dev setHOSTED_EVAL_V1_RUNNER: prime-rl.EvalConfig.push(--push/--no-push) andRunConfig.attach(--run.attach) are removed, and so is the validator that tied them together.RunConfig.idis now a localuuid4().hex, set when the config is created. Before,open_runassigned it from the prime-runs handle. It still goes on every trace (EvalRunInfo) and into$VF_RUN_ID.run_evalno longer opens, streams to, finishes or aborts a platform run. Episodes still go totraces.jsonlas each one finishes.verifiers/v1/utils/platform.py(PushState,open_run,log_episodes,finish_run,abort_run, and the unusedbuild_samplesre-export) and its tests.prime-runsis removed from the dependencies and fromexclude-newer-package.prime-tracesis removed fromexclude-newer-package, because nothing pulls it in any more.uv.lockdrops both packages and changes nothing else.--no-pushis removed from the docs, the nemo-gym-weather README and the examples integration test.Breaking
--push,--no-pushandpushin eval configs are removed.vf-evalruns no longer show up on the platform's Evaluations tab. To upload evals, run prime-rl'suv run eval. Remove--no-pushfrom scripts.--run.attach/run.attachis removed. The platform's verifiers v1 runner (generate_v1_eval_script, used whenHOSTED_EVAL_V1_RUNNER=verifiers) passes it. Production and dev both use the prime-rl runner, so nothing live calls it. Do not switch a deployment back to the verifiers runner after this ships. The platform'sconfig.pydefault is still"verifiers", and public-docsverifiers/v1/evaluation.mdxstill documentsrun.attach.pushkey fail to load. Every run saved before this change has"push": trueinconfigs/resolved/eval.json, sovf-eval @ <run>/configs/resolved/eval.json --resumefails with "Extra inputs are not permitted". Delete thepushkey from that file, then resume.Verification
pytest tests/unit: 244 passed, 10 skipped (9 needPRIME_API_KEY, 1 needsharbor).ruff check,ruff formatandtypass.vf-eval reverse-text --env.agent.harness.id null --env.agent.runtime.type subprocess -n 2 -r 1 --no-rich: 2 episodes were written, and both traces carry the same localrun.id.--resumefrom that run'sconfigs/resolved/eval.jsonloads and reports nothing to resume. The same file with"push": trueadded fails with "Extra inputs are not permitted".🤖 Generated with Claude Code
Note
Remove platform push from
vf-evaland drop theprime-runsdependencyopen_run,log_episodes,finish_run,abort_run,PushState, and related helpers are gone.run_evalin runner.py still writes completed episodes to the local trace store.pushfield fromEvalConfigand theattachfield andassign_idmethod fromRunConfig. Each run now gets a UUID run ID at construction, so readingidno longer waits for a platform run to open.prime-runsfrom pyproject.toml and removes--no-pushfrom docs and the example integration test. Deletes test_platform.py.RunConfig.idis a locally generated UUID instead of a platform-assigned ID, andVF_RUN_IDis set fromconfig.run.id. Any code readingEvalConfig.push,RunConfig.attach,verifiers.v1.utils.platform.build_samples, or passing--no-pushwill break; in-tree usages are updated.Macroscope summarized ab63017.
Note
Medium Risk
Breaking CLI/config surface (
push,attach, saved eval JSON) and run ID semantics change from platform-assigned to local UUID; core eval path remains disk-backed traces only.Overview
vf-evalis local-only for traces: it no longer opens, streams to, finishes, or aborts a Prime Intellect platform run. Episodes still append totraces.jsonlas before; platform uploads are expected via prime-rl'seval.Removed
verifiers/v1/utils/platform.py(includingPushState,open_run,log_episodes,finish_run,abort_run) and its unit tests.prime-runsis dropped frompyproject.tomlanduv.lock;prime-tracesis removed from exclude-newer-package only.Config breaking changes:
EvalConfig.push(--push/--no-push),RunConfig.attach, andassign_idare gone.run.idis auuid4().hexat config construction (still on traces and$VF_RUN_ID). Saved resolved configs that still contain"push": truewill fail validation on resume/replay until that key is removed.Runner and dashboard:
run_evalno longer calls platform helpers or shielded close-out; the live dashboard no longer shows push progress URLs. Docs and integration tests drop--no-pushfrom example commands.Reviewed by Cursor Bugbot for commit ab63017. Bugbot is set up for automated code reviews on this repo. Configure here.