The sandbox system isolates tool execution from your host, giving you a safe environment for file operations and code execution. You pick a backend depending on where you’re running: LocalSandbox for development, E2BSandbox for production.
Backends
| Backend | Use when |
|---|
LocalSandbox | Development and testing — runs commands directly on your local system |
E2BSandbox | Production — runs commands in a cloud-isolated container via e2b.dev |
Configuration
Add a sandbox_config block to your agent’s YAML file.
LocalSandbox
E2BSandbox
Python
sandbox_config:
type: local
work_dir: /path/to/working/directory # optional, defaults to current directory
persist_sandbox: true # optional, default true
sandbox_config:
type: e2b
work_dir: /home/user # optional, defaults to /home/user
template: base # E2B template name, default "base"
timeout: 300 # seconds, default 300
api_key: ${env.E2B_API_KEY}
persist_sandbox: true # if false, sandbox is destroyed after agent.run
envs:
CUSTOM_VAR: value
from nexau.archs.main_sub.config import AgentConfig
config = AgentConfig(
name="my_agent",
llm_config={"model": "gpt-4o"},
sandbox_config={
"type": "local", # or "e2b"
},
)
E2B configuration options
| Option | Default | Description |
|---|
template | "base" | E2B template (Docker image) to use |
timeout | 300 | Sandbox timeout in seconds |
api_key | — | E2B API key. Can reference ${env.E2B_API_KEY} |
persist_sandbox | true | If false, the sandbox is destroyed after each agent.run call |
envs | — | Environment variables to set inside the sandbox |
metadata | — | Custom metadata dictionary attached to the sandbox |
keepalive_interval | 60 | Seconds between keepalive pings. Set to 0 to disable |
max_retries | 5 | Max retries per SDK operation on transient network errors |
force_http | false | Use HTTP instead of HTTPS — useful for self-hosted E2B |
Bash output truncation
When a bash command produces large output, the sandbox automatically truncates it to avoid filling your LLM’s context window. The full output is always preserved in a temp file so your agent can read it if needed.
How it works
- Every
execute_bash call writes stdout and stderr to /tmp/nexau_bash_tool_results/{uuid}/.
- After execution, if the combined output exceeds
output_char_threshold characters, each stream is independently truncated — keeping the first N and last M characters.
- The truncated output includes a hint pointing to the full file.
[first 5,000 chars of stdout]
... [15,000 characters omitted] ...
(Full output: /tmp/nexau_bash_tool_results/a1b2c3d4/stdout.txt)
[last 5,000 chars of stdout]
Configuring thresholds
sandbox_config:
type: local # or e2b
output_char_threshold: 10000 # total chars before truncation kicks in (default: 10,000)
truncate_head_chars: 5000 # chars to keep from the start (default: 5,000)
truncate_tail_chars: 5000 # chars to keep from the end (default: 5,000)
Add execute_bash to the bypass_tool_names list in LongToolOutputMiddleware to avoid double-truncating its output. See Middleware for details.
Tools can access the active sandbox through agent_state.get_sandbox():
from nexau.archs.sandbox import BaseSandbox, SandboxStatus
from nexau.archs.main_sub.agent_state import AgentState
def file_analyzer(file_path: str, agent_state: AgentState) -> dict:
sandbox: BaseSandbox | None = agent_state.get_sandbox()
if not sandbox.file_exists(file_path):
return {"error": f"File not found: {file_path}"}
result = sandbox.read_file(file_path)
if result.status != SandboxStatus.SUCCESS:
return {"error": result.error}
info = sandbox.get_file_info(file_path)
return {
"path": file_path,
"size": info.size,
"lines": len(result.content.split("\n")) if result.content else 0,
}
For code execution:
from nexau.archs.sandbox import BaseSandbox, CodeLanguage
from nexau.archs.main_sub.agent_state import AgentState
def run_analysis(data: dict, agent_state: AgentState) -> dict:
sandbox: BaseSandbox | None = agent_state.get_sandbox()
code = f"""
import json
data = {data}
print(json.dumps({{'count': len(data), 'keys': list(data.keys())}}))
"""
result = sandbox.execute_code(
code=code,
language=CodeLanguage.PYTHON,
timeout=30000, # milliseconds
)
if result.status == SandboxStatus.SUCCESS:
import json
output = result.outputs[0]["text"] if result.outputs else "{}"
return json.loads(output)
return {"error": result.error_value}
State persistence
Sandbox state is automatically persisted to the session so it survives agent restarts. When agent.run completes, the sandbox manager saves its state. On the next start() call with the same session, it reconnects to the existing sandbox instance rather than creating a new one.
Pass session_manager=None to disable persistence and always create a fresh sandbox.
For E2B sandboxes, you can also reconnect to an existing sandbox directly by setting sandbox_id in your config. The manager will call Sandbox.connect(sandbox_id=...) instead of creating a new container.