Skip to content

fix(osworld): keep the Nano Omni profile's sampling and document its Omni v3 recipe - #4897

Open
JeffPengCoder wants to merge 6 commits into
NVIDIA-NeMo:mainfrom
JeffPengCoder:feature/osworld-nano-omni-recipe
Open

JeffPengCoder wants to merge 6 commits into
NVIDIA-NeMo:mainfrom
JeffPengCoder:feature/osworld-nano-omni-recipe

Conversation

@JeffPengCoder

@JeffPengCoder JeffPengCoder commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

prepare.py always emitted 1500 output tokens and temperature 1.0, overriding the Nano Omni profile's 4096 / 0.6 recipe. This change preserves profile and task-row sampling unless the caller passes explicit flags, pins the tested history-template argument, and documents the Omni v3 serving recipe.

Base and dependencies

This PR includes main at bd6f5f0d8f3a56cbf3f7e1d2d4a1d2220b7ff6fe. Updated head: 9de7ffcf8e75498a6ed2c97cec3efb3a71e642f4. The main-relative diff remains limited to the original seven OSWorld files.

What does this PR do?

It preserves the Nano Omni profile's sampling and documents the serving and agent configuration behind the reported Omni v3 scores, together with the current managed-install and SDK compatibility requirements.

  1. prepare.py no longer overrides the profile's sampling.

    • Before, it always wrote responses_create_params with max_output_tokens: 1500 and temperature: 1.0 into env.yaml.
    • Rollout collection merges that block over every row (row_params | responses_create_params_overrides in nemo_gym/rollouts/rollout_collection.py). The OSWorld agent then uses the request's values instead of its config.
    • So --profile nano_omni without flags ran at 1500 tokens and temperature 1.0 instead of the profile's 4096 tokens, temperature 0.6 and top-p 0.95.
    • Now --max-output-tokens, --temperature and --top-p default to None, and only the values that are passed are written.
    • test_nano_omni_env_keeps_the_profile_sampling_recipe merges the base config, the nano_omni profile and the generated env.yaml, and checks the effective sampling, step limit and history policy.
    • test_main_writes_complete_nano_omni_profile now also checks that no responses_create_params is written when the flags are omitted.
  2. The Omni v3 recipe is documented in benchmarks/osworld/README.md, with pointers from the profile config and the agent README:

    • Serve the checkpoint:
      • The checkpoint is nvidia/Nemotron-3-Nano-Omni-30B-A3B-Reasoning-BF16 at revision 24e67ea0.
      • The chat template must be passed with --chat-template. The correct one is SHA-256 ab7813c3…, the template embedded in the checkpoint's tokenizer_config.json. By default vLLM serves the checkpoint's chat_template.jinja (41428e0c…) instead.
      • The section also covers the nano_v3 reasoning parser, where to get it, and the vllm serve command.
    • Scope: Omni v3 only. Other Nemotron generations, such as 3.5 Super and 4, ship their own tokenizer, chat template and parser.
    • Prepare and run on the 361 tasks of OSWorld's test_nogdrive manifest (test_all without the 8 tasks that need Google Drive), including the command that builds that set.
    • Tune the output limit: the limit is tunable, so the section gives a method rather than one value.
    • Reference scores for Omni v3, with the run-to-run spread.
    • Infeasible tasks: an infeasible task scores only when the model itself ends the episode with FAIL. The adapter never appends FAIL at the step limit.
    • AgentENV backend:
      • the E2B SDK version;
      • how the managed lock selects the SDK independently of the root environment and historical recipe;
      • certificates from a private CA;
      • proxies.
  3. The profile pins truncate_history_thinking=true.

    • The profile sent no chat_template_kwargs, so the served template's own default decided whether earlier assistant turns keep their reasoning.
    • Every reference score used that default, true: image-backed history turns are rendered as an empty <think></think> plus the Action, and turns folded into the text history keep their Thought.
    • The profile now sets it explicitly, the serving table lists it, and test_nano_omni_profile_pins_truncated_history_reasoning checks it.
    • Sending false, as NVIDIA's computer-use cookbook for this model does, keeps the reasoning in those turns. That changes the model input, so the README treats it as a separate recipe to validate.

No issue: this documents the recipe behind the OSWorld scores reported in #3591. It also fixes a prepare.py default that was found while checking those scores.

Validation

Validated source: 9de7ffcf8e75498a6ed2c97cec3efb3a71e642f4, merging the original PR with main bd6f5f0d8f3a56cbf3f7e1d2d4a1d2220b7ff6fe and correcting README references to locked installation and SDK compatibility. The committed tree matches the audited candidate exactly.

  • OSWorld benchmark tests, all OSWorld agent tests, public-API/facade tests and token-capture tests: 1565 passed, 1 failed. The failure is the existing main test benchmarks/osworld/tests/test_run_scripts.py::test_managed_osworld_agent_installs_opensandbox_sdk, which still asserts the old managed-install contract, beginning with nemo-gym[dev] instead of nemo-gym[dev,ray].
  • Pure main's benchmark suite: 42 passed, 1 failed, with that same test failing. The two PR sampling regression tests, copied verbatim and run against main, both fail as expected; both pass in the merged candidate.
  • Sampling diagnostic: 60 complete cases, 30 on main and 30 on the candidate, covering default, pointer, nano_omni, omitted flags, single-field overrides, zero temperature, all flags, and task rows with their own sampling parameters. Every candidate emission matches the explicit flags. These are configuration/precedence checks, not live model rollouts.
  • pre-commit run --all-files --show-diff-on-failure: passed. git diff --check passed. Only the intended README corrections differ from the initially tested merged tree; executable source is unchanged after the test run.
  • All 12 Markdown relative links and in-page anchors across the two changed READMEs resolve.
  • 55 runtime/config/lock files under the OSWorld agent, OSWorld resources server and vLLM transport match main byte for byte. The agent parser files also match the original PR head byte for byte. No parser, model-output normalization, or repair behavior was added by this integration.

Tests ran on macOS ARM64, Python 3.13.14, with a separate validation environment using root-lock aiohttp 3.14.4, Ray 2.58.0 and OpenAI 2.44.0. This is not a complete installation or smoke test of the managed component lock (which selects aiohttp 3.14.5 and different sandbox SDK versions).

The current CI classifier makes this a full-suite diff because benchmark Python/YAML files are uncategorized paths; the agent test file also prevents a docs-only interpretation. A trusted main CI run is still required for this updated head. An authorized /ok to test <full-sha> applies only to the specified commit; no CI authorization comment was posted as part of this update.

Rollouts

No new model/VM rollout was run during this main-sync review. The historical runs below validate the intended sampling on their original sources and SDKs; they do not qualify the new managed lock. A model-and-verifier smoke with the final frozen environment remains outstanding before claiming current-main runtime compatibility.

With this change, --profile nano_omni without sampling flags gives the values the reference runs passed explicitly:

  • temperature 0.6 and top-p 0.95;
  • 100 steps;
  • the fixed history policy with three screenshots;
  • 4096 output tokens, unless --max-output-tokens is given.

test_nano_omni_env_keeps_the_profile_sampling_recipe checks these values on the merged config.

The README's reference scores come from real OSWorld runs on the 361 tasks with the documented serving configuration:

Backend Proxy-required tasks Output limit Raw reward rate Binary success rate
OpenSandbox Pool proxy enabled 4096 50.97% 48.48%
AgentENV proxy disabled 16384 44.61–48.13% (4 runs) 42.66–45.98%

The most recent AgentENV run is the October 20 reproduction in #3591's description.

Compatibility and benchmark impact

  • When --max-output-tokens, --temperature and --top-p are all omitted, prepare.py no longer writes responses_create_params, so the profile's agent config decides the sampling:
    • nano_omni: such runs change from 1500 output tokens at temperature 1.0 to the profile's 4096 tokens, temperature 0.6 and top-p 0.95, so their scores change.
    • default and pointer: with standard task rows that supply no sampling values, they still inherit 1500 tokens, temperature 1.0 and no top-p from osworld_agent.yaml.
    • All profiles with task-row sampling: without CLI flags, existing per-row sampling is now honored instead of having max-output tokens and temperature replaced by prepare's old defaults. For example, a row requesting 8192 tokens at temperature 0.2 now retains those values; main previously forced 1500 and 1.0. Explicit CLI flags still take priority, one field at a time.
  • Each explicitly passed flag retains its value; omitted fields now follow task-row sampling and then profile defaults.
  • The profile now sends chat_template_kwargs: {truncate_history_thinking: true} on every request. With the documented template this is the template's own default, so the model input and the scores do not change. With a server or template whose default differs, the rendering now stays the tested one.
  • Everything else is documentation and config comments.

Managed-runtime compatibility

The reference AgentENV runs used E2B 2.46.0, whose sandbox-create call uses POST /sandboxes. The managed OSWorld agent lock now selects E2B 2.58.0, whose sync and async create calls use POST /v2/sandboxes. The root Gym lock still selects 2.46.0; that does not control the isolated agent runtime. SDK wheels were read and their hashes checked against the committed locks to verify this difference.

The README now makes that distinction explicit. A control plane must support the selected SDK's endpoint, or the run needs a separately recorded agent manifest and lock selecting the compatible SDK. An ad hoc post-install pin and UV_CONSTRAINT do not define a reproducible locked environment. No deployment compatibility or new score is claimed from unit tests, and no SDK, provider or parser fallback is introduced here.

Checklist

  • I have read the contributing guidelines.
  • The change is focused; unrelated "drive-by" edits are tracked as separate issues/PRs.
  • Local targeted checks are recorded above; the pre-existing main installer assertion and a final-environment model/verifier smoke remain outstanding.
  • Documentation added or updated, or N/A with justification.
  • Pre-commit checks pass locally (pre-commit run --all-files) (so CI lint/format checks pass).
  • New source files include the required Apache-2.0 SPDX header. (No new files.)
  • All commits have DCO sign-off (git commit -s) (so the DCO check passes).

prepare.py always wrote responses_create_params with max_output_tokens 1500 and temperature 1.0. Collection applies those values over every row and the agent config, so a run prepared with --profile nano_omni and no sampling flags ignored the profile's temperature 0.6 and 4096-token limit. Write each sampling value only when its flag is passed. The default and pointer profiles already configure 1500 and 1.0 themselves, so their requests are unchanged.

Signed-off-by: Jeff Peng <jepeng@nvidia.com>
…oring rules

The Nano Omni profile reproduces the reference scores only with a serving configuration that was not written down: the checkpoint's own tokenizer with the chat template embedded in its tokenizer_config.json (vLLM otherwise serves the separate chat_template.jinja), the nano_v3 reasoning parser plugin, and the vLLM flags of the reference runs. Document them with sources and SHA-256 digests, the 361-task test_nogdrive input and how to build it, the model-explicit infeasible scoring rule, reference scores for a self-check, and the AgentENV backend's requirements.

Signed-off-by: Jeff Peng <jepeng@nvidia.com>
The chat template, reasoning parser, tokenizer and reference scores belong to the Omni v3 checkpoint revision 24e67ea0. Later revisions and other Nemotron generations, such as Nemotron 3.5 Super or Nemotron 4, ship their own tokenizer and chat template and may need a different parser; the repository's Nemotron 3.5 Super launchers already use the model's own template with nemotron_v3. Say so in the README, the profile and the agent README, and describe the AgentENV backend as it stands once the provider endpoints are on main.

Signed-off-by: Jeff Peng <jepeng@nvidia.com>
The per-step output limit is a tunable setting rather than a fixed part of the recipe: the profile's 4096 and the 16384 passed by the AgentENV reference runs both produced the reference scores. Describe how truncation shows up (finish_reason length, then model_output_truncated), how to count it from the trajectory record or the full model I/O log, when to raise the limit, and how to keep it within the served context length.

Signed-off-by: Jeff Peng <jepeng@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Oct 22, 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.

@JeffPengCoder JeffPengCoder added bug Something isn't working area:environment Individual environments, benchmarks, verifiers, and environment-specific resources servers needs-review PR is ready for code review and waiting on a reviewer labels Oct 22, 2026
@github-actions github-actions Bot added the sla:triage-overdue Review assignment is over the one-business-day SLA label Oct 23, 2026
…file

The profile sent no chat_template_kwargs, so the served template's own
default decided whether earlier assistant turns keep their reasoning. Every
reference score was measured with that default, truncate_history_thinking=true:
image-backed history turns are rendered as an empty <think></think> plus the
Action, while turns folded into the text history keep their Thought. Set it
explicitly so a different template, server or caller default cannot change
the model input unnoticed, and document it with the serving recipe. Sending
false, as NVIDIA's computer-use cookbook does, is a different recipe.

Signed-off-by: Jeff Peng <jepeng@nvidia.com>
Merge main at bd6f5f0 and document
the managed manifest/lock installation contract and AgentENV SDK endpoint
compatibility. Preserve the Nano Omni sampling fix and parser behavior.

Validation: 1565 tests passed; the one installer assertion failure also
reproduces on main. All 60 sampling cases and pre-commit checks passed.

Signed-off-by: Jeff Peng <jepeng@nvidia.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:environment Individual environments, benchmarks, verifiers, and environment-specific resources servers bug Something isn't working needs-review PR is ready for code review and waiting on a reviewer sla:triage-overdue Review assignment is over the one-business-day SLA

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant