Skip to content

feat: run Hermes inside task sandboxes - #3720

Merged
yaoyu-33 merged 10 commits into
mainfrom
ananthsub/episode-orchestration-08-hermes-sandbox-execution
Sep 29, 2026
Merged

yaoyu-33 merged 10 commits into
mainfrom
ananthsub/episode-orchestration-08-hermes-sandbox-execution

Conversation

@ananthsub

@ananthsub ananthsub commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Runs Hermes in a Resources-owned sandbox when SandboxAccess is supplied, or creates an Agent-owned fallback sandbox otherwise. Both paths return sandbox-captured model and tool observations during close.

Hermes calls the Model Server directly from the sandbox, so the sandbox must be able to reach it. The runner points every model client Hermes builds at the rollout's Model Server URL: the root agent, its iteration-limit summary, delegated children, and auxiliary clients. Streaming is turned off because the Model Server answers only whole responses.

The sandbox installs the Hermes version pinned in requirements.txt, derived at startup from the Hermes installed with the server, so there is one version pin and the sandbox runs the same Hermes as the host. Seeding reuses that Hermes when it already imports in the sandbox, for example because the image bakes it in, and otherwise installs it and checks the import again. The runner starts with one blocking exec, so it works on any sandbox provider. Close cancels an activation still in flight, and the runner's shell records its PID and honors a stop marker, so an interrupted activation, or one that exceeds sandbox_runner_timeout_seconds, stops the runner. Tearing down the sandbox remains the backstop.

Sessions use MCP tool grants. Each activation adds the granted servers to that session's Hermes configuration, and the runner fails before the first model call when a required server does not connect. The sandbox installs Hermes with its mcp extra, which carries the MCP client. Hermes names MCP tools mcp_<server>_<tool>; the response reports them as mcp__<server>__<tool>, the form Gym strips before verification, while captured model calls keep Hermes' names. Other required grants, such as direct HTTP, are rejected at seed, and an MCP grant may not reuse a Hermes toolset name.

Single-agent-turn interaction flow

This diagram describes Hermes under the built-in single-agent-turn Environment Server. Other Environment Servers may use different Agent activation and sandbox ownership rules.

sequenceDiagram
    participant E as EnvironmentServer
    participant A as HermesAgent
    participant S as TaskSandbox
    participant M as ModelServer

    E->>A: Seed with optional SandboxAccess
    A->>S: Borrow or create sandbox
    E->>A: One /v1/responses activation
    A->>S: Run Hermes and tools
    S->>M: Model calls
    A-->>E: Agent response
    E->>A: Close session
    A->>S: Disconnect borrowed or stop owned sandbox
Loading

Stack position

Part 1 of 3, based on main. Next: #3721.

No issue is linked because this is one layer of the Environment Server stack.

Validation

  • responses_api_agents/hermes_agent/.venv/bin/pytest responses_api_agents/hermes_agent/tests/ -q — 72 passed
  • The runner tests run the pinned Hermes against a local HTTP model server and check that the iteration-limit summary and default OpenAI clients reach it, and that delegated children do not stream.
  • Required Direct HTTP tool-grant reproduction now fails seed explicitly instead of running without the tool.
  • A runner test starts the example MCP weather Resources Server with MCP exposure, grants it to Hermes, and checks that the model's tool call reaches the seeded Resources session; another checks that an unreachable required server fails before any model call.
  • Non-Hermes real-model smoke: not run because this workspace has no configured model endpoint or credentials.

Rollouts

MCP grants: all 5 example_mcp_weather tasks with gpt-5.6-sol through single_agent_turn_legacy with the MCP tool transport scored reward 1.0, with Hermes calling get_weather over MCP from its sandbox. That run also used the Resources Server change that returns MCP access in resources_tools for Environment Server seeds, which is a separate PR. See the final integration PR for SWE-bench Pro rollout evidence.

Compatibility and security impact

reasoning_content replay on assistant messages comes from #3542; this PR adds tests for it. Sandbox requirements, including Model Server reachability, and the writable result-file limitation are documented in the Hermes README. Sandbox mode is suitable for evaluation, not RL training data, until result transport is isolated from model-written files.

@nemo-automation-bot
nemo-automation-bot Bot requested review from a team September 28, 2026 15:38
@ananthsub
ananthsub added this pull request to stack #3723 September 28, 2026 15:38
Base automatically changed from ananthsub/episode-orchestration-09-legacy-adapter to ananthsub/episode-orchestration-07-swe-pro-sessions September 28, 2026 15:41
@ananthsub
ananthsub force-pushed the ananthsub/episode-orchestration-08-hermes-sandbox-execution branch from 86f6424 to 3210d67 Compare September 28, 2026 15:41
@ananthsub
ananthsub removed this pull request from stack #3723 September 28, 2026 15:41
@ananthsub
ananthsub added this pull request to stack #3725 September 28, 2026 15:43
@yaoyu-33 yaoyu-33 added area:agent Agent harnesses and Responses API agent behavior complexity:high Cross-component or shared-contract change with a large review surface feature New capabilities, enhancements, or enablement work needs-review PR is ready for code review and waiting on a reviewer labels Sep 28, 2026
@ananthsub
ananthsub force-pushed the ananthsub/episode-orchestration-08-hermes-sandbox-execution branch from 3210d67 to 0f6b017 Compare September 28, 2026 15:48
@ananthsub
ananthsub force-pushed the ananthsub/episode-orchestration-08-hermes-sandbox-execution branch from 0f6b017 to c1571ce Compare September 28, 2026 16:03
Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
…errupts

- Route model requests through the sandbox relay at the HTTP transport, so the iteration-limit summary, delegated children, and auxiliary clients reach the Model Server like the root agent. Every agent runs without streaming, and Model Server errors keep their status and body.
- Close cancels an in-flight activation and waits for it, and termination waits for a runner launch still in progress, so a runner cannot start after its session closes.
- Treat a string input as the user message in sandbox sessions.

Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
The sandbox is expected to reach the Model Server, so the file relay is removed. The runner points Hermes, its iteration-limit summary, delegated children, and auxiliary clients at the rollout's Model Server URL, and turns streaming off because the Model Server answers only whole responses.

The runner now starts with one blocking exec instead of a PTY process session, so it works on every sandbox provider. Its shell records a PID and honors a stop marker, so an interrupted activation stops the runner; tearing down the sandbox remains the backstop. Invocation observations reference model calls by the response IDs Hermes saw.

Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Seeding checks whether the pinned Hermes imports from its runtime path, which is keyed by the pinned commit, and installs only when it does not. A runtime baked into the image or left by an earlier session is reused without the host's uv or network access. An install rebuilds the venv from scratch and checks the import again, so a partial install is not mistaken for a working one.

Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
A timed-out sandbox exec returns a result instead of raising, and the runner keeps running in the sandbox. The activation now stops the runner and fails with a timeout error.

Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
….txt

The sandbox install requirement and the runtime directory key are derived from the Hermes installed with the server, using its package metadata. A git install becomes a GitHub archive keyed by its commit, and a release install pins its version. Bumping Hermes now means editing requirements.txt, and the sandbox always runs the same Hermes as the host.

Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
yaoyu-33
yaoyu-33 previously approved these changes Sep 29, 2026
The secrets detector flags a real 40-character commit hash as a high-entropy string. The test only checks how a commit becomes an archive URL and a runtime key, so a synthetic commit is enough.

Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
@yaoyu-33

Copy link
Copy Markdown
Contributor

This PR is okay. I have few other fixes in my PR later #3554

The num_workers check ran at startup, so a Hermes server with several workers failed to start even when it only served /run, which keeps no session. Seeding a session now enforces it instead, as Simple Agent does, and the README says so.

Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Hermes sessions rejected every required tool grant. They now accept MCP grants:
each activation lists the granted servers under mcp_servers in that session's
Hermes config, adds them to a restricted enabled_toolsets, and the sandbox
runner fails before any model call when a required server does not connect.
The sandbox installs Hermes with its mcp extra, which carries the MCP client.

Hermes names MCP tools mcp_<server>_<tool>; the response renames granted
servers' calls to Gym's mcp__<server>__<tool>, which Gym strips before verify.
Grants Hermes cannot use (direct HTTP) are still rejected when required, and
MCP names may not shadow a Hermes toolset.

Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>
Signed-off-by: Ananth Subramaniam <ansubramania@nvidia.com>

@yaoyu-33 yaoyu-33 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Reviewed 6420620; 73 targeted tests passed, including the new MCP integration checks. Budget-exhaustion handling and further lifecycle fixes will follow in #3554. Preserving observations on runner exceptions remains a non-blocking follow-up.

@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/36643794124

This branch was previously deployed

1 inactive deployment
public — 6420620b Deployed Sep 29, 2026 by copy-pr-bot[bot] via release / finalize / notify #3986
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:agent Agent harnesses and Responses API agent behavior complexity:high Cross-component or shared-contract change with a large review surface feature New capabilities, enhancements, or enablement work 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.

2 participants