Repository navigation
fix(anyswe_agent): keep the runtime bundle off the agent PATH and isolate the runner Python - #4018
Conversation
bc19465 to
666d426
Compare
…late the runner Python The in-sandbox runner prepended the whole runtime bundle `bin/` to PATH. That directory also holds the bundle's python3, pip, node and npm, so the coding agent's `python`, `pip` and `node` resolved to the bundle instead of the task image. Agents solving numpy/pandas/Pillow tasks imported, "fixed" or reinstalled the bundle's copies instead of the task's. When the bundle is shared (a baked or bind-mounted runtime), one rollout's writes break every later sandbox. For the CLI harnesses (claude, cline, opencode, openclaw, pi), link only the harness executable into a private directory and put that first on PATH. Add `node` too when the executable is a node script. Other harnesses keep the whole bundle `bin/`. Start the runner with `python -I` so the task image's PYTHONPATH and user site cannot shadow the runtime's own packages. In images whose checkout is numpy or pandas, the runner otherwise dies importing nemo_gym before it makes a single model call. Signed-off-by: Lin Jia <linj@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
666d426 to
ff5daeb
Compare
|
/ok to test ff5daeb |
alexandery-nvidia
left a comment
There was a problem hiding this comment.
I traced the -I interplay before approving: isolated mode drops the script directory, PYTHONPATH, and the user site, which is safe here because stdlib and fastapi resolve from the bundle interpreter's own site-packages (the deps scripts install nemo_gym with dependencies into the bundle), and the deferred main() imports resolve through the explicit /nemo_gym_mount insert, which also shadows the bundle's own nemo_gym copy; nothing imports a sibling of the script. The shim fallback (unknown harness keeps the whole bin/) preserves current behavior for out-of-catalog agents, and the node-shebang detection covers the CLIs that are node scripts. Ran tests/test_runtime_isolation.py (4 passed) and tests/test_app.py (20 passed) at the PR head locally.
|
🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA-NeMo/Gym/actions/runs/38327143475 |
What does this PR do?
anyswe_agentruns its harness from a portable runtime bundle (CPython, NeMo Gym, Node and the CLI) inside the task image. Two leaks between that bundle and the task:1. The agent's
python,pipandnodewere the bundle's.agent_runner.pyprepends the whole bundlebin/toPATH, and that directory also holdspython3,pip,nodeandnpm. Every shell command the coding agent runs therefore resolvespython/pip/nodeto the bundle instead of the task image. Agents working on numpy, pandas or Pillow tasks then import, "fix" or reinstall the bundle's copies instead of the task's. When the bundle is shared, for example a baked or bind-mounted runtime, one rollout's writes break every later sandbox.For the CLI harnesses (
claude,cline,opencode,openclaw,pi), the runner now symlinks only the harness executable into a private temp directory and puts that first onPATH. If the executable is a node script (#!/usr/bin/env node, as npm-installed CLIs are),nodeis linked too so the CLI still starts. Python harnesses (Hermes, NeMo Fabric) and anything unknown keep the whole bundlebin/as before.2. The task image's Python environment could break the runner. The runner was started with plain
<runtime>/bin/python. If the task image setsPYTHONPATH(or has a user site) pointing at a checkout of numpy or pandas, the runner imports that source tree instead of the runtime's wheel and dies before its first model call ("Unable to import required dependency numpy"). It now starts withpython -I. The runner already adds/nemo_gym_mounttosys.pathitself, and child processes the agent spawns still get the normal environment.The README documents both.
Validation
python -m pytest -q responses_api_agents/anyswe_agent/tests: 24 passed.TestRuntimeIsolationintests/test_runtime_isolation.py:test_unknown_harness_keeps_the_whole_bundle_bintest_native_cli_hides_the_bundle_python_pip_and_node: the shim holds onlyclaude.test_node_script_cli_also_gets_node: the shim holdsclaudeandnode.test_runner_python_ignores_the_task_images_python_environment: drives_run_agent_in_sandboxwith a fake sandbox and checks the runner command usespython -I.pre-commit run --files <touched files>: all hooks pass.Rollouts
Both problems showed up in internal GRPO training of Claude Code on R2E-Gym / SWE task images. With the shared runtime on a cluster filesystem, an agent overwrote a file inside the bundle's numpy, and every later rollout of that run failed and was masked. In numpy/pandas images the runner failed at import. With these changes the training ran several thousand rollouts without either failure. I have no public rollout numbers to share.
Compatibility and benchmark impact
python/pip/noderather than the bundle's. Tasks that need Python or Node must get them from the image, which is the intended environment. If an image has nopythonat all, the agent no longer silently gets CPython 3.13 from the bundle.PYTHON*environment variables of the image.Checklist
pre-commit run --all-files) (so CI lint/format checks pass). (Run on the touched files.)git commit -s) (so the DCO check passes).🤖 Generated with Claude Code