Skip to navigation

nemo_gym.sandbox.providers

View as MarkdownOpen in Claude

Sandbox provider registry.

Subpackages

Submodules

Package Contents

Classes

NameDescription
ConnectableProviderOptional capability: rebuild a handle in another process from a descriptor.
SandboxCreateErrorRaised when a provider cannot create a sandbox.
SandboxCreateVerificationErrorRaised when a newly-created sandbox fails provider readiness checks.
SandboxEndpointProvider-neutral route to a long-lived service inside a sandbox.
SandboxExecResultProvider-neutral process execution result.
SandboxHandleProvider-neutral handle to a created sandbox.
SandboxProviderRuntime/infra provider contract used by the public sandbox API.
SandboxPtyErrorRaised when a PTY session fails outside normal process exit.
SandboxPtySessionOne live interactive terminal. Async context manager; exit closes it.
SandboxPtySpecInteractive PTY session request.
SandboxResourcesProvider-neutral creation request, retaining integer memory/disk inputs.
SandboxSidecarSpecAn extra container started with the sandbox from its own image.
SandboxSpecSandbox creation request.
SandboxStatusProvider-neutral sandbox lifecycle status.
SupportsSandboxBackgroundServicesOptional execution override for services needed by a later command.
SupportsSandboxEndpointOptional provider capability for resolving declared service ports.
SupportsSandboxIndependentUploadsOptional provider capability: a file upload never waits for capacity that running commands hold.
SupportsSandboxNetworkOptional direct networking between sandboxes, preserving service ports.
SupportsSandboxPauseResumeOptional provider capability to pause and resume a sandbox.
SupportsSandboxPortForwardingOptional loopback TCP forwarding, running until cancellation.
SupportsSandboxPtyOptional provider capability: interactive PTY sessions.
SupportsSandboxPtyAttachOptional provider capability: re-attach to a PTY session by id.
SupportsSandboxPullPolicyOptional per-sandbox image pull policy: always, missing or never (Compose’s pull_policy).
SupportsSandboxRuntimeRequirementsOptional validation and setup of task-declared runtime requirements.
SupportsSandboxServiceOptionsOptional container settings a Compose service declares: tmpfs, ulimits, sysctls, security_opt.
SupportsSandboxSharedStorageOptional shared filesystem provisioned by the operator’s provider config.
SupportsSandboxSidecarsOptional provider capability to run sidecar containers next to the sandbox.

Functions

NameDescription
clamp_resource_requestsCap each scheduling request at the limit the spec declares for the same key.
create_providerInstantiate a provider from a single-key provider config.
get_provider_classReturn a provider class by name (explicit > built-in > entry point).
list_providersList available provider names from all sources.
provider_service_option_fieldsThe Compose service options (tmpfs, ulimits, sysctls, security_opt) provider name can apply.
register_providerRegister a sandbox provider class.

Data

ExecResult

API

class nemo_gym.sandbox.providers.ConnectableProvider()
Protocol

Optional capability: rebuild a handle in another process from a descriptor.

Providers whose sandboxes are reachable by id (external control plane, e.g. OpenSandbox and Fargate, and the sandbox server’s remote provider) implement this. A provider that does not implement it can only be shared by fronting it with a sandbox server. Membership is checked with isinstance because the protocol is runtime_checkable.

nemo_gym.sandbox.providers.ConnectableProvider.connect(
descriptor: collections.abc.Mapping[str, typing.Any]
async

Rebuild a live handle in this process from a descriptor.

nemo_gym.sandbox.providers.ConnectableProvider.serialize_handle(
scope: str | None = None
) -> dict[str, typing.Any]
async

Return a JSON-serializable descriptor that connect can rebuild a handle from. scope is honored by providers that mint leases (the remote provider) and ignored by the rest.

class nemo_gym.sandbox.providers.SandboxCreateError()

Bases: RuntimeError

Raised when a provider cannot create a sandbox.

class nemo_gym.sandbox.providers.SandboxCreateVerificationError()

Bases: SandboxCreateError

Raised when a newly-created sandbox fails provider readiness checks.

class nemo_gym.sandbox.providers.SandboxEndpoint(
endpoint: str,
headers: dict[str, str] = dict()
)
Dataclass

Provider-neutral route to a long-lived service inside a sandbox.

endpoint is an absolute URL. headers carries provider-required authentication or routing headers without exposing the provider’s opaque handle to callers.

endpoint
str
headers
dict[str, str] = field(default_factory=dict)
nemo_gym.sandbox.providers.SandboxEndpoint.__post_init__() -> None
class nemo_gym.sandbox.providers.SandboxExecResult(
stdout: str | None,
stderr: str | None,
return_code: int,
error_type: str | None = None
)
Dataclass

Provider-neutral process execution result.

return_code is the process exit code when the sandbox actually ran the command. Providers may use a non-process sentinel with error_type set when the sandbox runtime reports an execution failure without a process exit code.

error_type="user_switch_unavailable" means the provider confirmed that credential switching prevented process launch. Helpers that allow the image’s default user can choose that branch without reporting a failure event.

error_type
str | None = None
return_code
int
stderr
str | None
stdout
str | None
class nemo_gym.sandbox.providers.SandboxHandle(
sandbox_id: str,
provider_name: str,
raw: typing.Any
)
Dataclass

Provider-neutral handle to a created sandbox.

raw is provider-owned opaque state. Public code should pass it back to the provider through this handle rather than inspecting or mutating it directly.

provider_name
str
sandbox_id
str
class nemo_gym.sandbox.providers.SandboxProvider()
Protocol

Runtime/infra provider contract used by the public sandbox API.

name
str
nemo_gym.sandbox.providers.SandboxProvider.aclose() -> None
async

Close provider-scoped resources such as SDK clients.

nemo_gym.sandbox.providers.SandboxProvider.close(
) -> None
async

End the sandbox lifecycle and close provider resources for it.

nemo_gym.sandbox.providers.SandboxProvider.create(
async

Create a ready sandbox and return a provider-neutral handle.

Providers must return only after the sandbox is healthy enough to run commands and transfer files. New and migrated providers must report allocation and readiness failures as NgFailureEvent with boundary="sandbox" and a registered kind. Providers awaiting migration still expose creation exceptions; see the sandbox documentation’s required provider migrations.

nemo_gym.sandbox.providers.SandboxProvider.download_file(
source_path: str,
target_path: pathlib.Path
) -> None
async

Download one sandbox file to the local filesystem.

nemo_gym.sandbox.providers.SandboxProvider.exec(
command: str,
cwd: str | None = None,
env: dict[str, str] | None = None,
timeout_s: int | float | None = None,
user: str | int | None = None
async

Run a command inside a sandbox.

nemo_gym.sandbox.providers.SandboxProvider.status(
async

Return the current sandbox lifecycle status.

nemo_gym.sandbox.providers.SandboxProvider.upload_file(
source_path: pathlib.Path,
target_path: str
) -> None
async

Upload one local file into a sandbox.

class nemo_gym.sandbox.providers.SandboxPtyError()

Bases: RuntimeError

Raised when a PTY session fails outside normal process exit.

class nemo_gym.sandbox.providers.SandboxPtySession()
Protocol

One live interactive terminal. Async context manager; exit closes it.

closed
bool

Whether close() has run; a closed session cannot run commands.

mode
str | None

"pty" or "pipe" once connected, None before that. Only pipe mode splits stderr; in PTY mode all output arrives through read().

session_id
str
nemo_gym.sandbox.providers.SandboxPtySession.__aenter__() -> nemo_gym.sandbox.providers.base.SandboxPtySession
async
nemo_gym.sandbox.providers.SandboxPtySession.__aexit__(
exc_type: typing.Any,
exc_val: typing.Any,
exc_tb: typing.Any
) -> None
async
nemo_gym.sandbox.providers.SandboxPtySession.__aiter__() -> collections.abc.AsyncIterator[bytes]

Yield output chunks until EOF.

nemo_gym.sandbox.providers.SandboxPtySession.close() -> None
async

Idempotent: release local resources; a session this client created is also ended, while an attached one is merely detached and lives on for its owner.

nemo_gym.sandbox.providers.SandboxPtySession.read(
timeout_s: float | None = None
) -> bytes
async

Return the next output chunk (all terminal output in PTY mode; stdout only in pipe mode). b"" means the process exited and the stream is drained. Raises TimeoutError when this wait expires; that alone does not mean the command failed. Report session death as NgFailureEvent; providers awaiting migration use SandboxPtyError.

nemo_gym.sandbox.providers.SandboxPtySession.read_stderr(
timeout_s: float | None = None
) -> bytes
async

Return the next stderr chunk. Only pipe mode (pty=False) carries stderr separately; in PTY mode this stream is empty and returns b"" once the process exits. Same timeout/error semantics as read().

nemo_gym.sandbox.providers.SandboxPtySession.resize(
rows: int,
cols: int
) -> None
async

Resize the terminal.

nemo_gym.sandbox.providers.SandboxPtySession.run_detached(
command: str,
poll_interval_s: float = 15.0
) -> tuple[bytes, int | None]
async

Run one command holding the transport only for brief completion polls; returns (merged output, exit code or None). The server retains a bounded window of output between polls, and exceeding it raises rather than returning truncated output.

nemo_gym.sandbox.providers.SandboxPtySession.send_signal(
signal: str
) -> None
async

Deliver a named signal, e.g. "SIGTERM", to the session’s process group. Interactive shells run foreground jobs in their own group, so signals reliably reach the process only for command sessions; whether SIGINT interrupts at all also depends on the sandbox runtime’s inherited signal dispositions.

nemo_gym.sandbox.providers.SandboxPtySession.wait_exit(
timeout_s: float | None = None
) -> int
async

Block until the process exits and return its exit code.

Raises TimeoutError when this wait expires; that alone does not mean the command failed. Session failures follow the same contract as read.

nemo_gym.sandbox.providers.SandboxPtySession.write(
data: bytes
) -> None
async

Send raw bytes to the terminal’s stdin.

class nemo_gym.sandbox.providers.SandboxPtySpec(
command: str | None = None,
cwd: str | None = None,
env: dict[str, str] | None = None,
rows: int = 24,
cols: int = 80,
user: str | int | None = None,
pty: bool = True
)
Dataclass

Interactive PTY session request.

command runs under the backend’s interactive shell; None spawns the shell itself. Backends without native env/user support may rewrite the command (mirroring exec()’s user rewrite) and must raise ValueError for values they cannot honor. pty=False selects pipe mode: no TTY, stdout and stderr delivered as separate streams, rows/cols ignored. Backends that cannot size a terminal at spawn apply rows/cols as soon as it connects, so a command reading the size immediately may observe the backend default.

cols
int = 80
command
str | None = None
cwd
str | None = None
env
dict[str, str] | None = None
pty
bool = True
rows
int = 24
user
str | int | None = None
class nemo_gym.sandbox.providers.SandboxResources(
cpu: float | None = None,
memory_mib: int | None = None,
disk_gib: int | None = None,
gpu: int | None = None,
gpu_type: str | None = None
)
Dataclass

Bases: SandboxResourceAmounts

Provider-neutral creation request, retaining integer memory/disk inputs.

disk_gib
int | None = None
memory_mib
int | None = None
nemo_gym.sandbox.providers.SandboxResources.from_mapping(
resources: collections.abc.Mapping[str, typing.Any] | None
classmethod
class nemo_gym.sandbox.providers.SandboxSidecarSpec(
name: str,
image: str,
env: dict[str, str] = dict(),
resources: nemo_gym.sandbox.providers.base.SandboxResources | collections.abc.Mapping[str, typing.Any] = SandboxResources()
)
Dataclass

An extra container started with the sandbox from its own image.

The sidecar has its own filesystem. Start services in it with AsyncSandbox.sidecar(name).exec. How the sandbox reaches a sidecar over the network is provider-specific.

env
dict[str, str] = field(default_factory=dict)
image
str
name
str
resources
SandboxResources | Mapping[str, Any] = field(default_factory=SandboxResources)
nemo_gym.sandbox.providers.SandboxSidecarSpec.__post_init__() -> None
class nemo_gym.sandbox.providers.SandboxSpec(
image: str | None = None,
ttl_s: int | float | None = None,
ready_timeout_s: int | float | None = None,
workdir: str | None = None,
env: dict[str, str] = dict(),
files: dict[str, str | bytes] = dict(),
metadata: dict[str, str] = dict(),
resources: nemo_gym.sandbox.providers.base.SandboxResources | collections.abc.Mapping[str, typing.Any] = SandboxResources(),
entrypoint: list[str] | None = None,
provider_options: dict[str, typing.Any] = dict(),
ports: tuple[int, ...] | list[int] = tuple(),
sidecars: tuple[nemo_gym.sandbox.providers.base.SandboxSidecarSpec, ...] | list[nemo_gym.sandbox.providers.base.SandboxSidecarSpec | collections.abc.Mapping[str, typing.Any]] = tuple(),
user: str | int | None = None
)
Dataclass

Sandbox creation request.

entrypoint
list[str] | None = None
env
dict[str, str] = field(default_factory=dict)
files
dict[str, str | bytes] = field(default_factory=dict)
image
str | None = None
metadata
dict[str, str] = field(default_factory=dict)
ports
tuple[int, ...] | list[int] = field(default_factory=tuple)
provider_options
dict[str, Any] = field(default_factory=dict)
ready_timeout_s
int | float | None = None
resources
SandboxResources | Mapping[str, Any] = field(default_factory=SandboxResources)
sidecars
tuple[SandboxSidecarSpec, ...] | list[SandboxSidecarSpec | Mapping[str, Any]] = field(default_factory=tuple)
ttl_s
int | float | None = None
user
str | int | None = None
workdir
str | None = None
nemo_gym.sandbox.providers.SandboxSpec.__post_init__() -> None
class nemo_gym.sandbox.providers.SandboxStatus

Bases: enum.Enum

Provider-neutral sandbox lifecycle status.

ERROR
= 'error'
PAUSED
= 'paused'
RUNNING
= 'running'
STARTING
= 'starting'
STOPPED
= 'stopped'
UNKNOWN
= 'unknown'
class nemo_gym.sandbox.providers.SupportsSandboxBackgroundServices()
Protocol

Optional execution override for services needed by a later command.

nemo_gym.sandbox.providers.SupportsSandboxBackgroundServices.exec_with_background_services(
command: str,
cwd: str | None = None,
env: dict[str, str] | None = None,
timeout_s: int | float | None = None,
user: str | int | None = None
async
class nemo_gym.sandbox.providers.SupportsSandboxEndpoint()
Protocol

Optional provider capability for resolving declared service ports.

nemo_gym.sandbox.providers.SupportsSandboxEndpoint.endpoint(
port: int
async

Resolve a declared service port to a caller-reachable endpoint.

class nemo_gym.sandbox.providers.SupportsSandboxIndependentUploads()
Protocol

Optional provider capability: a file upload never waits for capacity that running commands hold.

A provider that bounds its concurrent operations with one limit shared by commands and file transfers (CLI slots, worker threads, pooled connections) cannot promise this: once long-running commands hold every slot, an upload waits until one of them ends. SandboxSession.expire needs it to stop a running harness, because the stop is a file the harness’s supervisor watches for. The answer may depend on configuration.

nemo_gym.sandbox.providers.SupportsSandboxIndependentUploads.uploads_independent_of_execs() -> bool
class nemo_gym.sandbox.providers.SupportsSandboxNetwork()
Protocol

Optional direct networking between sandboxes, preserving service ports.

nemo_gym.sandbox.providers.SupportsSandboxNetwork.network_address(
) -> str
async
nemo_gym.sandbox.providers.SupportsSandboxNetwork.set_hosts(
hosts: collections.abc.Mapping[str, str]
) -> None
async
nemo_gym.sandbox.providers.SupportsSandboxNetwork.validate_networking() -> None
class nemo_gym.sandbox.providers.SupportsSandboxPauseResume()
Protocol

Optional provider capability to pause and resume a sandbox.

What survives a pause beyond the filesystem is backend-specific.

nemo_gym.sandbox.providers.SupportsSandboxPauseResume.pause(
) -> None
async

Pause a sandbox while preserving its state.

nemo_gym.sandbox.providers.SupportsSandboxPauseResume.resume(
) -> None
async

Resume a paused sandbox and refresh its handle.

class nemo_gym.sandbox.providers.SupportsSandboxPortForwarding()
Protocol

Optional loopback TCP forwarding, running until cancellation.

nemo_gym.sandbox.providers.SupportsSandboxPortForwarding.forward_ports(
target_address: str,
ports: tuple[int, ...],
ready_file: str
) -> None
async
nemo_gym.sandbox.providers.SupportsSandboxPortForwarding.validate_port_forwarding() -> None
class nemo_gym.sandbox.providers.SupportsSandboxPty()
Protocol

Optional provider capability: interactive PTY sessions.

async

Open an interactive terminal inside a sandbox.

class nemo_gym.sandbox.providers.SupportsSandboxPtyAttach()
Protocol

Optional provider capability: re-attach to a PTY session by id.

Separate from SupportsSandboxPty because it requires sessions that live in the sandbox rather than in the client, so a provider may offer terminals without offering re-attach.

nemo_gym.sandbox.providers.SupportsSandboxPtyAttach.attach_pty(
session_id: str,
takeover: bool = True,
since: int | None = None
async

Re-attach to an existing session by id.

takeover evicts the current holder, whose session then fails with SandboxPtyError; without it, attaching to a held session fails. since is a byte offset into the session’s retained output to replay before live output (0 replays everything still retained).

class nemo_gym.sandbox.providers.SupportsSandboxPullPolicy()
Protocol

Optional per-sandbox image pull policy: always, missing or never (Compose’s pull_policy).

pull_policy_options returns the provider_options that apply it at create time. A provider without this capability leaves the pull behaviour to the deployment’s default.

nemo_gym.sandbox.providers.SupportsSandboxPullPolicy.pull_policy_options(
policy: str
) -> dict[str, typing.Any]
class nemo_gym.sandbox.providers.SupportsSandboxRuntimeRequirements()
Protocol

Optional validation and setup of task-declared runtime requirements.

nemo_gym.sandbox.providers.SupportsSandboxRuntimeRequirements.configure_runtime(
cap_add: tuple[str, ...],
shm_size: int | None
) -> None
async
nemo_gym.sandbox.providers.SupportsSandboxRuntimeRequirements.validate_runtime_requirements(
cap_add: tuple[str, ...],
shm_size: int | None
) -> dict[str, str] | None

Validate support and return any required create-time metadata.

class nemo_gym.sandbox.providers.SupportsSandboxServiceOptions()
Protocol

Optional container settings a Compose service declares: tmpfs, ulimits, sysctls, security_opt.

SERVICE_OPTION_FIELDS names the subset the provider can apply; it is a class attribute so prepare can check a task against a provider by name, without instantiating it. service_options returns the provider_options that apply the given values at create time (an empty mapping when none are given) and raises ValueError for a value it cannot express.

SERVICE_OPTION_FIELDS
frozenset[str]
nemo_gym.sandbox.providers.SupportsSandboxServiceOptions.service_options(
tmpfs: tuple[str, ...] = (),
ulimits: collections.abc.Mapping[str, typing.Any] | None = None,
sysctls: collections.abc.Mapping[str, str] | None = None,
security_opt: tuple[str, ...] = ()
) -> dict[str, typing.Any]
class nemo_gym.sandbox.providers.SupportsSandboxSharedStorage()
Protocol

Optional shared filesystem provisioned by the operator’s provider config.

shared_volume_options returns provider options containing a volumes list of opaque mount descriptors. Collections concatenate these lists. source is relative to the configured shared root; None mounts that root for initialization and cleanup. Metadata supplies placement settings.

nemo_gym.sandbox.providers.SupportsSandboxSharedStorage.shared_volume_metadata() -> dict[str, str]
nemo_gym.sandbox.providers.SupportsSandboxSharedStorage.shared_volume_options(
source: str | None,
target: str,
read_only: bool = False
) -> dict[str, typing.Any]
class nemo_gym.sandbox.providers.SupportsSandboxSidecars()
Protocol

Optional provider capability to run sidecar containers next to the sandbox.

The provider creates the sidecars declared in SandboxSpec.sidecars together with the sandbox, then runs commands in them and reads files from them through these calls. Commands run as an argv without a shell, because sidecar images can be distroless.

nemo_gym.sandbox.providers.SupportsSandboxSidecars.download_sidecar_file(
sidecar: str,
source_path: str,
target_path: pathlib.Path
) -> None
async

Download one file from sidecar to the local filesystem.

nemo_gym.sandbox.providers.SupportsSandboxSidecars.sidecar_exec(
sidecar: str,
argv: list[str],
timeout_s: int | float,
on_stdout: collections.abc.Callable[[str], None] | None = None
async

Run argv in sidecar; on_stdout receives stdout text as it arrives, for long-running services.

nemo_gym.sandbox.providers.clamp_resource_requests(
requests: collections.abc.Mapping[str, typing.Any] | nemo_gym.sandbox.providers.base.SandboxResources,
limits: collections.abc.Mapping[str, typing.Any] | nemo_gym.sandbox.providers.base.SandboxResources
) -> tuple[dict[str, typing.Any], dict[str, tuple[typing.Any, typing.Any]]]

Cap each scheduling request at the limit the spec declares for the same key.

Kubernetes never schedules a pod whose request exceeds its limit, and OpenSandbox reports such a sandbox only as “pending allocation”, so a request above a task’s declared limit must not reach the create call. Returns the requests with the offending keys set to their limit, and {key: (request, limit)} for the keys that changed so the caller can log a warning naming them. Keys the limits do not declare pass through untouched.

nemo_gym.sandbox.providers.create_provider(
config: collections.abc.Mapping[str, typing.Any]

Instantiate a provider from a single-key provider config.

nemo_gym.sandbox.providers.get_provider_class(
name: str

Return a provider class by name (explicit > built-in > entry point).

nemo_gym.sandbox.providers.list_providers() -> list[str]

List available provider names from all sources.

nemo_gym.sandbox.providers.provider_service_option_fields(
name: str
) -> frozenset[str]

The Compose service options (tmpfs, ulimits, sysctls, security_opt) provider name can apply.

Read from the provider class’s SERVICE_OPTION_FIELDS (see SupportsSandboxServiceOptions), so prepare can check a task against the deployment’s provider without instantiating it. A provider without the attribute applies none of them.

nemo_gym.sandbox.providers.register_provider(
name: str,
override: bool = False
) -> None

Register a sandbox provider class.

nemo_gym.sandbox.providers.base.ExecResult = SandboxExecResult