Skip to content

fix(cli): treat servers nested three levels deep as editable installs - #4464

Merged
ananthsub merged 1 commit into
mainfrom
cmunley1/setup-nested-editable-install
Oct 12, 2026
Merged

ananthsub merged 1 commit into
mainfrom
cmunley1/setup-nested-editable-install

Conversation

@cmunley1

Copy link
Copy Markdown
Contributor

Servers three levels below the repo root (e.g. conversational_tool_use/simulation) failed the two-level pyproject.toml check, so their venvs installed nemo-gym from the package index instead of the local checkout.

Checks one more level up. Unit test added.

The two-level pyproject.toml check missed nested servers (e.g. conversational_tool_use/simulation), so their venvs installed nemo-gym from the package index instead of the checkout.

Signed-off-by: Christian Munley <cmunley@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Oct 12, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@cmunley1
cmunley1 marked this pull request as ready for review October 12, 2026 08:49
@cmunley1

Copy link
Copy Markdown
Contributor Author

/ok to test 77111e6

@nemo-automation-bot
nemo-automation-bot Bot requested review from a team October 12, 2026 08:50
@yaoyu-33 yaoyu-33 added area:cli Command-line interfaces and user-facing command behavior bug Something isn't working complexity:low Localized change in one scope with a small, straightforward review surface needs-review PR is ready for code review and waiting on a reviewer labels Oct 12, 2026
@ananthsub
ananthsub added this pull request to the merge queue Oct 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA-NeMo/Gym/actions/runs/38258590564

Merged via the queue into main with commit ac8057c Oct 12, 2026
52 of 54 checks passed
@ananthsub
ananthsub deleted the cmunley1/setup-nested-editable-install branch October 12, 2026 14:07
dims pushed a commit to dims/Nemo-Gym that referenced this pull request Oct 14, 2026
…train judge JSON, report mask_sample (NVIDIA-NeMo#4568)

## What does this PR do?

The nested conversational tool-use environment
(`resources_servers/conversational_tool_use_simulation` with the
`conversational_tool_use/simulation` agent) now starts from a source
checkout, and its rollouts are graded and
masked correctly. Before this PR its stack never came up: every model
server bound to the agent crashed during
startup. Behind that crash were two more defects, which this PR also
fixes. The trajectory judge often returned JSON
that failed validation, and the server's mask decision never reached the
`mask_sample` field that Gym and trainers read.

Fixes NVBug [6847461](https://nvbugspro.nvidia.com/bug/6847461). Closes
NVIDIA-NeMo#4497.

### Cause

1. **Startup crash.** `ServerClient.assistant_message_header`
(`nemo_gym/server_utils.py:825`, added by NVIDIA-NeMo#3711)
imports `responses_api_agents.{harness}` with the raw config key. Nested
harnesses are keyed by directory path,
so `conversational_tool_use/simulation` raises `ModuleNotFoundError` in
`policy_model` setup
(`base_responses_api_model.py:286`). The venv blocker in the same NVBug
(a pin to `nemo-gym==<version>`) was
   already fixed by NVIDIA-NeMo#4464.
2. **Unparseable judge output.** The judge prompt contains
`Evaluation.model_json_schema()` as text, and the reply
is parsed with `model_validate_json`, with no decoding constraint (since
NVIDIA-NeMo#2111). With the QA model (temperature 1.0), the
step-0 judgement failed all 3 attempts in 3 of 3 runs. Replies either
wrapped the instance in
`{"properties": {...}}` or left a string unquoted, so the row got
`verification_generation_error`.
3. **Mask dropped.** NVIDIA-NeMo#2111 reported the mask decision only as
`instance_config.mask_sample`. NVIDIA-NeMo#2611 later made
`BaseVerifyResponse.mask_sample` the contract. This environment was
never migrated, so simulator, tool, and judge
   failures reached rollouts with `mask_sample: false` and reward 0.

### Fix

1. Map `/` to `.` before importing the harness package.
2. When `judge_responses_create_params.text` is not configured, the
judge requests Responses
`text.format` (`json_schema`) for `Evaluation`, or for
`UserAgentEnvironmentEvaluation` in combined mode. A
configured `text` still wins. `openai_model` forwards it to the
provider; the chat converter maps it to
   `response_format`.
3. The resources server's `/verify` and the agent's transient-failure
response set top-level `mask_sample`.
`instance_config` is removed, and the checked-in
`example_rollouts.jsonl` is migrated. The README states the
   masking rule.

Rejected: catching `ImportError` in `assistant_message_header`. It would
hide a declared header from any nested
harness, and the new test fails on it.

### Before the fix

Gym `4a101eeb5` (main), QA case `conversational_tool_use_simulation`:

```bash
./run.sh test conversational_tool_use_simulation --ref 4a101ee --no-ai-log
```

```text
nemo_gym/base_responses_api_model.py", line 286, in setup_webserver
    assistant_message_header=self.server_client.assistant_message_header(self.config.name),
nemo_gym/server_utils.py", line 825, in assistant_message_header
ModuleNotFoundError: No module named 'responses_api_agents.conversational_tool_use/simulation'
RuntimeError: Process `policy_model` finished unexpectedly!
  ERROR (30.2s): StackStartupError: `gym env start` exited with code 1 during child startup
conversational_tool_use_simulation: 0/3 passed in 90.6s
```

With only the import fixed (intermediate commit), the stack started but
the judge failed to parse:

```text
FAIL (78.7s): original conversation has no generation or verification failures: expected [], got ['verification_generation_error']
generation_error = 2 validation errors for Evaluation
success
  Field required [type=missing, input_value={'properties': {'success'...tion', 'type': 'object'}, input_type=dict]
```

### After the fix

Gym `29d57f66c` (this branch before a rebase onto `977583d3d`; the one
new main commit touches no file in this diff), same command:

```bash
./run.sh test conversational_tool_use_simulation --ref 29d57f66c --no-ai-log
```

```text
PASS   373.9s  the canonical one-example conversation uses live roles and verifies session disposal and grading gates
PASS    79.1s  enable_llm_judge=false scores a complete conversation 1.0 without calling the judge
PASS    49.8s  complete_trajectory_combined_evaluation judges the whole conversation once with per-role verdicts
conversational_tool_use_simulation: 3/3 passed in 502.8s
```

### Validation

- QA testcase `conversational_tool_use_simulation` (3 cases: canonical
message-level judge, `enable_llm_judge=false`,
`complete_trajectory_combined_evaluation`): 0/3 on main (stack startup),
3/3 on this branch. The canonical case also replays the recorded
conversation and checks the step limit (`excessive_length`, not masked),
`###TRANSFER###` with both scope labels, and rejection of malformed
history (25 direct resources-server calls).
- Judge-format probe against the QA endpoint, 6 calls each: prompt-only
schema gave 5/6 valid replies, `text.format`
  gave 6/6.
- After the rebase (head `a3a6ab1f4`), I reran `test_server_utils.py`
(173), `gym env test` for the server (78), and the agent tests (36): all
pass.
- `tests/unit_tests/test_server_utils.py`: 173 passed. The new
`test_model_header_imports_nested_harness_key` fails on
  main, and also fails on a catch-`ImportError` fix.
- `gym env test --resources-server conversational_tool_use_simulation`:
78 passed. New judge structured-output
tests cover both judge paths and a configured `text`. 8 mask assertions
now check top-level `mask_sample`, and the
  example-rollout contract test checks the masking rule.
- `responses_api_agents/conversational_tool_use/simulation/tests`: 36
passed. 4 mask assertions moved to `mask_sample`.
- `tests/unit_tests` (Mac): same 43 pre-existing failures as main, plus
the new passing test. In one full
run,
`test_slurm_script.py::…multi_node_chain_survives_symmetric_run_entrypoint`
also failed (a `bash` subprocess
with a 10 s timeout). It passes 3/3 alone on both trees and 226/226 as a
file, and this diff does not touch it.
- `pre-commit run --all-files`: passed, no changes
- Rollout evidence: the QA case above runs live rollouts. The policy,
simulator, and judge all use
  `nvidia/nvidia/nemotron-3.5-super-vl-preview` through `openai_model`.

### Compatibility

- Consumers that read `instance_config.mask_sample` from this
environment, such as older NeMo RL, no longer get a
mask. They should read top-level `mask_sample`, like every other
environment.
- The judge request now includes `text.format`. A provider that rejects
`json_schema` structured output can turn it
  off by setting `judge_responses_create_params.text.format.type=text`.
- With a live judge, rows that it scores as user or tool failures are
now masked. Before this PR they counted as
  reward-0 policy samples.

🤖 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>
jkyi-nvidia added a commit that referenced this pull request Oct 15, 2026
…_tool_use_{stage}

The four conversational tool-use agents were nested under
responses_api_agents/conversational_tool_use/, which Gym's flat
responses_api_agents/<name> layout does not expect. #4464 and #4568 added
framework workarounds for the nesting.

Move each stage to a top-level agent directory:

  conversational_tool_use/domain_generation       -> conversational_tool_use_domain_generation
  conversational_tool_use/policy_tool_generation  -> conversational_tool_use_policy_tool_generation
  conversational_tool_use/scenario_generation     -> conversational_tool_use_scenario_generation
  conversational_tool_use/simulation              -> conversational_tool_use_simulation

- Rename harness keys in agent configs and the resources-server config
  (including allowed_agents), and update imports, hardcoded paths in
  prepare.py, tests, scripts, and docs.
- Point each agent's requirements.txt at the repo root with ../../.
- Drop the orphaned parent __init__.py, requirements.txt, and index README
  (the resources-server README already carries the same component table
  and Prepare Assets section).
- Revert the nested-path workarounds in nemo_gym/server_utils.py and
  nemo_gym/cli/setup_command.py, with their tests; nothing else is nested.

Metric names under the conversational_tool_use/ namespace are unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
jkyi-nvidia added a commit that referenced this pull request Oct 16, 2026
…_tool_use_{stage}

The four conversational tool-use agents were nested under
responses_api_agents/conversational_tool_use/, which Gym's flat
responses_api_agents/<name> layout does not expect. #4464 and #4568 added
framework workarounds for the nesting.

Move each stage to a top-level agent directory:

  conversational_tool_use/domain_generation       -> conversational_tool_use_domain_generation
  conversational_tool_use/policy_tool_generation  -> conversational_tool_use_policy_tool_generation
  conversational_tool_use/scenario_generation     -> conversational_tool_use_scenario_generation
  conversational_tool_use/simulation              -> conversational_tool_use_simulation

- Rename harness keys in agent configs and the resources-server config
  (including allowed_agents), and update imports, hardcoded paths in
  prepare.py, tests, scripts, and docs.
- Point each agent's requirements.txt at the repo root with ../../.
- Drop the orphaned parent __init__.py, requirements.txt, and index README
  (the resources-server README already carries the same component table
  and Prepare Assets section).
- Revert the nested-path workarounds in nemo_gym/server_utils.py and
  nemo_gym/cli/setup_command.py, with their tests; nothing else is nested.

Metric names under the conversational_tool_use/ namespace are unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>

This branch was previously deployed

1 inactive deployment
public — 77111e6b Deployed Oct 12, 2026 by copy-pr-bot[bot] via release / finalize / notify #5019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:cli Command-line interfaces and user-facing command behavior bug Something isn't working complexity:low Localized change in one scope with a small, straightforward review surface needs-review PR is ready for code review and waiting on a reviewer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants