Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
db2c00e
feat(trainer): freeze MoE router by default in RL (#3797)
faresobeid Oct 7, 2026
93a0fe0
refactor(trainer): add iter_moe_blocks for the MoE layer lookup (#3843)
faresobeid Oct 7, 2026
f3827c4
perf(trainer): avoid eager fallback of MoE blocks with an fp32 router…
garrett361 Oct 7, 2026
3587b28
chore: require prime-runs 0.1.4 (#3928)
kcoopermiller Oct 8, 2026
e6acff7
chore: align network prompt dependency pins (#3929)
xeophon Oct 8, 2026
a3f1f89
fix(eval): preserve empty outcomes and exclude zero-turn traces from …
xeophon Oct 8, 2026
adda473
fix(eval): salt inference caches only when policy weights change (#3825)
xeophon Oct 8, 2026
fec3acd
chore(orchestrator): fold GenerationSource into TrainEnv (#3838)
faresobeid Oct 8, 2026
765bbeb
fix(launch): default TRITON_CACHE_DIR to a node-local path (#3877)
faresobeid Oct 8, 2026
746d8a9
chore(models): drop rms_norm re-export, move fp8 quantizer into its t…
faresobeid Oct 8, 2026
0bcb868
fix(configs): size the single-node NCCL transfer group after the DP f…
faresobeid Oct 8, 2026
72834b3
feat(trainer): prepare RL micro batches on a background thread pool (…
garrett361 Oct 8, 2026
5e963f0
fix(monitors): send online-eval metrics to the parent training run (#…
JannikSt Oct 8, 2026
6b0906c
fix(eval): preserve sibling trace verdicts when an episode fails (#3824)
xeophon Oct 8, 2026
26681fc
fix(models): pass contiguous router-replay experts to compiled layers…
garrett361 Oct 8, 2026
1983d8d
chore: bump verifiers to main (#3934)
mikasenghaas Oct 8, 2026
bc25075
fix(ci): uv cache on h200 runners, drop phantom 4xa6000 job, cap fan-…
samsja Oct 8, 2026
31281d8
feat(sft): pass per-message loss selection to renderers (#3950)
hallerite Oct 8, 2026
8532083
feat(sft): pad to a multiple of cp and remove fp8 indexer dynamism (#…
garrett361 Oct 8, 2026
083b8fe
ci: reduce GPU usage and parallelize test setup (#3944)
xeophon Oct 9, 2026
88faa6d
feat(sft): warn when renderer is not prefix stable (#3953)
hallerite Oct 9, 2026
37b48a9
security(ci): pin BuildKit builder to v0.33.1 and rotate registry bui…
Apocrathia Oct 9, 2026
84e94bf
perf(orchestrator): poll for new weight versions every 0.1s instead o…
samsja Oct 9, 2026
f7e8ab6
fix(eval): resume rollouts by task content and selected occurrence (#…
xeophon Oct 9, 2026
9b39a10
refactor(sampling): share parameter resolution across eval and traini…
xeophon Oct 10, 2026
c5406f8
perf(examples): use cudnn_flashmla DSA backend in GLM-5.3 RL example …
faresobeid Oct 10, 2026
9570bcc
chore(configs): drop recipe lines that repeat defaults (#3982)
faresobeid Oct 10, 2026
c9ce5f3
chore(configs): drop dead orchestrator fields (#3983)
faresobeid Oct 10, 2026
8493109
chore(inference): drop typed vLLM fields that only repeat vLLM defaul…
faresobeid Oct 10, 2026
a1e0edb
fix(rl): inherit inference.deployment.gpus_per_node from deployment (…
faresobeid Oct 10, 2026
be89bbd
fix(inference): keep the routed-experts dtype vLLM picks from the mod…
faresobeid Oct 10, 2026
8b2eb32
chore(trainer)!: remove the model.index_cache override (#3984)
faresobeid Oct 10, 2026
32c48f5
chore(configs)!: rename tasks_per_minute to dispatch_per_minute (#3991)
faresobeid Oct 10, 2026
9cde4d7
fix(slurm): stop crashed multi-node RL jobs idling for an hour (#3979)
faresobeid Oct 10, 2026
41a8ed0
feat(configs): one weight wait timeout, default 3600 s (#3980)
faresobeid Oct 10, 2026
0936378
refactor(configs)!: one model.offload field for CPU offloading (#3988)
faresobeid Oct 10, 2026
73140de
fix(trainer): keep Qwen3.5 CP context setup eager (#4011)
hubert-marek Oct 10, 2026
47423bc
Merge branch 'PrimeIntellect-ai:main' into main
mannuch Oct 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions .github/workflows/build_image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,12 @@ jobs:

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
with:
# CVE-2026-93318: pin the BuildKit builder to the patched release so
# the version is deterministic on the self-hosted runners (otherwise
# the rolling moby/buildkit:buildx-stable-1 tag is used, and a
# persistent runner may keep a stale local copy of it).
driver-opts: image=moby/buildkit:v0.33.1@sha256:cec9f139f45e93c5c69c60f8b07cfad9f43f4ef6b6a6cd917527fea5ff2e3dea

- name: Set up uv
uses: astral-sh/setup-uv@v7
Expand All @@ -207,7 +213,12 @@ jobs:
run: |
set -euo pipefail
key=$(uv run --no-project --python 3.12 scripts/docker_dependencies.py fingerprint .)
image="${REGISTRY}/${IMAGE_NAME}:deps-${key}-${SUFFIX}"
# deps-v2: remediation epoch for CVE-2026-93318 — the fingerprint
# hashes only Dockerfile/lock inputs, not the workflow or BuildKit
# version, so pre-fix deps-${key} images would otherwise be reused
# as the runtime base instead of being rebuilt by the pinned v0.33.1
# builder.
image="${REGISTRY}/${IMAGE_NAME}:deps-${key}-v2-${SUFFIX}"
digest=$(uv run --no-project --python 3.12 scripts/docker_dependencies.py resolve "$image")
echo "image=${image}" >> "$GITHUB_OUTPUT"
echo "digest=${digest}" >> "$GITHUB_OUTPUT"
Expand All @@ -222,8 +233,10 @@ jobs:
file: ./Dockerfile.cuda
target: dependencies
outputs: type=image,push=true,compression=zstd,compression-level=3
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:dependency-buildcache-${{ matrix.suffix }}
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:dependency-buildcache-${{ matrix.suffix }},mode=max,image-manifest=true,oci-mediatypes=true,compression=zstd,compression-level=3
# buildcache-v2: rotated 2026-10-05 for CVE-2026-93318 — the pre-v0.33.1
# builders (cache writers since 2026-08-16) must not be re-imported.
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:dependency-buildcache-v2-${{ matrix.suffix }}
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:dependency-buildcache-v2-${{ matrix.suffix }},mode=max,image-manifest=true,oci-mediatypes=true,compression=zstd,compression-level=3
platforms: ${{ matrix.platform }}
tags: ${{ steps.dependency.outputs.image }}

Expand All @@ -240,8 +253,10 @@ jobs:
RENDERERS_PRETEND_VERSION=${{ steps.dependency.outputs.renderers }}
PYDANTIC_CONFIG_PRETEND_VERSION=${{ steps.dependency.outputs.pydantic_config }}
outputs: type=image,push=true,compression=zstd,compression-level=3
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:application-buildcache-${{ matrix.suffix }}
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:application-buildcache-${{ matrix.suffix }},mode=max,image-manifest=true,oci-mediatypes=true,compression=zstd,compression-level=3
# buildcache-v2: rotated 2026-10-05 for CVE-2026-93318 — the pre-v0.33.1
# builders (cache writers since 2026-08-16) must not be re-imported.
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:application-buildcache-v2-${{ matrix.suffix }}
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:application-buildcache-v2-${{ matrix.suffix }},mode=max,image-manifest=true,oci-mediatypes=true,compression=zstd,compression-level=3
platforms: ${{ matrix.platform }}
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.tag }}-${{ matrix.suffix }}
Expand Down
23 changes: 14 additions & 9 deletions .github/workflows/cpu_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

jobs:
unit-tests:
name: Unit tests
Expand All @@ -15,15 +19,16 @@ jobs:
uses: actions/checkout@v7
with:
submodules: false
- name: Init public submodules
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
git submodule update --init --recursive -- deps/verifiers deps/renderers deps/prime-envs deps/pydantic-config
- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
- parallel:
- name: Init public submodules
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
git submodule update --init --recursive -- deps/verifiers deps/renderers deps/prime-envs deps/pydantic-config
- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
- name: Install dependencies
run: uv sync --all-extras --all-packages --locked
- name: Run tests
Expand Down
203 changes: 156 additions & 47 deletions .github/workflows/gpu_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,103 @@ on:
branches: [main]
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
changes:
name: Select tests
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
permissions:
pull-requests: read
outputs:
unit: ${{ github.event_name != 'pull_request' || steps.filter.outputs.unit == 'true' }}
integration: ${{ steps.matrix.outputs.tests }}
eval: ${{ github.event_name != 'pull_request' || steps.filter.outputs.eval == 'true' }}
steps:
- uses: dorny/paths-filter@v4
id: filter
if: github.event_name == 'pull_request'
with:
filters: |
unit:
- &runtime
- '.github/workflows/gpu_tests.yaml'
- '{pyproject.toml,uv.lock,.python-version,.gitmodules}'
- 'deps/**'
- 'packages/**/pyproject.toml'
- 'packages/prime-rl-configs/src/prime_rl/configs/{trainer,shared,__init__}.py'
- 'packages/prime-rl-configs/src/prime_rl/utils/**'
- 'src/prime_rl/*.py'
- 'src/prime_rl/{trainer,multimodal,transports,utils}/**'
- 'tests/{__init__.py,conftest.py,utils.py}'
- 'tests/integration/{__init__.py,conftest.py}'
- 'tests/unit/{train,inference}/**'
- 'src/prime_rl/inference/**'
sft:
- *runtime
- 'tools/convert_{dcp_to_bf16,dcp_to_fp8,bf16_to_fp8,fp8_to_bf16}.py'
- 'src/prime_rl/dashboard/**'
- 'tests/integration/dashboard_smoke.py'
- 'packages/prime-rl-configs/src/prime_rl/configs/{sft,eval,monitors}.py'
- 'src/prime_rl/entrypoints/{sft,dashboard}.py'
- 'src/prime_rl/monitors/**'
- 'src/prime_rl/eval/{online,runner}.py'
- 'tests/integration/test_reverse_text_sft{,_lora}.py'
- 'configs/ci/integration/reverse-text-sft{,-lora}/**'
rl:
- *runtime
- 'tools/convert_{dcp_to_bf16,dcp_to_fp8,bf16_to_fp8,fp8_to_bf16}.py'
- 'src/prime_rl/dashboard/**'
- 'tests/integration/dashboard_smoke.py'
- 'packages/prime-rl-configs/src/prime_rl/configs/{rl,orchestrator,inference,env_server,algorithm,eval,monitors}.py'
- 'src/prime_rl/entrypoints/{rl,trainer,inference,orchestrator,env_server,dashboard}.py'
- 'src/prime_rl/{inference,orchestrator,monitors}/**'
- 'src/prime_rl/eval/{online,runner}.py'
- 'tests/integration/test_reverse_text{,_lora,_moe,_rl_opd,_rl_sft}.py'
- 'tests/integration/test_alphabet_sort.py'
- 'configs/ci/integration/reverse-text{,-lora,-moe,-rl-opd,-rl-sft}/**'
- 'configs/ci/integration/alphabet_sort.toml'
eval:
- *runtime
- 'packages/prime-rl-configs/src/prime_rl/configs/{eval,orchestrator,inference,env_server,algorithm,monitors}.py'
- 'src/prime_rl/{eval,orchestrator,monitors}/**'
- 'src/prime_rl/entrypoints/{eval,env_server}.py'
- 'tests/integration/test_gsm8k_eval.py'
- 'configs/ci/integration/gsm8k-eval.toml'
- name: Build integration matrix
id: matrix
env:
# Main and manual runs retain the full suite.
RUN_ALL: ${{ github.event_name != 'pull_request' }}
SFT: ${{ steps.filter.outputs.sft || 'false' }}
RL: ${{ steps.filter.outputs.rl || 'false' }}
run: |
tests=$(jq -cn --argjson all "$RUN_ALL" --argjson sft "$SFT" --argjson rl "$RL" '[
if $all or $sft then "reverse_text_sft", "reverse_text_sft_lora" else empty end,
if $all or $rl then
"reverse_text", "reverse_text_rl_opd", "reverse_text_rl_sft",
"alphabet_sort", "reverse_text_lora", "reverse_text_moe"
else empty end
]')
echo "tests=$tests" >> "$GITHUB_OUTPUT"

unit-tests:
name: Unit tests
needs: changes
runs-on: prime-rl-2xh200
container:
image: pytorch/pytorch:2.10.0-cuda13.0-cudnn9-devel
options: --gpus all
timeout-minutes: 45
if: github.event_name == 'push' || github.event.pull_request.draft == false
if: needs.changes.outputs.unit == 'true'
steps:
- name: Install Git
run: |
Expand All @@ -29,12 +112,16 @@ jobs:
uses: actions/checkout@v7
with:
submodules: false
- name: Init public submodules
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
git submodule update --init --recursive -- deps/verifiers deps/renderers deps/prime-envs deps/pydantic-config
- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
- parallel:
- name: Init public submodules
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
git submodule update --init --recursive -- deps/verifiers deps/renderers deps/prime-envs deps/pydantic-config
- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
- name: Install dependencies
run: uv sync --all-extras --all-packages --locked
- name: Run unit tests
Expand All @@ -50,46 +137,20 @@ jobs:

integration-tests:
name: Integration tests (${{ matrix.test }})
runs-on: ${{ matrix.runner }}
needs: changes
runs-on: prime-rl-2xh200
container:
image: pytorch/pytorch:2.10.0-cuda13.0-cudnn9-devel
options: --gpus all
timeout-minutes: 60
if: github.event_name == 'push' || github.event.pull_request.draft == false
if: needs.changes.outputs.integration != '[]'
strategy:
fail-fast: false
# Bound per-PR fan-out: at most 5 integration jobs at a time (plus unit-tests),
# i.e. 6 h200 pods per PR. Tune together with the ARC scale set maxRunners.
max-parallel: 5
matrix:
include:
- test: reverse_text_sft
runner: prime-rl-2xh200
pytest_args: "tests/integration/test_reverse_text_sft.py"
- test: reverse_text_sft_lora
runner: prime-rl-2xh200
pytest_args: "tests/integration/test_reverse_text_sft_lora.py"
- test: reverse_text
runner: prime-rl-2xh200
pytest_args: "tests/integration/test_reverse_text.py"
- test: reverse_text_rl_opd
runner: prime-rl-2xh200
pytest_args: "tests/integration/test_reverse_text_rl_opd.py"
- test: reverse_text_rl_sft
runner: prime-rl-2xh200
pytest_args: "tests/integration/test_reverse_text_rl_sft.py"
- test: alphabet_sort
runner: prime-rl-2xh200
pytest_args: "tests/integration/test_alphabet_sort.py"
- test: reverse_text_lora
runner: prime-rl-2xh200
pytest_args: "tests/integration/test_reverse_text_lora.py"
- test: reverse_text_moe
runner: prime-rl-2xh200
pytest_args: "tests/integration/test_reverse_text_moe.py"
- test: benchmark_regression
runner: 4xa6000
pytest_args: "tests/integration/test_benchmark_regression.py"
- test: gsm8k_eval
runner: prime-rl-2xh200
pytest_args: "tests/integration/test_gsm8k_eval.py"
test: ${{ fromJSON(needs.changes.outputs.integration) }}
steps:
- name: Install Git
run: |
Expand All @@ -100,12 +161,16 @@ jobs:
uses: actions/checkout@v7
with:
submodules: false
- name: Init public submodules
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
git submodule update --init --recursive -- deps/verifiers deps/renderers deps/prime-envs deps/pydantic-config
- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
- parallel:
- name: Init public submodules
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
git submodule update --init --recursive -- deps/verifiers deps/renderers deps/prime-envs deps/pydantic-config
- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
- name: Install dependencies
run: uv sync --all-extras --all-packages --locked
- name: Run integration tests
Expand All @@ -120,7 +185,7 @@ jobs:
GITHUB_HEAD_REF: ${{ github.head_ref }}
PYTEST_OUTPUT_DIR: /tmp/outputs
VLLM_WORKER_MULTIPROC_METHOD: spawn
run: uv run pytest -vvs ${{ matrix.pytest_args }}
run: uv run pytest -vvs tests/integration/test_${{ matrix.test }}.py
- name: Upload run logs on failure
if: failure()
uses: actions/upload-artifact@v7
Expand All @@ -129,3 +194,47 @@ jobs:
path: /tmp/outputs/**/*.log
retention-days: 7
if-no-files-found: ignore

eval-tests:
name: Integration tests (gsm8k_eval)
needs: changes
if: needs.changes.outputs.eval == 'true'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repository
uses: actions/checkout@v7
with:
submodules: false
- parallel:
- name: Init public submodules
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
git submodule update --init --recursive -- deps/verifiers deps/renderers deps/prime-envs deps/pydantic-config
- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
- name: Install dependencies
run: uv sync --all-extras --all-packages --locked
- name: Run eval tests
env:
USERNAME_CI: CI_RUNNER
WANDB_MODE: offline
HF_TOKEN: ${{ secrets.HF_TOKEN }}
PRIME_API_KEY: ${{ secrets.PRIME_API_KEY }}
PRIME_BASE_URL: ${{ secrets.PRIME_BASE_URL }}
PRIME_TEAM_ID: ${{ secrets.PRIME_TEAM_ID }}
GITHUB_REF_NAME: ${{ github.ref_name }}
GITHUB_HEAD_REF: ${{ github.head_ref }}
PYTEST_OUTPUT_DIR: /tmp/outputs
run: uv run pytest -vvs tests/integration/test_gsm8k_eval.py
- name: Upload run logs on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: gsm8k_eval-logs
path: /tmp/outputs/**/*.log
retention-days: 7
if-no-files-found: ignore
4 changes: 4 additions & 0 deletions .github/workflows/style.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ on:
# This will trigger the workflow for pull requests to any branch
types: [opened, synchronize, reopened]

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

jobs:
ruff:
name: Ruff
Expand Down
7 changes: 3 additions & 4 deletions configs/advanced/deepseek-v4-flash/sft.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@
# `dist_timeout_seconds = 14400` is needed on any run that has to build the HF -> prime-rl
# conversion cache, which takes far longer than the 3600s default.
#
# To buy memory back for quicker testing on fewer nodes, set `full_offload = true` under `[model]`,
# which keeps the fp32 masters, moments and gradients in CPU RAM and needs `optim_cpu_offload =
# false` and `optim.max_norm = "None"` set alongside it; the lighter `optim_cpu_offload = true` is
# already the default here.
# To buy memory back for quicker testing on fewer nodes, set `offload = "full"` under `[model]`,
# which keeps the fp32 masters, moments and gradients in CPU RAM and disables gradient clipping;
# the lighter `offload = "optimizer"` is already the default here.
#
# There is no `[ckpt]` block. The trainer saves unconditionally at the last step, and a 43-layer
# checkpoint (fp32 master weights plus two fp32 AdamW moments) is ~3 TiB. Add one with
Expand Down
4 changes: 0 additions & 4 deletions configs/advanced/minimax-m2.5/swe.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ level = "debug"
[model]
name = "PrimeIntellect/MiniMax-M2.5-bf16"

[weight_broadcast]
type = "nccl"

[deployment]
type = "multi_node"
num_train_nodes = 4
Expand All @@ -35,7 +32,6 @@ fused_lm_head_token_chunk_size = 1024
max_inflight_activations = 5

[trainer.model.ac]
freq = 1

[trainer.optim]
type = "adamw"
Expand Down
Loading
Loading