Repository navigation
feat: add end-to-end synthetic conversational tool-use generation and rollouts - #2111
Merged
Merged
Conversation
Co-authored-by: Jonathan Li <jonli@nvidia.com> Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
jkyi-nvidia
marked this pull request as ready for review
July 24, 2026 17:18
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
…onversational-tool-use
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
…onversational-tool-use
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
Signed-off-by: Junkeun Yi <jkyi@nvidia.com>
bxyu-nvidia
approved these changes
Aug 8, 2026
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>
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 a Gym-native pipeline for generating and evaluating long-horizon synthetic conversational tool-use tasks.
The pipeline is split into five composable components:
conversational_tool_use_domain_generation: generates domain candidates.conversational_tool_use_policy_tool_generation: generates, refines, validates, and judges domain policies and tool schemas.conversational_tool_use_scenario_generation: generates customer scenarios for accepted policy/tool artifacts.conversational_tool_use_agent: runs the policy-model conversation loop.conversational_tool_use_simulation: simulates users and tool results, maintains session state, and verifies completed trajectories.Each component uses standard Gym agents, resource servers, model-server references, rollout JSONL, and explicit materialization steps. This PR does not change
nemo_gymcore infrastructure.Design
Generation pipeline
The generation stages are independent Gym agents connected through typed rollout artifacts:
Each rollout preserves the generated artifact, source lineage, model requests and responses, parsing outcomes, and validation or judgment results. Materializers produce stable IDs and the exact row contract required by the next stage.
The pipeline supports
generalandproactiveprofiles. Prompt assets, schemas, golden policy/tool references, checked-in examples, and package-specific configuration live with the component that owns them.Conversational rollout environment
The policy agent supports multi-turn assistant messages, sequential and parallel function calls, prefilled histories, transfers, and bounded policy-model steps. A normal assistant message does not terminate the rollout: the agent asks the simulator for the next user turn and continues until a stop condition, transfer, incomplete response, verification failure, or step limit.
The simulation resource server owns:
Policy, user-simulator, tool-simulator, and judge roles are separate model-server references and can use different models or providers.
Transcript and data contracts
The returned Gym row has two aligned views:
responses_create_paramsandresponsecontain the policy-visible Responses API transcript;result.trajectorycontains simulator-native user, agent, tool, terminal, and verification state.The agent validates that the materialized system prompt and model-visible tools match the top-level policy and simulator tool definitions before starting a rollout.
Provider output order is preserved when a response contains assistant content and function calls. Parallel tool results are appended only after all selected response items. Each decomposed trajectory message records its source
response_idandresponse_output_index; the complete raw response is stored once rather than duplicated on every message.Transient seeding, generation, and verification failures use Gym's failure-sidecar contract and are excluded from scored rollout JSONL. Semantic failures remain verified rollout results with synchronized reward, invalid-reason, failure-label, and judge-diagnostic fields.
Dataset preparation
The resource-server package includes builders for checked-in examples, full
generalandproactivedatasets, combined datasets, parallel-tool-call variants, and deterministic balanced sampling.Builders reject malformed or incomplete tools, invalid JSON Schemas, malformed scenarios, duplicate tool names, and model-template leakage. Full generated datasets, reports, and rollout outputs are intentionally not checked in.
Validation
Automated validation
68 passed:resources_servers/conversational_tool_use_simulationtest suite.34 passed:responses_api_agents/conversational_tool_use/simulationtest suite.Live rollout validation
inference_providerusing DeepSeek V4 Pro as the policy and Nemotron 3 Ultra as simulator and judge.reasoning -> message -> function_call(s).End-to-end NeMo RL validation
The materialized conversational tool-use dataset was used to train
NVIDIA-Nemotron-3-Nano-30B-A3B-BF16through Step 30 with multi-turn GRPO. Steps 10, 20, and 30 were converted from DCP to Hugging Face format and evaluated alongside the base checkpoint on TAU2 and TAU3 BM25 artificial analysis.TAU2 averageis the arithmetic mean across airline, retail, and telecom. This run validates the complete downstream path from dataset materialization through rollout collection, verification, training, checkpoint conversion, and Gym evaluation. TAU2 average increased from46.84%at base to48.31%at Step 30.