Repository navigation
feat(training): NeMo Gym resources server for a bundle's tasks - #399
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
…erver is at its limit Gym runs every rollout of a step at once, so a session refused at the limit waits until its reset deadline instead of masking the rollout after 4 s; the TRL helper keeps its 4 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d session module Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…writing the Gym server Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NeMo RL GRPO through this server, on GPUNeMo RL main (dd2e251, its Gym pinned at 3f6f205) trained Qwen3-4B through this resources server on the GridSim v1 training bundle. The bundle was served by Setup. It mirrors the bundle's earlier GRPO run with this repo's TRL helper:
The hardware was 4× L40S (g6e.12xlarge), with vLLM colocated.
One sampled rollout per day leaves about ±0.065 of noise (95%) between two means. NeMo RL's +0.13 by step 20 is outside that; TRL's +0.045 by step 40 isn't. The two runs share their data, model, LoRA and sampling, but not their loss normalization. TRL's What the run shows about the integration:
About the GPU build, which isn't part of this PR. NeMo RL's container builds its CUDA code for sm 9.0/10.0 only, and no H100 capacity was available. So NeMo RL was built on bare metal for Ada (sm 8.9), with three local changes:
A dense model doesn't use those packages. On H100s, NeMo RL's own container should need none of this. 🤖 Generated with Claude Code |
…nce when rollouts wait for room, and take one worker A rollout whose run fails or is cancelled is never verified, so its session held a slot on the bundle's server until shutdown; the server now ends a session with no request for idle_timeout seconds (600 by default). The first time a rollout waits for room the server says so once, naming the limit, and the config refuses num_workers above 1, since sessions live in the server's process. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nterval Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he shared session fewer hooks The resources server now calls start, call, result, close and idle_for on its session instead of reaching into the shared session's internals. Both helpers check an episode's first turn offers no tool the model isn't shown, which drops the _misses hook; how long a session waits for room travels in Shared instead of a None-means-deadline class setting. 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>
…nents, for GDPO NeMo RL's GDPO trains on a verify result's reward_components, a score per component, and NeMo RL refuses a result whose reward isn't their sum. With reward_components in the server's config (--reward-components when writing it), verify also answers with each of the episode's scores by step id, which the OpenEnv server already sends when the episode ends, and the reward is their sum. It's off by default, since a reward= that picks or weights scores breaks that sum, and the config refuses the two together. A masked rollout answers no components. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…onents build_app refuses a task with several scores and no reward=, so --reward-components couldn't write or serve the bundles it's for. With components on, the writer's probe server and the resources server's own serve the bundle with the scores' sum as its reward, which the components make the reward anyway. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Makes a bundle's tasks trainable from NeMo Gym, and so with NeMo RL, the trainer that takes its environments. Gym is also the environment layer for verl, Unsloth and Miles.
What it adds
python -m agent_env.training.nemo_gym SOURCE ROOT. SOURCE is a bundle, or the URL of an OpenEnv server serving one. The command writes the bundle's resources server into a Gym root: the rootNEMO_GYM_EXTRA_ROOTSnames, or a Gym checkout's own, as NeMo RL's is. Underresources_servers/<name>/it writes:app.py;pyproject.toml;configs/<name>.yaml, which runs the server, Gym'ssimple_agentand thelegacy_agentenvironment server NeMo RL dispatches through;data/<split>.jsonl, a row per task: the prompt, every tool the task's turns offer,split,indexandtask_id.It finds a toolset's tools by playing one of its tasks to the last turn, unscored, as the TRL helper does.
agent_env.training.nemo_gym.server.AgentEnvResourcesServeris that server. It runs in the venv Gym builds for it./seed_session(the row)POST /<tool>end_turnthe next turn's prompt./verifymask_sampleand afailure_reason, so it's left out of training./close_sessionThe bundle is served by
agent_env.openenv.build_app. The config names an OpenEnv server'surl, or thebundleitself, which the server then serves on loopback for its lifetime.training/_openenv.py. The TRL helper's session code moves here so both helpers share it:Session, the Task API reads, the toolset probe and the in-processServer.trl.pykeeps only what's TRL's own: the sync wrappers, its event-loop thread, the environment classes and their pickling, and the exit hook.Why a
pyproject.toml, not arequirements.txtA Gym checkout's
[tool.uv] exclude-dependenciesdrops packages from every server venv under it,cryptographyamong them, which agent-env imports. uv applies the[tool.uv]settings of the nearestpyproject.toml, so the server's own puts them back.--overridedoesn't (uv 0.13.6). Outside a checkout, Gym installs nemo-gym itself and ignores the../..source.Packaging and CI
nemo-gymextra:openenv, plusnemo-gym>=0.7.0rc0on Python 3.13.14 or later, the Python nemo-gym needs. The rc0 floor is the version NeMo RL's Gym checkout reports.dev, assmolis, so the 3.12 jobs install nothing new.uv.lock(Ray, MLflow and others), all under that Python marker..github/workflows/nemo-gym.ymlruns the new tiertst/nemo_gymon Python 3.13 with that extra, on the same triggers astrl.yml. It allows no skips and isn't a required check.make nemo-gym-testruns the tier locally.smol's.THIRD_PARTY_NOTICES.mdis unchanged. It lists the extras its intro names, andsmolandvercelaren't there either. Whether to add nemo-gym's tree is the maintainers' call.Tests
Unit, Python 3.14 on macOS:
tst/unit/training/nemo_gym_test.pycovers the server's folder, config and rows, from a URL and from a bundle; one probe per toolset; and a tool named after a Gym route being refused. The TRL and OpenEnv suites pass unchanged on the shared module, as do the import guards.tst/nemo_gym, Linux, Python 3.13.14, nemo-gym 0.7.0 fromuv.lock:end_turnanswering with the next turn's prompt;37 pass, with the training unit tests.
End to end, on a Linux box with Docker: the GridSim v1 training bundle's first 32 eval days, collected with
gym env startandgym eval run. A scripted OpenAI-compatible model submits one fixed schedule per day. Gym's rewards equal the Episode API's for the same schedule on 32 of 32 days, with none masked; they take 12 distinct values between 0 and 0.49. That holds on both setups:32 rollouts take 36 s.
NeMo RL GRPO through this server on GPU follows.
🤖 Generated with Claude Code


Confidence Score: 5/5
The PR appears safe to merge, with the multi-score startup issue fixed.Summary
Adds a NeMo Gym resources server for training on a bundle’s tasks.
Diagram
sequenceDiagram participant Gym as NeMo Gym participant Resources as AgentEnvResourcesServer participant OpenEnv as OpenEnv bundle server Gym->>Resources: seed_session with task row Resources->>OpenEnv: Start episode in background Gym->>Resources: Call tool Resources->>OpenEnv: Call episode tool OpenEnv-->>Gym: Tool text through resources server Gym->>Resources: verify with last reply Resources->>OpenEnv: End remaining turns OpenEnv-->>Resources: Reward and scores Resources-->>Gym: Reward, optional components, or masked sampleReviews (8) · Last reviewed commit: "fix(training): serve a multi-score bundl..." · Reviewed by Greptile