airflow.providers.common.ai.toolsets.sandbox¶
Toolset giving an agent shell and file access inside an isolated sandbox, off the worker.
Attributes¶
Classes¶
Give an agent shell and file access inside a disposable sandbox, off the Airflow worker. |
Module Contents¶
- class airflow.providers.common.ai.toolsets.sandbox.SandboxToolset(backend, *, spec=None, default_command_timeout=60.0, max_command_timeout=300.0, max_output_lines=2000, max_output_bytes=50 * 1024, max_read_bytes=5 * 1024 * 1024, tool_prefix='', attach_to=None, owner=None, exports=None, export_conn_id=None, max_export_bytes=1024 * 1024 * 1024)[source]¶
Bases:
airflow.providers.common.ai.utils.toolset_base.AirflowToolsetGive an agent shell and file access inside a disposable sandbox, off the Airflow worker.
Note
Experimental: this can change or be removed in a minor release of this provider. See Stable and experimental features.
Exposes four tools –
run_command,read_file,write_fileandlist_directory– against a sandbox provisioned by the givenSandboxBackend. The same four names and shapes are what pydantic-ai’s own sandbox capabilities use, so a model that has seen one already knows this one.What the boundary covers. Only what these tools do runs in the sandbox. The agent loop, the LLM calls, and every other toolset on the same agent still run in the Airflow worker process with its credentials. This contains model-written code; it does not contain the agent. See the toolsets documentation for the full picture of which boundary protects what.
The sandbox is created lazily on the first tool call, shared by every call within one agent run, and destroyed when that run ends. A run that never calls a tool never provisions one. Files persist between calls in a run; each
run_commandis a fresh shell, so shell variables do not.Or the sandbox is someone else’s. With
attach_toset to the handle another task provisioned, the toolset uses that sandbox for the run and does not destroy it: the task that created it decides its environment, its network policy and its lifetime, and reads out whatever the agent left behind. The handle alone is not enough. The sandbox has to carry the owner the toolset presents, by default the current Dag run, so a wrong handle from an upstream XCom is refused rather than used, and one agent run holds a sandbox at a time.attach_tois templated when the toolset is passed throughAgentOperator(toolsets=...), wherever it sits in that list, which is how the handle travels from the provisioning task:attach_to="{{ ti.xcom_pull('provision') }}".Files the agent builds can leave.
exportsmaps a path in the sandbox to an object-storage destination, and when the run ends the toolset copies each file there before it destroys the sandbox. The copy streams through the worker in bounded pieces and never passes through the model’s context or XCom, so a parquet file, a chart, or a trained model is as easy to hand downstream as a line of text. The destinations are templated the same wayattach_tois. A promised file that cannot be exported fails the task, and a failed run exports nothing; a sandbox that cannot be destroyed afterwards does not fail the task.A non-zero exit or a timeout is normal tool output – the model reads it and corrects itself. A recoverable sandbox failure becomes a bounded retry. Only a terminal failure (credentials rejected, daemon unreachable) fails the task, so Airflow’s own retry handles it.
- Parameters:
backend (airflow.providers.common.ai.sandbox.base.SandboxBackend) – Backend that provisions and drives the sandbox.
spec (airflow.providers.common.ai.sandbox.base.SandboxSpec | None) – What to provision the sandbox with – environment variables and network policy. Defaults to no environment and no egress.
default_command_timeout (float) – Seconds allowed for a
run_commandcall when the model does not ask for one. Default60.max_command_timeout (float) – Hard ceiling in seconds for any single command, including a model-supplied
timeout_seconds. Default300.max_output_lines (int) – Maximum lines retained per output stream or file read. Default
2000.max_output_bytes (int) – Maximum bytes retained per output stream or file read. Default 50 KiB. Whichever cap is reached first wins.
max_read_bytes (int) – Largest file
read_filewill transfer. Default 5 MiB; larger files are refused with a hint to slice them in the shell.tool_prefix (str) – Prefix for the four tool names, e.g.
"local"giveslocal_run_command. Set this when one agent has more than oneSandboxToolset, since duplicate tool names are rejected.attach_to (str | None) – Handle of a sandbox another task provisioned, to use instead of creating one. Needs a backend that can find a sandbox from another process (an
AttachableSandboxBackend, whichModalSandboxBackendis andSbxSandboxBackendis not), and cannot be combined withspec, since the sandbox is already provisioned. The toolset never destroys an attached sandbox.exports (collections.abc.Mapping[str, str] | None) – Files to copy out of the sandbox when the run ends, as a mapping from a path in the sandbox (relative paths resolve the way the
read_filetool resolves them) to an object-storage URL such as"s3://bucket/{{ run_id }}/report.parquet", anythingObjectStoragePathcan open. Only a regular file is exported. Cannot be combined withattach_to: the task that owns an attached sandbox collects its files itself.export_conn_id (str | None) – Airflow connection for the export destinations, or
Nonefor the storage’s default credentials. Only meaningful withexports.max_export_bytes (int) – Largest file an export will copy. Default 1 GiB.
owner (str | None) – The owner the attached sandbox must carry. Defaults to the Dag run the task is part of, which is what a provisioning task in the same run stamps with
SandboxSpec(owner=dag_run_owner(context)). Set it only when the sandbox was provisioned under another name, or when the toolset runs outside an Airflow task. Only meaningful withattach_to.
- agent_template_fields: collections.abc.Sequence[str] = ('attach_to', '_exports', '_export_conn_id')[source]¶
- property id: str[source]¶
An ID for the toolset that is unique among all toolsets registered with the same agent.
If you’re implementing a concrete implementation that users can instantiate more than once, you should let them optionally pass a custom ID to the constructor and return that here.
A toolset needs to have an ID in order to be used in a durable execution environment like Temporal, in which case the ID will be used to identify the toolset’s activities within the workflow.
IDs wrapped in angle brackets (‘<agent>’ for an agent’s own function toolset, ‘<output>’ for its output tools) name a role the framework fills on the user’s behalf rather than a registered toolset. Don’t return one from your own toolset.
- async for_run(ctx)[source]¶
Return the toolset to use for this agent run.
Called once per run, before __aenter__. Override this to return a fresh instance for per-run state isolation. Default: return self (shared across runs).
- async __aenter__()[source]¶
Enter the toolset context.
This is where you can set up network connections in a concrete implementation.
- async __aexit__(*args)[source]¶
Exit the toolset context.
This is where you can tear down network connections in a concrete implementation.
- __enter__()[source]¶
Own the sandbox’s lifetime from synchronous code, such as a task running a native agent.
- async execute_tool(name, tool_args, *, ctx, tool)[source]¶
Run tool
namewith validatedtool_argsand return its result unmasked.This is the method a subclass implements;
call_tool()runs it and masks what it returns.ctxandtoolare keyword-only so that arguments can be added here later without breaking subclasses.