Skip to navigation

nemo_gym.agents.utils.sandbox_python

View as Markdown

A Python harness’s private runtime, built on the Agent Server host and uploaded into the task sandbox.

The sandbox needs no network, no uv and no Python of its own. For each sandbox platform, the host downloads a pinned python-build-standalone CPython and checks its SHA-256, then installs the harness’s requirements for that platform with uv into a separate site-packages archive. Packages are pinned to the versions installed in this Agent Server’s environment, so the sandbox runs the versions the adapter is tested with. Requirements given as direct URLs, such as a harness pinned to a commit, are built from source on the host; every other package must publish a wheel for the sandbox’s platform. Both archives are cached on the host under sandbox_python in Gym’s cache_dir.

In the sandbox, install_python_runtime.sh unpacks the archives in a private directory, checks that the runtime imports the harness, and renames it into place, so a concurrent seed never sees a partial runtime. The runtime lives under /tmp, outside the task’s working directory and HOME, and every command runs from /.

Module Contents

Classes

NameDescription
SandboxPlatformThe sandbox’s CPU architecture and C library, which select the Python build and the wheels.
SandboxPythonRuntimeA harness’s private Python in the sandbox: the pinned CPython with requirements installed.

Functions

NameDescription
_agent_environment_pinsname==version for each package this server’s environment installed from an index.
_cache_dirWhere the host keeps the archives: sandbox_python under Gym’s cache_dir.
_cachedpath, built once per host. Builders write atomically, so other processes see it whole or not at all.
_discardRemove path from the sandbox, best effort. Cancelling the caller does not stop the removal.
_environment_proxyThe proxy the host’s environment names for url. Gym’s shared HTTP client does not read it itself.
_forget_build-
_python_archiveThe pinned python-build-standalone archive for platform, checked against its published SHA-256.
_run-
_sha256-
_source_builtNames of the requirements given as direct URLs; uv builds these from source on the host.
_write_archive-
probe_sandbox_platformAsk the sandbox for its kernel, machine and C library.

Data

LOG

PYTHON_VERSION

_BUILDS

_INSTALLER

_MACHINES

_MANYLINUX_LEVELS

_PLATFORM_PROBE

_PYTHON_DOWNLOADS

_PYTHON_FILE

_PYTHON_RELEASE

_PYTHON_SHA256

_SITE_PACKAGES

API

class nemo_gym.agents.utils.sandbox_python.SandboxPlatform(
arch: str,
libc: str,
glibc_minor: int | None = None
)
Dataclass

The sandbox’s CPU architecture and C library, which select the Python build and the wheels.

arch
str
glibc_minor
int | None = None
libc
str
wheel_platform
str

The uv pip --python-platform value whose wheels run in the sandbox.

class nemo_gym.agents.utils.sandbox_python.SandboxPythonRuntime(
harness: str,
requirements: tuple[str, ...],
import_check: str,
overrides: tuple[str, ...] = ()
)
Dataclass

A harness’s private Python in the sandbox: the pinned CPython with requirements installed.

import_check is Python source that runs without error only in a usable runtime, for example "import run_agent, mcp". overrides are the uv overrides the adapter’s own environment is installed with, such as the lines of its overrides.txt.

directory
str

Sandbox directory keyed by everything that goes into the runtime.

A runtime found there, such as one an earlier session left in this sandbox, was built from the same inputs and is reused. The key covers every index-installed version in this Agent Server’s environment, so a runtime baked into an image is reused only by an Agent Server environment with exactly those versions. The adapter may keep its own harness files here, beside python/.

harness
str
import_check
str
overrides
tuple[str, ...] = ()
python
str

The runtime’s interpreter in the sandbox, once is_installed() passes or install() returns.

Run an absolute harness script with -E -s: ignore the task’s Python environment settings and user site-packages without changing the environment inherited by tool subprocesses. The script directory must belong to the harness, so task files cannot shadow its imports.

requirements
tuple[str, ...]
nemo_gym.agents.utils.sandbox_python.SandboxPythonRuntime._build_site_packages(
destination: pathlib.Path
) -> None
async
nemo_gym.agents.utils.sandbox_python.SandboxPythonRuntime._site_packages_archive(
) -> pathlib.Path
async
nemo_gym.agents.utils.sandbox_python.SandboxPythonRuntime.install(
timeout_s: float
) -> None
async

Build the runtime for the sandbox’s platform on this host if needed, then upload and publish it.

timeout_s bounds the whole installation, including a build that another seed started. Raises RuntimeError when the platform is unsupported, the host build or download fails, or the runtime fails its import check in the sandbox, and TimeoutError when timeout_s runs out.

nemo_gym.agents.utils.sandbox_python.SandboxPythonRuntime.is_installed(
) -> bool
async

Whether the runtime in the sandbox passes import_check. The existence of the directory proves nothing.

Like the installer’s checks, it runs with HOME in the runtime directory, because some harnesses write their state under HOME when imported.

nemo_gym.agents.utils.sandbox_python._agent_environment_pins() -> tuple[str, ...]

name==version for each package this server’s environment installed from an index.

Passed to uv as constraints, which keep the extras that dependencies request (an override would replace lxml[html_clean] with plain lxml). Packages installed from a URL or a path, including editable ones, are left free.

nemo_gym.agents.utils.sandbox_python._cache_dir() -> pathlib.Path

Where the host keeps the archives: sandbox_python under Gym’s cache_dir.

nemo_gym.agents.utils.sandbox_python._cached(
path: pathlib.Path,
build: collections.abc.Callable[[], collections.abc.Awaitable[None]]
) -> pathlib.Path
async

path, built once per host. Builders write atomically, so other processes see it whole or not at all.

Concurrent callers share one build and its outcome, and a caller that is cancelled leaves it running for the others. A failed build is retried by the next call.

nemo_gym.agents.utils.sandbox_python._discard(
path: str
) -> None
async

Remove path from the sandbox, best effort. Cancelling the caller does not stop the removal.

nemo_gym.agents.utils.sandbox_python._environment_proxy(
url: str
) -> str | None

The proxy the host’s environment names for url. Gym’s shared HTTP client does not read it itself.

nemo_gym.agents.utils.sandbox_python._forget_build(
path: pathlib.Path,
build: asyncio.Task[None]
) -> None
nemo_gym.agents.utils.sandbox_python._python_archive(
) -> pathlib.Path
async

The pinned python-build-standalone archive for platform, checked against its published SHA-256.

nemo_gym.agents.utils.sandbox_python._run(
argv: list[str],
cwd: pathlib.Path
) -> None
async
nemo_gym.agents.utils.sandbox_python._sha256(
path: pathlib.Path
) -> str
nemo_gym.agents.utils.sandbox_python._source_built(
requirements: collections.abc.Iterable[str]
) -> list[str]

Names of the requirements given as direct URLs; uv builds these from source on the host.

nemo_gym.agents.utils.sandbox_python._write_archive(
source: pathlib.Path,
archive: pathlib.Path
) -> None
nemo_gym.agents.utils.sandbox_python.probe_sandbox_platform(
async

Ask the sandbox for its kernel, machine and C library.

nemo_gym.agents.utils.sandbox_python.LOG = logging.getLogger(__name__)
nemo_gym.agents.utils.sandbox_python.PYTHON_VERSION = '3.13.14'
nemo_gym.agents.utils.sandbox_python._BUILDS: dict[Path, Task[None]] = {}
nemo_gym.agents.utils.sandbox_python._INSTALLER = Path(__file__).with_name('install_python_runtime.sh')
nemo_gym.agents.utils.sandbox_python._MACHINES = {'x86_64': 'x86_64', 'amd64': 'x86_64', 'aarch64': 'aarch64', 'arm64': 'aarch64'...
nemo_gym.agents.utils.sandbox_python._MANYLINUX_LEVELS = (40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 28, 17)
nemo_gym.agents.utils.sandbox_python._PLATFORM_PROBE = 'uname -s; uname -m; libc=$(getconf GNU_LIBC_VERSION 2>/dev/null || ldd --versio...
nemo_gym.agents.utils.sandbox_python._PYTHON_DOWNLOADS = 'https://github.com/astral-sh/python-build-standalone/releases/download'
nemo_gym.agents.utils.sandbox_python._PYTHON_FILE = 'cpython-{version}%2B{release}-{arch}-unknown-linux-{libc}-install_only_stripped...
nemo_gym.agents.utils.sandbox_python._PYTHON_RELEASE = '20260805'
nemo_gym.agents.utils.sandbox_python._PYTHON_SHA256 = {'x86_64/gnu': '39e82d05926bdcd206732026bcd878d9f00e288cd227d91c1fabf379b6ea4fa5...
nemo_gym.agents.utils.sandbox_python._SITE_PACKAGES = f'python/lib/python{PYTHON_VERSION.rsplit('.', 1)[0]}/site-packages'