Repository navigation
fix(conversational_tool_use): start the nested simulation stack, constrain judge JSON, report mask_sample - #4568
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: qiaochuz <qiaochuz@nvidia.com>
… trajectory judge Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: qiaochuz <qiaochuz@nvidia.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: qiaochuz <qiaochuz@nvidia.com>
Contributor
Author
|
/ok to test a3a6ab1 |
yaoyu-33
approved these changes
Oct 13, 2026
yaoyu-33
left a comment
Contributor
There was a problem hiding this comment.
LGTM. Reviewed the nested import, judge JSON schema, and top-level mask_sample changes; 250 focused tests passed locally. The Hermes model_error conformance check still needs to be cleared before merge.
Contributor
|
🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA-NeMo/Gym/actions/runs/38486441840 |
Contributor
Author
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>
linj-glitch
pushed a commit
to linj-glitch/Gym
that referenced
this pull request
Oct 16, 2026
…act when the opening user message fails (NVIDIA-NeMo#4641) ## What does this PR do? Upstreams NVIDIA-NeMo#3111 to `main`. NVIDIA-NeMo#3111 was merged only into `super-v3.5-posttraining`. When the user simulator fails on the opening user message, the conversational tool-use server now opens the conversation with the scenario's `reason_for_contact`. Before, it ended the trajectory before the policy spoke. A failure here means the simulator raised an error, or its first message already contained `###STOP###` or `###TRANSFER###`. ### Cause In both failure cases the server marked the trajectory invalid or terminal at turn 0. The agent then returned a response with an empty `output` list. NeMo RL `main` cannot represent a sample with no policy tokens. It raises before any mask is read, so one such row can fail the rollout batch. ### Fix - When no user message exists yet, the server uses `customer_scenario.reason_for_contact` as the first user message. If that is empty or contains `###STOP###` or `###TRANSFER###`, it uses a generic request (`DEFAULT_FIRST_USER_MESSAGE`). A `###STOP###`/`###TRANSFER###` message triggers the fallback only when nothing precedes it in the conversation; a generation error triggers it whenever no user message exists yet. - Each fallback is appended to `result.source_artifacts.first_user_message_fallbacks`, so each fallback stays visible in the rollout result. - Failures on later user turns keep the existing invalid/terminal behavior. - The new config flag `fallback_first_user_message` controls this. It defaults to `true`, and the canonical YAML declares it. `test_config.py` asserts the canonical value. - The README configuration table and `docs/rollout.md` document the flag. No issue is linked. The cause and fix are recorded in NVIDIA-NeMo#3111, which this PR ports. ## Validation Ran on this branch (base `main` at `974d1a921`). NVIDIA-NeMo#3111 cherry-picked cleanly. Since `super-v3.5-posttraining` split from `main`, `main` changed these files in 3 commits. The closest is NVIDIA-NeMo#4568 (judge `text.format`, top-level `mask_sample`). None of them touch the opening-message path. - `ng_test +entrypoint=resources_servers/conversational_tool_use_simulation +should_validate_data=true`: 85 passed, and data validation passed. - The 3 new fallback tests fail against `main`'s `app.py` and pass on this branch: - `test_first_user_stop_falls_back_to_reason_for_contact` - `test_first_user_generation_error_falls_back_to_reason_for_contact` - `test_first_user_fallback_uses_default_when_reason_for_contact_is_unusable` The 3 guard tests pass on both. They cover the flag turned off, for the stop and error cases, and an error on a later turn. - 3 more tests check that a fallback row is scored and not masked through `verify()`, that the flag defaults to `true`, and that a `###STOP###` first message is retried before the fallback replaces it. Each fails if the behavior it covers is broken. - Parity with `super-v3.5-posttraining`: the fallback code is identical to that branch at every Gym commit the training run below used (`e978899b7`, `34b99364`, `14317ecb5`). A local run of the real agent and resource server through `verify()` on 23 cases (user simulator, policy and judge stubbed) matches that branch on reward, mask and messages with the flag at its default, `true` or `false`. With `false` it also matches `main` without this PR. - `pre-commit run --all-files`: passed, no changes. - DCO: every commit is signed off. ### Rollout evidence The fix ran in a Nemotron 3.5 Super RLVR training run, `super35-journey-rlvr-v43-yifuw-001` ([W&B](https://forge.coreweave.com/wandb/nvidia/super-v3p5-posttraining?nw=j0nn1gshftc)). The run used NeMo RL `super-v3.5-posttraining`, whose Gym pin has included NVIDIA-NeMo#3111 since 2026-09-04. The run's data blend includes `conversational_tool_use_simulation`. - The fallback fired twice. Each time, the user simulator returned only a reasoning item and no message, so the server logged `first user message fallback: message_generation_error` (`A response does not contain a message output`). Without the fix, each of these rows would have produced an empty agent output. That branch's NeMo RL also has RL NVIDIA-NeMo#4001, which turns such rows into masked placeholders, so this run shows the fallback trains safely rather than that it prevented a failure. NeMo RL `main` doesn't have NVIDIA-NeMo#4001. - Training kept going after both. The first fallback happened during step 35 of W&B run `dvp5tc0d`, which went on to step 38. The second happened during step 41 of `0g5thn9y`, which went on to step 51. The run reached step 78. ## Compatibility - This changes default behavior. On `main`, a first-turn simulator failure produces a row with an empty agent output, labeled `user_failure` and masked. With this PR, that row becomes a normal conversation that starts from the scenario's own request, and it is scored and trained on. If the judge rejects that first message itself, the row is masked as a user failure, as before. Set `fallback_first_user_message: false` to restore the old behavior. - Rows whose prefilled history already contains a user message never fall back. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Yi-Fu Wu <yifuw@nvidia.com> Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.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
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?
The nested conversational tool-use environment (
resources_servers/conversational_tool_use_simulationwith theconversational_tool_use/simulationagent) now starts from a source checkout, and its rollouts are graded andmasked 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_samplefield that Gym and trainers read.Fixes NVBug 6847461. Closes #4497.
Cause
ServerClient.assistant_message_header(nemo_gym/server_utils.py:825, added by [1/5] feat(opencode): link assistant messages to captured model calls #3711)imports
responses_api_agents.{harness}with the raw config key. Nested harnesses are keyed by directory path,so
conversational_tool_use/simulationraisesModuleNotFoundErrorinpolicy_modelsetup(
base_responses_api_model.py:286). The venv blocker in the same NVBug (a pin tonemo-gym==<version>) wasalready fixed by fix(cli): treat servers nested three levels deep as editable installs #4464.
Evaluation.model_json_schema()as text, and the replyis parsed with
model_validate_json, with no decoding constraint (since feat: add end-to-end synthetic conversational tool-use generation and rollouts #2111). With the QA model (temperature 1.0), thestep-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 gotverification_generation_error.instance_config.mask_sample. feat(core): report infrastructure failure from verify, not just a reward #2611 later madeBaseVerifyResponse.mask_samplethe contract. This environment was never migrated, so simulator, tool, and judgefailures reached rollouts with
mask_sample: falseand reward 0.Fix
/to.before importing the harness package.judge_responses_create_params.textis not configured, the judge requests Responsestext.format(json_schema) forEvaluation, or forUserAgentEnvironmentEvaluationin combined mode. Aconfigured
textstill wins.openai_modelforwards it to the provider; the chat converter maps it toresponse_format./verifyand the agent's transient-failure response set top-levelmask_sample.instance_configis removed, and the checked-inexample_rollouts.jsonlis migrated. The README states themasking rule.
Rejected: catching
ImportErrorinassistant_message_header. It would hide a declared header from any nestedharness, and the new test fails on it.
Before the fix
Gym
4a101eeb5(main), QA caseconversational_tool_use_simulation:./run.sh test conversational_tool_use_simulation --ref 4a101eeb5 --no-ai-logWith only the import fixed (intermediate commit), the stack started but the judge failed to parse:
After the fix
Gym
29d57f66c(this branch before a rebase onto977583d3d; the one new main commit touches no file in this diff), same command:./run.sh test conversational_tool_use_simulation --ref 29d57f66c --no-ai-logValidation
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).text.formatgave 6/6.
a3a6ab1f4), I rerantest_server_utils.py(173),gym env testfor the server (78), and the agent tests (36): all pass.tests/unit_tests/test_server_utils.py: 173 passed. The newtest_model_header_imports_nested_harness_keyfails onmain, and also fails on a catch-
ImportErrorfix.gym env test --resources-server conversational_tool_use_simulation: 78 passed. New judge structured-outputtests cover both judge paths and a configured
text. 8 mask assertions now check top-levelmask_sample, and theexample-rollout contract test checks the masking rule.
responses_api_agents/conversational_tool_use/simulation/tests: 36 passed. 4 mask assertions moved tomask_sample.tests/unit_tests(Mac): same 43 pre-existing failures as main, plus the new passing test. In one fullrun,
test_slurm_script.py::…multi_node_chain_survives_symmetric_run_entrypointalso failed (abashsubprocesswith 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 changesnvidia/nvidia/nemotron-3.5-super-vl-previewthroughopenai_model.Compatibility
instance_config.mask_samplefrom this environment, such as older NeMo RL, no longer get amask. They should read top-level
mask_sample, like every other environment.text.format. A provider that rejectsjson_schemastructured output can turn itoff by setting
judge_responses_create_params.text.format.type=text.reward-0 policy samples.
🤖 Generated with Claude Code