Airflow Summit 2026 is coming August 31 - September 2 in Austin, TX. Register now to secure your spot!

airflow.providers.common.ai.sandbox.base

Vendor-neutral contract for running agent commands and file operations in an isolated sandbox.

Exceptions

SandboxError

A sandbox operation failed in a way the agent may be able to work around.

SandboxTerminalError

The sandbox is unusable and retrying the same call cannot succeed.

SandboxFileTooLargeError

A file is larger than the caller's read budget, so it was not transferred.

Classes

SandboxSpec

What a single sandbox should be provisioned with.

SandboxExecResult

Outcome of one command executed inside a sandbox.

SandboxBackend

Contract for running commands and file operations in an isolated sandbox.

Module Contents

exception airflow.providers.common.ai.sandbox.base.SandboxError[source]

Bases: Exception

A sandbox operation failed in a way the agent may be able to work around.

The toolset turns this into a ModelRetry so the model can adjust and try again within the run (a bad path, a command the image cannot run).

exception airflow.providers.common.ai.sandbox.base.SandboxTerminalError[source]

Bases: SandboxError

The sandbox is unusable and retrying the same call cannot succeed.

Credentials were rejected, the daemon is unreachable, the sandbox is gone. The toolset lets this propagate and fail the task, so Airflow’s own retry handles it rather than the model burning its retry budget.

exception airflow.providers.common.ai.sandbox.base.SandboxFileTooLargeError(path, size_bytes, max_bytes)[source]

Bases: SandboxError

A file is larger than the caller’s read budget, so it was not transferred.

path[source]
size_bytes[source]
max_bytes[source]
class airflow.providers.common.ai.sandbox.base.SandboxSpec[source]

What a single sandbox should be provisioned with.

Passed to SandboxBackend.create(). Every field is optional and a backend may not be able to honor all of them; a backend that cannot enforce a field it was given must raise rather than silently ignore it, so a DAG author never believes a restriction is in force when it is not.

Parameters:
  • env – Environment variables to set inside the sandbox. Airflow never populates this itself – the DAG author decides what, if anything, the sandbox is given. Anything placed here is visible to model-generated code, so scope it to what that code legitimately needs.

  • block_network – Deny all outbound network access. Defaults to True: an isolated sandbox that cannot phone home is the safe starting point, and egress is opened deliberately.

  • allow_egress_to – Hostnames the sandbox may reach when block_network is True. An empty or unset value with block_network=True means no egress at all.

env: collections.abc.Mapping[str, str] | None = None[source]
block_network: bool = True[source]
allow_egress_to: collections.abc.Sequence[str] | None = None[source]
class airflow.providers.common.ai.sandbox.base.SandboxExecResult[source]

Outcome of one command executed inside a sandbox.

timed_out means the command hit the budget, so exit_code carries no meaning. stdout_truncated / stderr_truncated mean the backend dropped bytes while reading that stream, before any model-facing formatting. sandbox_terminated means the backend destroyed the sandbox to stop the command, so the toolset must provision a fresh one before the next call.

exit_code: int[source]
stdout: str[source]
stderr: str[source]
timed_out: bool = False[source]
stdout_truncated: bool = False[source]
stderr_truncated: bool = False[source]
sandbox_terminated: bool = False[source]
class airflow.providers.common.ai.sandbox.base.SandboxBackend[source]

Bases: abc.ABC

Contract for running commands and file operations in an isolated sandbox.

The lifecycle is create -> (any number of operations) -> destroy, driven by SandboxToolset. The four operation methods are named after the four tools the toolset exposes, so the mapping from a model-facing tool to the backend call behind it is literal; create and destroy are lifecycle and have no tool.

Implementations must be cheap to construct, because constructors run at Dag-parse time: resolve credentials and open connections lazily, on first use. destroy must be idempotent – destroying an already-gone sandbox is not an error. All methods are synchronous; the toolset offloads them to a thread, so a call may block for as long as its timeout allows.

Raise SandboxError for a failure the model could work around, and SandboxTerminalError for one it cannot.

name: ClassVar[str][source]

Short backend identifier (e.g. "sbx"), used in the toolset id.

abstract create(*, spec=None)[source]

Provision one sandbox and return its handle (name or id).

spec of None means “no requirements stated”: the backend applies its own defaults and makes no guarantee. It is not the same as a default SandboxSpec, which is an explicit request for an isolated sandbox. The toolset always sends a concrete spec, so None only reaches a backend a caller drives directly.

Raise SandboxTerminalError if spec asks for something this backend cannot enforce, rather than provisioning something weaker than was asked for. It is terminal rather than recoverable because it states a configuration fact the model cannot see and cannot fix by retrying.

abstract run_command(sandbox, command, *, timeout, max_output_bytes)[source]

Run command through a shell in the sandbox, bounded by timeout seconds.

max_output_bytes bounds what the backend retains per stream while reading, so unbounded command output cannot exhaust worker memory before the toolset gets a chance to format it.

read_file(sandbox, path, *, max_bytes)[source]

Read a file from the sandbox.

Raise SandboxFileTooLargeError instead of transferring a file larger than max_bytes.

write_file(sandbox, path, content)[source]

Write content to path in the sandbox, creating parent directories.

The payload rides in the command itself, so this default is bounded by the guest’s command-line length. A backend that can stream stdin or upload directly should override.

list_directory(sandbox, path)[source]

Return (name, is_dir) for each entry in a sandbox directory.

abstract destroy(sandbox)[source]

Tear down the sandbox. Must be idempotent.

Was this entry helpful?