Repository navigation
(fix) Move mlflow/wandb out of core deps and into extras - #3547
Merged
Merged
Conversation
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: haydeniw <hwolff@nvidia.com>
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
…ency change Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: haydeniw <hwolff@nvidia.com>
gitlab_utils.py's GitLab model-registry integration imported mlflow eagerly at module top-level, breaking any import of nemo_gym.cli.dataset / nemo_gym.dataset_orchestrator without mlflow installed. create_mlflow_client() now imports mlflow lazily and raises an actionable ConfigError (pip install nemo-gym[mlflow]) instead of an opaque ImportError. reward_profile.py was the bigger find: `from wandb import Histogram` at module top-level made wandb a de-facto core dependency of nearly all of Gym (via base_resources_server.py / base_responses_api_agent.py), even though the histogram stat is always stripped before it reaches any output or exporter. Made that import lazy too, falling back to None when wandb isn't installed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: haydeniw <hwolff@nvidia.com>
Contributor
|
🌿 Preview your docs: https://nvidia-preview-pr-3547-735e0b5bed19.docs.buildwithfern.com/nemo/gym |
The generic except Exception fallback already surfaces a missing SDK's ImportError message without crashing setup_exporters, so this extra ImportError-specific branch wasn't necessary. Reverts the registry 3-tuple and its test in test_exporters.py too. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: haydeniw <hwolff@nvidia.com>
marta-sd
requested changes
Sep 21, 2026
setup_exporters now catches ImportError specifically and names the extra to install (pip install nemo-gym[mlflow] / [wandb]) instead of relying on the generic except Exception fallback's raw exception text. This restores the change dropped in 580e893. That revert was a mistake: I judged the change unnecessary since setup_exporters already failed gracefully, but PR review (#3547) asked for exactly this behavior, plus extending it to rollout collection. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: haydeniw <hwolff@nvidia.com>
Signed-off-by: haydeniw <hwolff@nvidia.com>
Signed-off-by: haydeniw <hwolff@nvidia.com>
marta-sd
approved these changes
Oct 3, 2026
kajalj22
approved these changes
Oct 4, 2026
Contributor
|
🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA-NeMo/Gym/actions/runs/37224471699 |
Merged
7 tasks done
khazic
pushed a commit
to khazic/Gym-lao
that referenced
this pull request
Oct 5, 2026
…the migration script (NVIDIA-NeMo#3929) ## What does this PR do? Since NVIDIA-NeMo#3724, config validation rejects any agent that no environment server names, with `AgentWithoutEnvironmentServerError`. A config written before environment servers therefore stops loading when Gym is upgraded. This also affects configs in this repository: `resources_servers/wordle/configs/wordle.yaml` and `environments/wordle/config.yaml` fail to parse on `main`. This PR turns that error into a deprecation, so these configs keep running while users migrate. It also fixes the migration script so it can update configs outside this repository. ### What happens to an agent without an environment server During config parsing, Gym finds each agent that no environment server names. For each one, it adds a `legacy_agent` environment server in front of the agent. A `legacy_agent` server relays `/run` to its agent unchanged, so rollouts and results are the same as before. Gym then logs one deprecation warning: ``` DEPRECATED: agents without an environment server: `workplace_assistant_simple_agent`. Rollout collection reaches an agent only through an environment server. This run generated a legacy_agent environment server for each agent above. Each one relays /run to its agent unchanged, so results are not affected. A future release will reject these configs with AgentWithoutEnvironmentServerError. To migrate, declare the environment servers in your config. Either: 1. Run the migration script from a NeMo Gym checkout on your config files or directories: python scripts/add_legacy_agent_environment_servers.py path/to/config.yaml [more paths] [--check] --check reports what would change without writing. 2. Or add these blocks yourself, at the same level as the agents: workplace_assistant_environment_server: environment_servers: legacy_agent: entrypoint: app.py agent_server: type: responses_api_agents name: workplace_assistant_simple_agent To make this an error now, set error_on_agent_without_environment_server: true in your config. You can also pass +error_on_agent_without_environment_server=true on the command line. ``` - The generated server is named the way the migration script names it: the agent type is stripped from the agent name. For example, `workplace_assistant_simple_agent` gets `workplace_assistant_environment_server`. The block in the warning is therefore the block the script writes. If that name is already taken, the server is named `<agent>_environment_server` instead. - Gym only adds a server for an agent that has none. An agent with an existing environment server is left alone, so the new server can never make agent routing ambiguous. - Setting `error_on_agent_without_environment_server: true` restores the error. It follows the existing `error_on_almost_servers` switch. The error message now also points at the migration script. - Renaming an agent with `_inherit_from` moves it to the new name. An environment server that named the old agent is then left pointing at an agent that no longer exists, and parsing fails with `ServerRefNotFoundError`. That error now says the environment server must be renamed with the agent, and points at the script. The test this PR replaces explained why the error existed: without it, a config written before environment servers "would otherwise run, silently dispatching straight to the agent." The generated server keeps that guarantee. Rollout collection still reaches the agent only through an environment server, and the warning names every server Gym added. ### Fixes to `scripts/add_legacy_agent_environment_servers.py` - The script now accepts config files and directories as arguments. Before, it could only update this repository's configs, so users had no way to migrate their own. Run without arguments, it still updates this repository's configs. - The script now skips an agent that any environment server already names. Before, it only checked whether a server with the generated name existed. In `benchmarks/swebench/pro/hermes.yaml`, a `single_agent_turn_legacy` server already fronts the agent under a different name, so the script added a second server. Two servers in front of one agent make agent routing ambiguous, and rollout collection then fails. - The script now handles an agent that only renames another one, such as `renamed_agent: {_inherit_from: some_agent}`. Before, such configs were skipped because the new instance has no agent body of its own. The script now writes a server for the new name that inherits the original agent's server. Because `_inherit_from` moves the original server, the renamed agent ends up with exactly one server. - A config that cannot be read or parsed is now reported, and the script exits with 2. Before, such files were skipped without any message. `test_langchain_deepagents_configs_have_environment_servers` now parses with `error_on_agent_without_environment_server: true`. The test checks that in-repo configs declare their environment server. A generated server would have the same name, so without strict mode the test would pass even when the declaration is missing. The script's `--check` mode reports six configs on `main` that declare no environment server: two `wordle` configs, two `swemer_oml` configs, and two `swe_internal_v1` configs. With this PR they load with the deprecation warning. Migrating them is left to their owners. No issue is linked. This is a compatibility follow-up to NVIDIA-NeMo#3724. ## Validation - `pytest tests/unit_tests/test_global_config.py`, covering the generated server, its name, the warning text, strict mode, an agent that already has a server, a name collision, a full `parse()` of a config without environment servers, and the rename hint on `ServerRefNotFoundError`. - `pytest tests/unit_tests/test_add_legacy_agent_environment_servers.py` (new), covering configs outside the repository, `--check` not writing, an agent that already has a server, a rename through `_inherit_from`, an unreadable config, and that the script and Gym name servers the same way. The behavior tests fail against the script on `main`. - Six configs outside this repository that failed validation were migrated with the script, covering both added agents and `_inherit_from` renames. Each migrated config was then parsed with `GlobalConfigDictParser` and `error_on_agent_without_environment_server: true`. An unmigrated copy, parsed the same way, raised `AgentWithoutEnvironmentServerError`. - `pytest tests/unit_tests/test_rollout_collection.py tests/unit_tests/test_environment_scaffold.py`. - `pytest tests/unit_tests`. The tests that fail in this environment fail identically on `main`. They need the `sandbox` extra, or `mlflow` and `wandb`, which NVIDIA-NeMo#3547 moved into extras. - `pre-commit run --all-files`. ## Rollouts `example_single_tool_call` was run with its environment server block removed from the config, against `Qwen/Qwen3-0.6B` served by a local vLLM with the hermes tool parser: - `gym env start` logged the deprecation warning and started the generated environment server alongside the agent, the resources server, and the model server. - `gym eval run --no-serve` completed every requested rollout without failures. Each record has the generated server in `_ng_environment_server` and `legacy_agent` in `_ng_result_type`. - When the model called `get_weather`, the verifier scored the rollout 1.0. When it answered in prose without calling the tool, the verifier scored it 0.0. Dispatch through the generated server has not changed since that run. Only the server's name and the warning text have. ## Compatibility and benchmark impact - Configs that failed with `AgentWithoutEnvironmentServerError` now load and log a deprecation warning. Results do not change, because `legacy_agent` relays `/run` to the agent unchanged. - Users who want the error back can set `error_on_agent_without_environment_server: true`. The warning tells users that a future release will make this the default. - No benchmark impact. Proposed labels: `feature`, `area:config`. ## Checklist - [x] I have read the [contributing guidelines](https://github.com/NVIDIA-NeMo/Gym/blob/main/CONTRIBUTING.md). - [x] The change is focused; unrelated "drive-by" edits are tracked as separate issues/PRs. - [x] Tests added or updated and pass locally, or N/A for docs-only / non-code changes (so CI unit/server checks pass when applicable). - [x] Documentation added or updated, or N/A with justification. - [x] Pre-commit checks pass locally (`pre-commit run --all-files`) (so CI lint/format checks pass). - [x] New source files include the required Apache-2.0 SPDX header. - [x] All commits have DCO sign-off (`git commit -s`) (so the DCO check passes). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
ananthsub
added a commit
to ananthsub/Gym
that referenced
this pull request
Oct 5, 2026
…the migration script (NVIDIA-NeMo#3929) Since NVIDIA-NeMo#3724, config validation rejects any agent that no environment server names, with `AgentWithoutEnvironmentServerError`. A config written before environment servers therefore stops loading when Gym is upgraded. This also affects configs in this repository: `resources_servers/wordle/configs/wordle.yaml` and `environments/wordle/config.yaml` fail to parse on `main`. This PR turns that error into a deprecation, so these configs keep running while users migrate. It also fixes the migration script so it can update configs outside this repository. During config parsing, Gym finds each agent that no environment server names. For each one, it adds a `legacy_agent` environment server in front of the agent. A `legacy_agent` server relays `/run` to its agent unchanged, so rollouts and results are the same as before. Gym then logs one deprecation warning: ``` DEPRECATED: agents without an environment server: `workplace_assistant_simple_agent`. Rollout collection reaches an agent only through an environment server. This run generated a legacy_agent environment server for each agent above. Each one relays /run to its agent unchanged, so results are not affected. A future release will reject these configs with AgentWithoutEnvironmentServerError. To migrate, declare the environment servers in your config. Either: 1. Run the migration script from a NeMo Gym checkout on your config files or directories: python scripts/add_legacy_agent_environment_servers.py path/to/config.yaml [more paths] [--check] --check reports what would change without writing. 2. Or add these blocks yourself, at the same level as the agents: workplace_assistant_environment_server: environment_servers: legacy_agent: entrypoint: app.py agent_server: type: responses_api_agents name: workplace_assistant_simple_agent To make this an error now, set error_on_agent_without_environment_server: true in your config. You can also pass +error_on_agent_without_environment_server=true on the command line. ``` - The generated server is named the way the migration script names it: the agent type is stripped from the agent name. For example, `workplace_assistant_simple_agent` gets `workplace_assistant_environment_server`. The block in the warning is therefore the block the script writes. If that name is already taken, the server is named `<agent>_environment_server` instead. - Gym only adds a server for an agent that has none. An agent with an existing environment server is left alone, so the new server can never make agent routing ambiguous. - Setting `error_on_agent_without_environment_server: true` restores the error. It follows the existing `error_on_almost_servers` switch. The error message now also points at the migration script. - Renaming an agent with `_inherit_from` moves it to the new name. An environment server that named the old agent is then left pointing at an agent that no longer exists, and parsing fails with `ServerRefNotFoundError`. That error now says the environment server must be renamed with the agent, and points at the script. The test this PR replaces explained why the error existed: without it, a config written before environment servers "would otherwise run, silently dispatching straight to the agent." The generated server keeps that guarantee. Rollout collection still reaches the agent only through an environment server, and the warning names every server Gym added. - The script now accepts config files and directories as arguments. Before, it could only update this repository's configs, so users had no way to migrate their own. Run without arguments, it still updates this repository's configs. - The script now skips an agent that any environment server already names. Before, it only checked whether a server with the generated name existed. In `benchmarks/swebench/pro/hermes.yaml`, a `single_agent_turn_legacy` server already fronts the agent under a different name, so the script added a second server. Two servers in front of one agent make agent routing ambiguous, and rollout collection then fails. - The script now handles an agent that only renames another one, such as `renamed_agent: {_inherit_from: some_agent}`. Before, such configs were skipped because the new instance has no agent body of its own. The script now writes a server for the new name that inherits the original agent's server. Because `_inherit_from` moves the original server, the renamed agent ends up with exactly one server. - A config that cannot be read or parsed is now reported, and the script exits with 2. Before, such files were skipped without any message. `test_langchain_deepagents_configs_have_environment_servers` now parses with `error_on_agent_without_environment_server: true`. The test checks that in-repo configs declare their environment server. A generated server would have the same name, so without strict mode the test would pass even when the declaration is missing. The script's `--check` mode reports six configs on `main` that declare no environment server: two `wordle` configs, two `swemer_oml` configs, and two `swe_internal_v1` configs. With this PR they load with the deprecation warning. Migrating them is left to their owners. No issue is linked. This is a compatibility follow-up to NVIDIA-NeMo#3724. - `pytest tests/unit_tests/test_global_config.py`, covering the generated server, its name, the warning text, strict mode, an agent that already has a server, a name collision, a full `parse()` of a config without environment servers, and the rename hint on `ServerRefNotFoundError`. - `pytest tests/unit_tests/test_add_legacy_agent_environment_servers.py` (new), covering configs outside the repository, `--check` not writing, an agent that already has a server, a rename through `_inherit_from`, an unreadable config, and that the script and Gym name servers the same way. The behavior tests fail against the script on `main`. - Six configs outside this repository that failed validation were migrated with the script, covering both added agents and `_inherit_from` renames. Each migrated config was then parsed with `GlobalConfigDictParser` and `error_on_agent_without_environment_server: true`. An unmigrated copy, parsed the same way, raised `AgentWithoutEnvironmentServerError`. - `pytest tests/unit_tests/test_rollout_collection.py tests/unit_tests/test_environment_scaffold.py`. - `pytest tests/unit_tests`. The tests that fail in this environment fail identically on `main`. They need the `sandbox` extra, or `mlflow` and `wandb`, which NVIDIA-NeMo#3547 moved into extras. - `pre-commit run --all-files`. `example_single_tool_call` was run with its environment server block removed from the config, against `Qwen/Qwen3-0.6B` served by a local vLLM with the hermes tool parser: - `gym env start` logged the deprecation warning and started the generated environment server alongside the agent, the resources server, and the model server. - `gym eval run --no-serve` completed every requested rollout without failures. Each record has the generated server in `_ng_environment_server` and `legacy_agent` in `_ng_result_type`. - When the model called `get_weather`, the verifier scored the rollout 1.0. When it answered in prose without calling the tool, the verifier scored it 0.0. Dispatch through the generated server has not changed since that run. Only the server's name and the warning text have. - Configs that failed with `AgentWithoutEnvironmentServerError` now load and log a deprecation warning. Results do not change, because `legacy_agent` relays `/run` to the agent unchanged. - Users who want the error back can set `error_on_agent_without_environment_server: true`. The warning tells users that a future release will make this the default. - No benchmark impact. Proposed labels: `feature`, `area:config`. - [x] I have read the [contributing guidelines](https://github.com/NVIDIA-NeMo/Gym/blob/main/CONTRIBUTING.md). - [x] The change is focused; unrelated "drive-by" edits are tracked as separate issues/PRs. - [x] Tests added or updated and pass locally, or N/A for docs-only / non-code changes (so CI unit/server checks pass when applicable). - [x] Documentation added or updated, or N/A with justification. - [x] Pre-commit checks pass locally (`pre-commit run --all-files`) (so CI lint/format checks pass). - [x] New source files include the required Apache-2.0 SPDX header. - [x] All commits have DCO sign-off (`git commit -s`) (so the DCO check passes). --------- Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com> (cherry picked from commit 1f2446c) Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
ananthsub
added a commit
to ananthsub/Gym
that referenced
this pull request
Oct 6, 2026
…the migration script (NVIDIA-NeMo#3929) Since NVIDIA-NeMo#3724, config validation rejects any agent that no environment server names, with `AgentWithoutEnvironmentServerError`. A config written before environment servers therefore stops loading when Gym is upgraded. This also affects configs in this repository: `resources_servers/wordle/configs/wordle.yaml` and `environments/wordle/config.yaml` fail to parse on `main`. This PR turns that error into a deprecation, so these configs keep running while users migrate. It also fixes the migration script so it can update configs outside this repository. During config parsing, Gym finds each agent that no environment server names. For each one, it adds a `legacy_agent` environment server in front of the agent. A `legacy_agent` server relays `/run` to its agent unchanged, so rollouts and results are the same as before. Gym then logs one deprecation warning: ``` DEPRECATED: agents without an environment server: `workplace_assistant_simple_agent`. Rollout collection reaches an agent only through an environment server. This run generated a legacy_agent environment server for each agent above. Each one relays /run to its agent unchanged, so results are not affected. A future release will reject these configs with AgentWithoutEnvironmentServerError. To migrate, declare the environment servers in your config. Either: 1. Run the migration script from a NeMo Gym checkout on your config files or directories: python scripts/add_legacy_agent_environment_servers.py path/to/config.yaml [more paths] [--check] --check reports what would change without writing. 2. Or add these blocks yourself, at the same level as the agents: workplace_assistant_environment_server: environment_servers: legacy_agent: entrypoint: app.py agent_server: type: responses_api_agents name: workplace_assistant_simple_agent To make this an error now, set error_on_agent_without_environment_server: true in your config. You can also pass +error_on_agent_without_environment_server=true on the command line. ``` - The generated server is named the way the migration script names it: the agent type is stripped from the agent name. For example, `workplace_assistant_simple_agent` gets `workplace_assistant_environment_server`. The block in the warning is therefore the block the script writes. If that name is already taken, the server is named `<agent>_environment_server` instead. - Gym only adds a server for an agent that has none. An agent with an existing environment server is left alone, so the new server can never make agent routing ambiguous. - Setting `error_on_agent_without_environment_server: true` restores the error. It follows the existing `error_on_almost_servers` switch. The error message now also points at the migration script. - Renaming an agent with `_inherit_from` moves it to the new name. An environment server that named the old agent is then left pointing at an agent that no longer exists, and parsing fails with `ServerRefNotFoundError`. That error now says the environment server must be renamed with the agent, and points at the script. The test this PR replaces explained why the error existed: without it, a config written before environment servers "would otherwise run, silently dispatching straight to the agent." The generated server keeps that guarantee. Rollout collection still reaches the agent only through an environment server, and the warning names every server Gym added. - The script now accepts config files and directories as arguments. Before, it could only update this repository's configs, so users had no way to migrate their own. Run without arguments, it still updates this repository's configs. - The script now skips an agent that any environment server already names. Before, it only checked whether a server with the generated name existed. In `benchmarks/swebench/pro/hermes.yaml`, a `single_agent_turn_legacy` server already fronts the agent under a different name, so the script added a second server. Two servers in front of one agent make agent routing ambiguous, and rollout collection then fails. - The script now handles an agent that only renames another one, such as `renamed_agent: {_inherit_from: some_agent}`. Before, such configs were skipped because the new instance has no agent body of its own. The script now writes a server for the new name that inherits the original agent's server. Because `_inherit_from` moves the original server, the renamed agent ends up with exactly one server. - A config that cannot be read or parsed is now reported, and the script exits with 2. Before, such files were skipped without any message. `test_langchain_deepagents_configs_have_environment_servers` now parses with `error_on_agent_without_environment_server: true`. The test checks that in-repo configs declare their environment server. A generated server would have the same name, so without strict mode the test would pass even when the declaration is missing. The script's `--check` mode reports six configs on `main` that declare no environment server: two `wordle` configs, two `swemer_oml` configs, and two `swe_internal_v1` configs. With this PR they load with the deprecation warning. Migrating them is left to their owners. No issue is linked. This is a compatibility follow-up to NVIDIA-NeMo#3724. - `pytest tests/unit_tests/test_global_config.py`, covering the generated server, its name, the warning text, strict mode, an agent that already has a server, a name collision, a full `parse()` of a config without environment servers, and the rename hint on `ServerRefNotFoundError`. - `pytest tests/unit_tests/test_add_legacy_agent_environment_servers.py` (new), covering configs outside the repository, `--check` not writing, an agent that already has a server, a rename through `_inherit_from`, an unreadable config, and that the script and Gym name servers the same way. The behavior tests fail against the script on `main`. - Six configs outside this repository that failed validation were migrated with the script, covering both added agents and `_inherit_from` renames. Each migrated config was then parsed with `GlobalConfigDictParser` and `error_on_agent_without_environment_server: true`. An unmigrated copy, parsed the same way, raised `AgentWithoutEnvironmentServerError`. - `pytest tests/unit_tests/test_rollout_collection.py tests/unit_tests/test_environment_scaffold.py`. - `pytest tests/unit_tests`. The tests that fail in this environment fail identically on `main`. They need the `sandbox` extra, or `mlflow` and `wandb`, which NVIDIA-NeMo#3547 moved into extras. - `pre-commit run --all-files`. `example_single_tool_call` was run with its environment server block removed from the config, against `Qwen/Qwen3-0.6B` served by a local vLLM with the hermes tool parser: - `gym env start` logged the deprecation warning and started the generated environment server alongside the agent, the resources server, and the model server. - `gym eval run --no-serve` completed every requested rollout without failures. Each record has the generated server in `_ng_environment_server` and `legacy_agent` in `_ng_result_type`. - When the model called `get_weather`, the verifier scored the rollout 1.0. When it answered in prose without calling the tool, the verifier scored it 0.0. Dispatch through the generated server has not changed since that run. Only the server's name and the warning text have. - Configs that failed with `AgentWithoutEnvironmentServerError` now load and log a deprecation warning. Results do not change, because `legacy_agent` relays `/run` to the agent unchanged. - Users who want the error back can set `error_on_agent_without_environment_server: true`. The warning tells users that a future release will make this the default. - No benchmark impact. Proposed labels: `feature`, `area:config`. - [x] I have read the [contributing guidelines](https://github.com/NVIDIA-NeMo/Gym/blob/main/CONTRIBUTING.md). - [x] The change is focused; unrelated "drive-by" edits are tracked as separate issues/PRs. - [x] Tests added or updated and pass locally, or N/A for docs-only / non-code changes (so CI unit/server checks pass when applicable). - [x] Documentation added or updated, or N/A with justification. - [x] Pre-commit checks pass locally (`pre-commit run --all-files`) (so CI lint/format checks pass). - [x] New source files include the required Apache-2.0 SPDX header. - [x] All commits have DCO sign-off (`git commit -s`) (so the DCO check passes). --------- Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com> (cherry picked from commit 1f2446c) Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
khazic
pushed a commit
to khazic/Gym-lao
that referenced
this pull request
Oct 15, 2026
…EADME (NVIDIA-NeMo#4574) ## What does this PR do? The math_with_judge README's "Prepare for trajectory collection" command works again. It loads `configs/dapo17k_trajectory_collection.yaml`, which no longer exists, so `gym dataset collate` exited with `ConfigPathNotFoundError` before downloading anything. This PR restores that config in the current schema, documents the step's prerequisites, and adds a regression test that replays the README command. Running the README's other GitLab download, OpenMathReasoning, from outside the Gym root exposed a second bug: the GitLab downloader did not create the output directory. The second commit fixes it. Fixes NVBug [6847517](https://nvbugspro.nvidia.com/bug/6847517). Closes NVIDIA-NeMo#4498. ### Cause NVIDIA-NeMo#859 ("Gym 0.2.0 huggingface dataset pointers") deleted three dapo17k variants under `resources_servers/math_with_judge/configs/`, including `dapo17k_trajectory_collection.yaml`, and removed their root-README rows. The math_with_judge README, which has cited that file since NVIDIA-NeMo#291, was not updated. Config resolution (`nemo_gym/global_config.py` `load_extra_config_paths`) then raises `ConfigPathNotFoundError`. `dapo17k.yaml` is not a drop-in replacement. The deleted config put the DAPO17k train problems in the **validation** split, repeated 16 times, because NeMo RL with `is_trajectory_collection: true` collects from the validation dataloader only. `dapo17k.yaml` has DAPO17k as `train` ×1 and AIME24 ×32 as `validation`, so trajectory collection would run on AIME24. Restoring the old file verbatim would not work either. It set `judge_model_server.name: ???`, and since NVIDIA-NeMo#1575 the parser rejects any `???` left after merging (`ConfigMissingValuesError`). The second bug is in `download_jsonl_dataset` (`nemo_gym/gitlab_utils.py`). It opened `output_fpath` for writing without creating its directory. A Gym checkout tracks `data/`, so the README's `--output data/open_math_reasoning_problems.jsonl` works from the Gym root but fails with `FileNotFoundError` from any other directory. `gym dataset collate --download` fails the same way for GitLab-backed datasets. The Hugging Face download already creates the directory (`hf_utils.py`). ### Fix - Restore `configs/dapo17k_trajectory_collection.yaml`. The validation split is the `dapo17k` 0.0.1 `dapo17k_train.jsonl` artifact (the same GitLab source as `dapo17k.yaml`), `num_repeats: 16`. Grading uses math-verify only (`should_use_judge: false`), so `judge_model_server.name` is `policy_model` and the README command needs no override. The file has `description`/`value` and the environment-server block like `dapo17k.yaml`. The `update-readme-table` hook re-adds its root-README row. - It keeps its own local file, `data/dapo17k_trajectory_collection_train.jsonl`, as before NVIDIA-NeMo#859. Collate checks each dataset against `<jsonl stem>_metrics.json`. Sharing `dapo17k.yaml`'s `dapo17k_train.jsonl` would compare the ×16 validation stats with that file's train sidecar and fail (`train != validation`, `17398 != 278368`). - Add `data/dapo17k_trajectory_collection_train_metrics.json`, written by a real collate run (278368 rows = 17398 × 16). Its word and turn statistics match `dapo17k_train_metrics.json` exactly, so the rows are the same. - README: the command is unchanged. One note says the GitLab downloads in this README (the OpenMathReasoning download and this `--download`) need the `mlflow` extra (optional since NVIDIA-NeMo#3547) and `mlflow_tracking_uri` / `mlflow_tracking_token` in `env.yaml`. The section says what it writes and why the split is validation. Test: `tests/unit_tests/test_math_with_judge_readme_trajectory_config.py` takes the README's `gym dataset collate` block and runs it through the real CLI with `dispatch` intercepted. It resolves the config offline (no `env.yaml`), checks the single dataset is `validation` ×16 with `dapo17k.yaml`'s GitLab identifier, and checks the committed sidecar describes that split. It then runs `TrainDataProcessor` on a three-row fixture in a temporary directory, without network access, and checks that only `validation.jsonl` and its metrics come out, with each question repeated 16 times in order. - `download_jsonl_dataset` now creates the output's parent directory, as the Hugging Face download does. A new test in `tests/unit_tests/test_gitlab_utils.py` fakes the registry lookup and the HTTP fetch, then downloads into a missing nested directory. It fails before this change with the same `FileNotFoundError` and passes after. These plausible wrong fixes all fail the trajectory test: - restoring the file verbatim (`???`); - pointing the README at `dapo17k.yaml` with a judge override; - `num_repeats: 1`; - a `train` split; - sharing `dapo17k_train.jsonl`. ### Before the fix Gym `977583d3d` (`main`), the README command from the Gym root: ```bash gym dataset collate \ --config resources_servers/math_with_judge/configs/dapo17k_trajectory_collection.yaml \ --config responses_api_models/openai_model/configs/openai_model.yaml \ --output-dir data/dapo17k_trajectory_collection \ --mode train_preparation \ --download ``` ```text nemo_gym.config_types.ConfigPathNotFoundError: config_paths entry 'resources_servers/math_with_judge/configs/dapo17k_trajectory_collection.yaml' was not found. Looked in: - <gym>/resources_servers/math_with_judge/configs/dapo17k_trajectory_collection.yaml Check the path is spelled correctly and is relative to your working directory, an extra root (NEMO_GYM_EXTRA_ROOTS / --search-dir), or the Gym install root. EXIT=1 ``` The README's OpenMathReasoning GitLab download, from a directory without `data/`, same base: ```bash gym dataset download --storage gitlab --name math_open_math_reasoning --revision 0.0.1 \ --artifact open_math_reasoning_problems.jsonl --output data/open_math_reasoning_problems.jsonl ``` ```text File ".../nemo_gym/gitlab_utils.py", line 111, in download_jsonl_dataset with open(config.output_fpath, "w") as f: FileNotFoundError: [Errno 2] No such file or directory: '<workspace>/data/open_math_reasoning_problems.jsonl' ``` ### After the fix This branch, same command, with the `mlflow` extra and GitLab registry credentials in `env.yaml`. No local data beforehand: ```text Downloading dataset `validation` for `math_with_judge_simple_agent` from gitlab using dataset_name='dapo17k' version='0.0.1' artifact_fpath='dapo17k_train.jsonl' output_fpath='resources_servers/math_with_judge/data/dapo17k_trajectory_collection_train.jsonl' Dataset validation repeating 16x: each line repeated 16 times (e.g. pattern: abc -> aaaabbbbcccc) Aggregate metrics for resources_servers/math_with_judge/data/dapo17k_trajectory_collection_train_metrics.json Aggregate metrics for data/dapo17k_trajectory_collection/validation_metrics.json EXIT=0 $ wc -l data/dapo17k_trajectory_collection/validation.jsonl 278368 data/dapo17k_trajectory_collection/validation.jsonl ``` There are 17398 runs of identical questions, each 16 rows long, and no `train.jsonl`. A second run skips the download, reports the sidecar `already up to date`, and exits 0. The OpenMathReasoning download, same command and directory: exit 0, with the file written (the QA case below checks its rows). ### Validation - QA testcase `math_with_judge`, which runs both README GitLab steps from a scratch directory with registry credentials: - base `977583d3d`: 0/2. Trajectory collation fails because the config is missing; the download fails with `FileNotFoundError`. - this branch: 2/2. The download passes in 4.4 s; the trajectory collation passes in 20.3 s with 17398 × 16 rows and the committed sidecar unchanged. - The QA-suite change ships separately. - New tests: trajectory test before 1 failed (`ConfigPathNotFoundError`), after 1 passed, and the five wrong fixes above fail it. Downloader test before 1 failed (`FileNotFoundError`), after 1 passed, also with the real `mlflow` 3.16.1 installed. - `test_train_data_utils.py`, `test_cli_main.py`, `test_global_config.py`, `test_dataset_source.py`, `test_task_data.py::TestSchemaPresence`, `test_ray_opt_out.py`, `test_cli_resources_servers.py`, `test_model_registry.py`, `test_resources_server_registry.py`, `test_environment_scaffold.py`, `test_gitlab_utils.py`, `test_hf_utils.py`, and the new tests: 592 passed. - `pre-commit run --all-files`: passed. - Rollout evidence: N/A. This is a config and docs change, and `gym dataset collate` runs no model. The full download-and-collate run above uses the real registry data. ### Compatibility A new config file. Nothing that loads other configs changes. GitLab downloads now create a missing output directory instead of failing. The restored config uses the same GitLab artifact as `dapo17k.yaml`, but a separate local file, so each keeps its own metrics sidecar. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: qiaochuz <qiaochuz@nvidia.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This branch was previously deployed
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.
What does this PR do?
Moves optional exporter deps into
pyproject.tomlextras so they are not automatically installed.Closes #3207
Checklist
pre-commit run --all-files) (so CI lint/format checks pass).git commit -s) (so the DCO check passes).