Declarative Usage (@sandbox Decorator)
The @sandbox decorator lets you declaratively execute Python functions in a remote sandbox without manually managing the sandbox lifecycle.
Basic Usage
from agent_sandbox.declarative import sandbox
@sandbox(template="code-interpreter-v1")
def analyze(data):
import pandas as pd
df = pd.DataFrame(data)
return df.describe().to_dict()
# When called, it automatically: creates sandbox → uploads function → executes → returns result → destroys sandbox
result = analyze({"col1": [1, 2, 3], "col2": [4, 5, 6]})
print(result)
Parameter Configuration
@sandbox(
template="code-interpreter-v1", # Template name (default "code-interpreter-v1")
timeout=300, # Sandbox timeout in seconds (default 300)
envs={"MY_KEY": "value"}, # Environment variables
packages=["pandas", "numpy"], # pip packages to pre-install remotely
serializer="json", # Serialization method (default "json")
sandbox_id=None, # Reuse an existing sandbox ID (skips creation when not None)
keep_alive=False, # When True, the sandbox is not destroyed after execution
api_key=None, # API Key override
api_url=None, # Platform API URL override
domain=None, # Domain override
cpu=None, # CPU cores
memory=None, # Memory in MB
)
def my_func():
pass
Parameter Details
| Parameter | Type | Default | Description |
|---|---|---|---|
template |
str |
"code-interpreter-v1" |
Sandbox template name |
timeout |
int |
300 |
Sandbox timeout in seconds |
envs |
dict |
None |
Injected environment variables (envd scope; see Environment Variables Guide) |
packages |
list[str] |
None |
pip packages to pre-install remotely |
serializer |
str |
"json" |
Serialization mode (only json is supported) |
sandbox_id |
str |
None |
Reuse an existing sandbox ID |
keep_alive |
bool |
False |
Do not destroy the sandbox after execution |
api_key |
str |
None |
API Key override |
api_url |
str |
None |
Platform URL override |
domain |
str |
None |
Platform domain |
cpu |
int |
None |
CPU cores |
memory |
int |
None |
Memory in MB |
Serialization Rules
The serializer parameter controls how function arguments and return values are serialized. Currently only JSON mode is supported.
| Mode | Extra Dependencies | Supported Types | Description |
|---|---|---|---|
json (default) |
None | JSON-serializable types | Safest, cross-language compatible |
JSON mode: Arguments are serialized via json.dumps, and results are deserialized via json.loads. Unsupported types fall back to default=str.
Using with async
The decorator automatically detects whether the decorated function is asynchronous:
@sandbox(template="code-interpreter-v1")
async def async_analyze(data):
import pandas as pd
df = pd.DataFrame(data)
return df.describe().to_dict()
# Async call
result = await async_analyze({"col": [1, 2, 3]})
For synchronous functions, the decorator generates a synchronous wrapper. If the synchronous wrapper is called within an existing event loop, it uses a ThreadPoolExecutor to avoid blocking.
Reusing a Sandbox
# Create a sandbox and keep it running
@sandbox(template="code-interpreter-v1", keep_alive=True)
def setup():
import subprocess
subprocess.run(["pip", "install", "flask"])
return "ready"
sandbox_id = "sbx-xxxx" # Get the sandbox ID
# Reuse the existing sandbox
@sandbox(sandbox_id=sandbox_id)
def use_flask():
from flask import Flask
return "Flask imported successfully"
Registration-Style Commands
In addition to the decorator pattern, the sandbox object also supports registration-style commands:
from agent_sandbox.declarative import sandbox
@sandbox.register
def demo(x: int, y: str) -> str:
"""A simple demo command"""
return f"{y}={x}"
# Sync call
result = sandbox.run("demo", x=1, y="hello")
print(result) # "hello=1"
# Async call
result = await sandbox.run_async("demo", x=2, y="world")
# List registered commands
commands = sandbox.list_registered()
Registered function parameters only support scalar types: str, int, float, bool.
This is the one mechanism for named commands. A command registered in a template's commands.py (or with @sandbox.register) is served by the in-sandbox server, and a regular Sandbox calls it with await sandbox.run("demo", x=1, y="hello") (POST /commands/demo). template.yaml has no custom_commands key; the client rejects it.
File Transfer
sandbox.register only registers named commands. File upload and download are endpoints of the server's file_ops group (on by default); a client uses sandbox.files or ServerClient.files.
Start the HTTP Server
sandbox.server.start(port=9000, host="0.0.0.0")
Limitations
- Parameter serialization: Function arguments and return values must be JSON-serializable (non-serializable types fall back to
str) - Function source code: The decorator obtains function source via
inspect.getsource()— lambdas and dynamically generated functions are not supported - Imports: Libraries needed in the remote sandbox must be pre-installed via the
packagesparameter or already included in the template - Registered command parameter types:
@sandbox.registeronly supports scalar types (str/int/float/bool) — complex types are not supported - Closure variables: External variables referenced in the function are not automatically serialized — use explicit parameter passing instead
- Execution environment isolation: The decorated function runs in an independent remote Python process and does not share state with the local process
Next Steps
- SDK Usage Guide — Use the Sandbox API directly
- Authoring Templates — Create custom templates
- API Reference — Complete API signatures