Skip to content

feat(sandbox): add the sandbox_task hook mechanism - #2402

Draft
terrykong wants to merge 2 commits into
terryk/sandbox-renewablefrom
terryk/sandbox-task-hooks
Draft

feat(sandbox): add the sandbox_task hook mechanism#2402
terrykong wants to merge 2 commits into
terryk/sandbox-renewablefrom
terryk/sandbox-task-hooks

Conversation

@terrykong

@terrykong terrykong commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

PR 3 of 4 in the gym sandbox debug stack (#2400#2401#2402#2403).

Why

Four of the six nemo_gym.sandbox consumers build their SandboxSpec in Python, because it depends on the task row — there is nothing declarative to read. So anything outside the owning server (a debugger, a validator) cannot answer "what image would this row get?" without importing that server's entire dependency tree. For mini_swe_agent_2 that means ray, minisweagent and swebench.

What

An optional sandbox_task block on BaseRunServerInstanceConfig:

sandbox_task:
  spec_resolver: <module>:<fn>    # (row, config) -> SandboxSpec
  exec_wrapper:  <module>:<fn>    # (command, **kwargs) -> str
  image_from_row: <field>         # for the no-Python case
  id_from_row:    <field>

Servers that declare nothing are unaffected, and servers ignore the block at runtime.

nemo_gym.sandbox.hooks deliberately imports nothing from the CLI — the whole point is that a resolver is reachable from a process that has not imported the agent.

And its first user

mini_swe_agent_2 adopts it in the same PR, because a mechanism with no users is not reviewable. Image derivation moved out of app.py and the conda preamble out of sandbox_environment.py, into a stdlib-only sandbox_hooks.py that both the agent and an outside process can import. app.py and sandbox_environment.py now delegate to it — one source of truth, no behaviour change.

Four of the six sandbox consumers build their SandboxSpec in Python because it
depends on the task row, so there is nothing declarative to read. Anything
outside the owning server -- a debugger, a validator -- cannot answer "what
image would this row get" without importing that server's whole dependency
tree.

`sandbox_task` lets a server declare that answer instead: `spec_resolver` and
`exec_wrapper` name plain module:attribute callables, plus `image_from_row` and
`id_from_row` for the cases that need no Python at all. It is optional on
BaseRunServerInstanceConfig, so servers that declare nothing are unaffected and
servers at runtime ignore it entirely.

`nemo_gym.sandbox.hooks` deliberately imports nothing from the CLI: the whole
point is that the resolver is reachable from a process that has not imported
the agent.

Signed-off-by: Terry Kong <terryk@nvidia.com>
…nto hooks

The image name was derived in `app.py` and the conda preamble lived in
`sandbox_environment.py`, both reachable only by importing modules that
pull in ray, minisweagent and swebench. Anything outside the agent's own
venv -- `gym sandbox debug`, for one -- could not ask "what image would
this row get?" without paying for all of that.

Move both into a stdlib-only `sandbox_hooks` module and point the agent
at it, so there is one definition rather than two that can drift, and
declare it from the config through the `sandbox_task` block.

No behaviour change: the same image names and the same wrapped command.

Signed-off-by: Terry Kong <terryk@nvidia.com>
@copy-pr-bot

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

Comment thread nemo_gym/sandbox/hooks.py
remaining = dict(mapping or {})
image = rewrite_image(remaining.pop("image", None), list(remaining.pop("image_rewrites", []) or []))

spec = SandboxSpec(

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.

should this have ports too

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants