Repository navigation
feat: select taskset tasks per train and eval source - #3703
Merged
Merged
Conversation
Every train and eval source takes a `select` block (include/exclude by idx, id, key or name, then shuffle, skip and limit), applied by the taskset's own select(); prime-rl no longer shuffles or slices tasksets itself. Eval blocks take a group-level `select` default that each source inherits field by field; `uv run eval -n/-s` set it. Bumps verifiers (taskset selection views) and prime-envs (take()). Breaking: EnvConfig.shuffle and the eval `num_examples` fields are gone (use `select.shuffle` / `select.limit`). The shuffle seed moves from 42 to verifiers' 0, so shuffled selections pick other tasks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # deps/prime-envs # docs/eval.md
Train and eval groups take a `select` default that each source inherits field by field, layered in the same before-validator as the group `env` block. Only `uv run eval` keeps -n/-s, through vf.SelectCLIConfig, so nested select blocks no longer claim the short flags on the rl, orchestrator and sft CLIs. Resume may now change any `select` field, as landed episodes are matched by task key. Group blocks use `[... .select]` tables in configs and docs, and the eval skill documents common selection patterns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # src/prime_rl/eval/resume.py # tests/unit/eval/test_resume.py
A source whose `select` did not validate was silently replaced by the group's `select`, so a typo like `limt` was dropped. The source now keeps its block and reports its own error. The merge validates every group block with vf.SelectCLIConfig, which drops the per-group type lookup. The dashboard's fallback total reads `select.limit`, the configs skill lists `[select]`, and the docs note that a source's include/exclude replaces the group's. Bumps verifiers for slice steps and key matching against the recorded task data. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mikasenghaas
added a commit
to PrimeIntellect-ai/verifiers
that referenced
this pull request
Sep 28, 2026
## Summary - Add lazy, chainable selection views to `Taskset`: `include` and `exclude` (by `idx`, `ids`, `keys` or `names`), `shuffle(seed)`, `skip(n)` and `take(n)`. Each view is a shallow copy, so the base taskset does not change. ```python taskset.include(idx=["0:100"]).exclude(names=["broken"]).shuffle(seed=0).take(5) ``` - Add `SelectConfig` and `TaskMatchConfig` (`verifiers/v1/configs/select.py`). `Taskset.select(config)` chains the views in a fixed order: `include`, `exclude`, `shuffle`, `skip`, `limit`. `idx` takes ints and Python slices `start:stop:step`, each part optional (`"100:"`, `":50"`, `"::2"`, `"0:10,17"`); negative positions are not supported. Within `include` or `exclude`, a task matches when any list names it. - Give the eval, debug, validate and GEPA configs a top-level `select` block. The four entrypoints select only through `Taskset.select`, so the copied "shuffle, then head" blocks are gone. - Keep `SelectConfig` free of aliases, so that a config with several `select` blocks (prime-rl's group defaults and sources) has no ambiguous flags. `SelectCLIConfig` adds the short flags for the one `select` block of an entrypoint: `-n` sets `select.limit` and `-s` sets `select.shuffle`. - Make `idx` a framework field: iteration sets `TaskData.idx` to the task's position in `load()` and overwrites any value that the taskset sets. Iteration also applies the config `system_prompt` before the views, so a `keys` match compares the keys that traces record. The built-in tasksets, the example environments, the `vf-init` template and the docs no longer pass `idx`. - Add an optional durable `TaskData.id`. - Add `Taskset.bounded`. `take` bounds a view, and so does an `include` that names only closed `idx` ranges. `shuffle`, an `include` by `ids`, `keys` or `names` (which could wait forever for a match), and an `exclude` of an open `idx` range (which drops every later task) raise on a view that is not bounded. `select` applies `limit` after the shuffle, so there only closed `include.idx` ranges can bound it; the error says so. An `idx`-only `include` stops reading `load()` after its last position. - Log a warning when an `include` or `exclude` entry matches no task (usually a typo). - Document the views and the `select` block in `docs/v1/tasksets.md#selecting-tasks`. Companion PRs: - prime-rl: PrimeIntellect-ai/prime-rl#3703 (consumes `select` per train/eval source) - prime-envs: PrimeIntellect-ai/prime-envs#852 (one script stops calling `head()`) ## Breaking - `EvalConfig`, `DebugConfig` and `ValidateConfig` drop `num_tasks` and `shuffle`. Use `select.limit` and `select.shuffle` (`-n` and `-s` still work). In TOML, change a top-level `num_tasks = 5` to `select.limit = 5`. - `GEPAConfig` drops `shuffle`, and GEPA no longer shuffles by default. Pass `-s` to keep the old train/val split behaviour. - `Taskset.head(n)` becomes `take(n)`. `Taskset.view` and the `SEED` constant are removed. - Tasksets that never set `idx` get new default task keys, because `idx` is part of the content hash. An interrupted eval of such a taskset cannot resume across this change. ## Verification - `uv run pytest tests -m "not e2e"`: 113 passed. `ruff check` and `ruff format --check` pass. `tests/v1/test_taskset.py` has one test per behaviour: `idx` assignment, each view, lazy reads, the bounds that allow `shuffle`, `idx` parsing, `keys` matches under a `system_prompt` override, the `SelectConfig` defaults and `SelectCLIConfig` aliases, and the fixed order of `select()`. - `vf-validate` on a dummy 20-task taskset and a dummy infinite taskset: 27 CLI combinations of `--select.*`, `-n`, `-s` and a TOML `[select]` block matched an independent oracle. The combinations included every `idx` form, the union inside `include`, `exclude.idx`, and the infinite-taskset errors. - Real configs against a local mock OpenAI server (no inference spend). The mock counted the model calls: - `vf-eval @ configs/gsm8k.toml`: tasks 0–4 × 3 rollouts, 15 calls. With `-s`: the oracle's shuffled 5 of 1319. - With `--select.include.idx 100:103 --select.exclude.idx 101`: tasks 100 and 102, 6 calls. - `vf-eval @ configs/wordle.toml` (infinite): tasks 0–4. - `vf-eval @ configs/alphabet_sort.toml -s`: refused with "cannot shuffle", 0 calls. With `--select.include.idx 0:4 -s -n 2`: runs. - `vf-validate gsm8k …` and `vf-debug reverse-text -n 3 -s`: task order matches the oracle. - `vf-eval @ configs/<each>.toml --dry-run` for all 12 configs: each resolves to its intended `select.limit`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Breaking config and task-key semantics affect eval resume and all CLIs; selection logic on infinite tasksets is easy to misconfigure but is guarded with explicit errors. > > **Overview** > Introduces a unified **`[select]`** block (and `--select.*` / `-n` / `-s`) for choosing which tasks run, replacing top-level **`num_tasks`** and **`shuffle`** on eval, debug, validate, and GEPA. **`Taskset.select(SelectConfig)`** applies lazy views in fixed order: **`include` / `exclude`** (by `idx` slices, `ids`, `keys`, `names`), **`shuffle`**, **`skip`**, **`limit`** (`take` in Python; **`head` is removed**). > > **`TaskData.idx`** is now set from the **`load()` stream position** during iteration (overwriting author-set values); built-in and example tasksets drop manual `idx`, and **`TaskData.id`** is added for durable source IDs. **`Taskset.bounded`** gates shuffle and identity-based filters on infinite tasksets; unmatched include/exclude entries log warnings. > > Sample **`configs/*.toml`** move limits to **`[select].limit`**. Docs describe selection and updated task identity. **GEPA** no longer shuffles by default—use **`select.shuffle`** (`-s`) for the old split behavior. Task keys may change for tasksets that relied on embedded `idx` in the hash, affecting resume across this upgrade. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c305bde. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- 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] > ### Add lazy taskset selection views and `select` config replacing `num_tasks` > - Iterating a taskset now assigns `idx` automatically, so all environment loaders drop manually supplied `TaskData.idx`; `TaskData` gains an optional durable `id` field and `Task` gains a `with_data` copy helper ([taskset.py](https://github.com/PrimeIntellect-ai/verifiers/pull/2695/files#diff-7e5e561017828ff64ab186fa98a8e394675de1971f358af769aa825f7c7997c9), [task.py](https://github.com/PrimeIntellect-ai/verifiers/pull/2695/files#diff-a1b4a5d6915beae41831864087ea497ed41f0b67b9091ad1ee614834cbfd9399)). > - `Taskset` gains lazy `include`, `exclude`, `shuffle`, `skip`, and `take` views (replacing `head`), plus a `select` view that applies include/exclude/shuffle/skip/limit in a fixed order. Matching supports idx ranges, `id`, `key`, and `name`, warns on unmatched selectors, and rejects unbounded shuffles of infinite streams. > - New `SelectConfig`/`SelectCLIConfig` models in [select.py](https://github.com/PrimeIntellect-ai/verifiers/pull/2695/files#diff-c2b7d88c6cfd8129800ee79349fa672c6c19af8d879cbd4a86396435fb5dd9ff) replace top-level `num_tasks` and `shuffle` in `EvalConfig`, `DebugConfig`, `ValidateConfig`, and `GEPAConfig`; CLI aliases map `-n` to `select.limit` and `-s` to `select.shuffle`. Exported via [__init__.py](https://github.com/PrimeIntellect-ai/verifiers/pull/2695/files#diff-731a849803c53d001c41b5e0fb1bfcb392eaae7eb4fa4b3ace382768dc40066a). > - Runners for eval, validate, debug, and GEPA now apply `config.select` and require the resulting view to be bounded; example TOML configs and docs updated. > - Behavioral Change: config files using top-level `num_tasks`/`shuffle` no longer parse — migrate to `[select]` with `limit`/`shuffle`. `head()` on tasksets is replaced by `take()`; check [configs/](https://github.com/PrimeIntellect-ai/verifiers/pull/2695/files#diff-175ab01246347ee3cb3ad67cd8f359e5bdd765f7751c692026b7e782a3fa53ef) and the GEPA runner's shuffle default (now off unless `select.shuffle` is set). > > <!-- Macroscope's review summary starts here --> > > <sup><a href="https://app.macroscope.com">Macroscope</a> summarized c305bde.</sup> > <!-- Macroscope's review summary ends here --> > <!-- Macroscope's pull request summary ends here --> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # deps/verifiers
mikasenghaas
marked this pull request as ready for review
September 28, 2026 20:18
hallerite
approved these changes
Sep 28, 2026
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
selectblock (EnvConfig.select, avf.SelectConfig):include/excludeby taskidx,ids,keysornames, thenshuffle,skipandlimit. The orchestrator loads each source's tasks withvf.load_taskset(...).select(source.select). prime-rl no longer shuffles or slices tasksets itself, so it picks the same tasks asvf-evalfor the same selection.[orchestrator.train],[orchestrator.eval], SFT[eval], the top level ofuv run eval) takes a sharedselectblock. The same before-validator that layers the groupenvblock layers it under each source, field by field, and a field that the source sets wins. A source'sincludeorexcludereplaces the group's whole block. A sourceselectthat does not validate keeps its own block, so its error surfaces. For example, this evaluates 128 tasks of each taskset:uv run evalhas the-n/-sshort flags (select.limit/select.shuffle), throughvf.SelectCLIConfig. Therl,orchestratorandsftCLIs have severalselectblocks, so they get no short flags.select.limit, per source and for vf-shaped configs.num_examplestoselect.limit. Group-level blocks use[... .select]tables.selectbytask.key.configsskill ([select],-s). Update the eval skill: theselectshorthands, and common patterns (a random subset, tasks by position or name, dropping broken tasks, contiguous and random train/test splits viainclude/excludeandskip).deps/verifiersto its main, which merged feat: add taskset selection views and select config verifiers#2695 (Taskset.select,vf.SelectConfig). Raise theverifiersminimum to0.3.2.dev152, its first release, in bothpyproject.tomlfiles, so the slimprime-rl-configsinstall gets it.Companion PRs: PrimeIntellect-ai/verifiers#2695 (merged), PrimeIntellect-ai/prime-envs#852 (independent;
compile_statementsstops callinghead()).Breaking
EnvConfig.shuffleis removed. Useselect.shuffle.EvalSourceConfig.num_examplesand the group-levelnum_examplesare removed. Useselect.limiton the source or on the eval block.select.seed). Existingshuffle = trueconfigs pick other tasks, so eval numbers before and after this change are not comparable.idx(see verifiers#2695). An interrupted eval of such a taskset cannot resume across this change.Verification
prime-rl-configswheel installed outside the workspace resolvesverifiers 0.3.2.dev152, and the workflow's import script passes.uv run pytest tests/unit/test_configs.py tests/unit/eval tests/unit/orchestrator tests/unit/test_dashboard_timeline.py: 296 passed (2 vLLM-only tests deselected;vllmis not installed on the test box).test_load_configsloads every migrated TOML.idxmatched an independent oracle:uv run eval @ configs/debug/eval/single-turn.toml: tasks 0–7 × 2, 16 calls.uv run eval @ configs/debug/eval/resume.toml: first run 16 calls.--resume --select.limit 10restored 16 episodes and ran only tasks 8–9 (4 calls).--resume --select.include.idx 0:5kept the landed episodes of tasks 0–4 and made no model calls.uv run eval gsm8k -n 4 -s --select.exclude.idx '[0]': the oracle's 4 tasks, 4 calls.[:50]and the rest under a groupselectdefault: both sources match the oracle, 5 calls.selectdefaults reach every source, a source's own fields win, and the resolvedOrchestratorConfigre-validates to the same values.uv run rl -h,orchestrator -handsft -hlist no-n/-s;uv run eval -hdoes.uv run rl --dry-runonconfigs/debug/algo/grpo.toml,examples/basic/reverse-text/rl.tomlandconfigs/debug/multi-env/rl.toml, anduv run sft --dry-runonexamples/basic/reverse-text/sft.toml: group eval limits (128, 64, 32) resolve onto each source, a per-sourceselect.limit = 256is kept, and train sources default to all tasks.🤖 Generated with Claude Code
Note
Medium Risk
Breaking config renames and verifiers-driven selection/shuffle/task-key semantics affect every train/eval run and eval resume comparability across the upgrade, though runtime logic is largely delegated to verifiers.
Overview
Replaces
num_examplesand per-sourceshufflewith verifiers'selectblock on every train/eval source (and group-level[select]/[orchestrator.eval.select]/[eval.select]).select.limitcaps how many tasks run;include/exclude,shuffle,skip, andseedfollow verifiers' ordering so prime-rl matchesvf-evalfor the same selection.The orchestrator now loads tasks with
vf.load_taskset(...).select(source.select)instead of client-side shuffle (seed 42) andislice. Group config merging layers sharedselectonto each source likeenv.uv run evalmaps-n/-stoselect.limit/select.shuffle; eval resume no longer validates config against the interrupted run—landed episodes are matched bytask.keyto the newselect.All example/debug/CI TOMLs, docs, and skills are migrated.
verifiersminimum is raised to0.3.2.dev152. The dashboard expectsselect.limitwhen estimating episode counts.Breaking: rename configs from
num_examples→select.limit,shuffle→select.shuffle; default shuffle seed and task keys may differ from pre-change runs (resume/comparability implications).Reviewed by Cursor Bugbot for commit f30798a. Bugbot is set up for automated code reviews on this repo. Configure here.