feat(cli): config_composer for agent/dataset composition (RFC M3)#1673
Open
wprazuch wants to merge 2 commits into
Open
feat(cli): config_composer for agent/dataset composition (RFC M3)#1673wprazuch wants to merge 2 commits into
wprazuch wants to merge 2 commits into
Conversation
707d816 to
f6da402
Compare
2949bea to
1910101
Compare
9740d8f to
d14dc18
Compare
1910101 to
4ea15e4
Compare
d14dc18 to
8c34493
Compare
2a9eaf8 to
ad4cbf3
Compare
21d5994 to
1e62870
Compare
wprazuch
added a commit
that referenced
this pull request
Jun 25, 2026
…duplicates the asset selector Per a duplication audit against main: resolve_agent_config_path was dead code in this PR (no CLI wires it) and reinvented the unified CLI`s generic name->config resolution (cli/main.py _asset_config_path) — the same pattern #1635 deliberately removed on the environment side. Drop it (and its AgentNotFound/Variant/NotComposable errors and the duplicate _did_you_mean). This PR is now purely discovery + Pattern A/B classification + `gym list agents`. Run-by-name resolution (with the require_composable guard) will land with its real consumer, the config composer (#1673), as an `agent` asset row rather than a parallel resolver. Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
wprazuch
added a commit
that referenced
this pull request
Jun 25, 2026
… core) (#1671) ## What Adds `nemo_gym.agent_registry` + the **`gym list agents`** command — the foundation for RFC **M3 / friction 6** ("every agent×environment combination requires a separate config"). Maps an agent's short `<name>` (directory under `responses_api_agents/`) to its config variant(s) and classifies how each harness composes. ## `gym list agents` (CLI) Lists every discovered agent and its composition pattern — the one thing the unified CLI's generic `--<asset>` selectors can't surface. Table + `--json`, mirroring `gym list benchmarks` / `gym list environments` (#1635). ``` $ gym list agents agent composition variants description simple_agent composable (A) simple_agent swe_agents self-contained (B) swebench_openhands, ... Software engineering tasks ... ... ``` Across the repo: **23 agents — 15 Pattern A (composable), 8 Pattern B (self-contained).** ## API - `discover_agents() -> Dict[str, AgentEntry]` — one entry per agent dir; `AgentEntry(name, path, config_paths, self_contained, description)` with a `.variants` map (variant stem → config). - `resolve_agent_config_path(name, variant=None, *, require_composable=False) -> str` — explicit variant wins; a single config is used directly; a variant named after the agent is the default when several exist; otherwise raises. The run-by-name primitive consumed by the composer (#1673). - Errors: `AgentNotFoundError` (did-you-mean), `AgentVariantError` (zero-config / ambiguous), `AgentNotComposableError` (for the composer's `require_composable` guard). ## Composition classification (`self_contained`) - **Pattern A (`self_contained=False`):** references a *separate* `resources_server` → wireable into a compatible environment (e.g. `simple_agent`, `langgraph_agent`). Which harness↔resources-server pairings are actually compatible is the **composer's** concern, not the registry's. - **Pattern B (`self_contained=True`):** bundles its own environment/framework or external LLM loop (`agent_framework`; e.g. `swe_agents`, `harbor_agent`, `verifiers_agent`, `claude_code_agent`) and runs with its own config. `require_composable=True` rejects these with a clear error. - Non-agent YAML in a `configs/` dir is filtered out; zero-config agents (e.g. `aviary_agent`) are still discovered (their wiring lives in a paired benchmark/resources config). Resolution-safe (`resolve=False, throw_on_missing=False`; never starts servers), so it works with unset secrets. > Reflects @cmunley1's review: classification reframed around Pattern A vs self-contained B, field renamed `composable`→`self_contained`, and cross-pattern compatibility documented as the composer's job (separate commit, history preserved). ## Tests `test_agent_registry.py` (21 cases — A/B classification, external-harness carve-out, zero-config, variant selection, did-you-mean, `require_composable`) + `test_cli_agents.py` / `test_cli_main.py` (`gym list agents` table / empty / `--json` / router dispatch). Part of epic #1205 (M3 / friction 6). --------- Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
ad4cbf3 to
8c4143d
Compare
5 tasks
1 task
ritaneves
pushed a commit
that referenced
this pull request
Jun 25, 2026
… core) (#1671) ## What Adds `nemo_gym.agent_registry` + the **`gym list agents`** command — the foundation for RFC **M3 / friction 6** ("every agent×environment combination requires a separate config"). Maps an agent's short `<name>` (directory under `responses_api_agents/`) to its config variant(s) and classifies how each harness composes. ## `gym list agents` (CLI) Lists every discovered agent and its composition pattern — the one thing the unified CLI's generic `--<asset>` selectors can't surface. Table + `--json`, mirroring `gym list benchmarks` / `gym list environments` (#1635). ``` $ gym list agents agent composition variants description simple_agent composable (A) simple_agent swe_agents self-contained (B) swebench_openhands, ... Software engineering tasks ... ... ``` Across the repo: **23 agents — 15 Pattern A (composable), 8 Pattern B (self-contained).** ## API - `discover_agents() -> Dict[str, AgentEntry]` — one entry per agent dir; `AgentEntry(name, path, config_paths, self_contained, description)` with a `.variants` map (variant stem → config). - `resolve_agent_config_path(name, variant=None, *, require_composable=False) -> str` — explicit variant wins; a single config is used directly; a variant named after the agent is the default when several exist; otherwise raises. The run-by-name primitive consumed by the composer (#1673). - Errors: `AgentNotFoundError` (did-you-mean), `AgentVariantError` (zero-config / ambiguous), `AgentNotComposableError` (for the composer's `require_composable` guard). ## Composition classification (`self_contained`) - **Pattern A (`self_contained=False`):** references a *separate* `resources_server` → wireable into a compatible environment (e.g. `simple_agent`, `langgraph_agent`). Which harness↔resources-server pairings are actually compatible is the **composer's** concern, not the registry's. - **Pattern B (`self_contained=True`):** bundles its own environment/framework or external LLM loop (`agent_framework`; e.g. `swe_agents`, `harbor_agent`, `verifiers_agent`, `claude_code_agent`) and runs with its own config. `require_composable=True` rejects these with a clear error. - Non-agent YAML in a `configs/` dir is filtered out; zero-config agents (e.g. `aviary_agent`) are still discovered (their wiring lives in a paired benchmark/resources config). Resolution-safe (`resolve=False, throw_on_missing=False`; never starts servers), so it works with unset secrets. > Reflects @cmunley1's review: classification reframed around Pattern A vs self-contained B, field renamed `composable`→`self_contained`, and cross-pattern compatibility documented as the composer's job (separate commit, history preserved). ## Tests `test_agent_registry.py` (21 cases — A/B classification, external-harness carve-out, zero-config, variant selection, did-you-mean, `require_composable`) + `test_cli_agents.py` / `test_cli_main.py` (`gym list agents` table / empty / `--json` / router dispatch). Part of epic #1205 (M3 / friction 6). --------- Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com> Signed-off-by: Rita Fernandes Neves <rfernandesne@nvidia.com>
wprazuch
added a commit
that referenced
this pull request
Jun 29, 2026
PR #1673 added the `gym env compose` command (agent/dataset composition) but did not document it. Add it to the Environments quick-reference list and a dedicated section with flags and examples, mirroring the sibling commands. Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
|
🌿 Preview your docs: https://nvidia-preview-wprazuch-config-composer.docs.buildwithfern.com/nemo/gym Here are the markdown pages you've updated: |
wprazuch
added a commit
that referenced
this pull request
Jun 29, 2026
Resolve PR #1673 conflicts with main (now includes #1804/#1805/#1806). The gym env compose work coexists with #1805's install-root _asset_config_path and the agent asset selector in nemo_gym/cli/main.py; both `env compose` and `env validate` remain registered. Auto-merge verified: no conflict markers, 167 unit tests pass (only the pre-existing TestDidYouMean argparse failures), and `gym env compose --benchmark gsm8k --agent simple_agent` + `gym env validate` both work. Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
533ea92 to
38e90c0
Compare
38e90c0 to
72ef9e6
Compare
…ition (RFC M3) Compose a benchmark with a swapped agent harness and/or edited benchmark-dataset params, without writing a bespoke per-combination config (epic #1205, criterion C3): - nemo_gym/config_composer.py: compose(), substitute_agent() (wires the env's resources_server/model_server/datasets into the swapped agent, filling a generic agent's mandatory resources_server.name), find_agent_block_key, substitute_dataset_params, _validate_no_mandatory_placeholders (scans for remaining ??? WITHOUT resolving interpolations), and a composability guard (Pattern B rejected). - gym env compose command + an agent asset selector in the unified CLI. - docs: document gym env compose in the CLI reference. Rebased onto current main (composes with #1805/#1806/#1807): #1807's env.py install-root resolution + validate preserved; gym env compose and gym env validate coexist. Verified: compose --benchmark gsm8k --agent simple_agent wires resources_server; validate works; env-test resolution intact. Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
72ef9e6 to
1cb55e6
Compare
Contributor
Author
|
Closing as deferred |
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
Adds
nemo_gym/config_composer.py(RFC M3 / friction 6): a pure, resolution-safe composer that rewrites an already-merged OmegaConfDictConfig(the kind produced by Gym's Hydra stack from a benchmarkconfig.yaml) along two axes — agent and dataset.It never starts servers, reads secrets, resolves interpolations (
resolve=False), or emits Hydra override tokens. It returns a newDictConfig; an empty request is a pure passthrough.What it does
find_agent_block_key— locate the single top-level block whoseresponses_api_agents.<type>carries atype: benchmarkdataset (mirrorsbenchmarks.py); raiseNoComposableAgentBlockErrorfor zero or ambiguous targets (candidates listed).substitute_agent— swap the composable harness, loading the new agent viaresolve_agent_config_path(new_agent, require_composable=True). A Pattern B (self-contained) agent raisesagent_registry.AgentNotComposableError(propagated). The env'sresources_server/model_server(name: policy_model) /datasetswin over the agent config's own values, and the inner block is re-keyed to<new_agent>.substitute_dataset_params— editnum_repeats/prompt_configon the single benchmark dataset entry; no-op forNone.substitute_model— documented no-op shim. The model axis is deferred to the CLI's--model*flags, which run before composition._validate_no_mandatory_placeholders— reject any remaining???(OmegaConf.is_missing) field in the agent block and its referenced resources-server block, without resolving interpolations.compose— pipeline:find_agent_block_key→substitute_agent(if requested) →substitute_dataset_params→_validate_no_mandatory_placeholders.Tests
tests/unit_tests/test_config_composer.py— 24 tests, 100% module coverage. Covers dataset-param substitution, agent swap (wiring carry-over + re-keying), placeholder validation (raise on???, pass when filled), empty-request passthrough, zero/ambiguous agent block →NoComposableAgentBlockError, and Pattern B →AgentNotComposableErrorviarequire_composable. Synthetic mergedDictConfigs are built inline; the agent resolver is injected as a stub.