How to Configure Sandbox Execution with SandboxBackendProtocol for Tool Execution in DeepAgents

Configure sandbox execution by selecting a provider (modal, runloop, daytona, or langsmith), initializing a sandbox via the create_sandbox() context manager, and calling execute() or aexecute() to run isolated tool commands.

The langchain-ai/deepagents repository provides a robust sandboxing system that isolates tool execution through the SandboxBackendProtocol. This protocol enables secure, backend-agnostic command execution across multiple cloud providers while maintaining a consistent interface for file operations and process management.

Understanding the SandboxBackendProtocol Architecture

The sandbox system centers on a protocol-based design that abstracts provider-specific implementations behind a unified interface.

Protocol Definition and Core Methods

SandboxBackendProtocol extends BackendProtocol in libs/deepagents/deepagents/backends/protocol.py to add sandbox-specific capabilities. The protocol requires implementations to provide:

  • execute(command, timeout=None): Synchronously run shell commands inside the isolated environment
  • aexecute(command, timeout=None): Asynchronous variant for non-blocking execution
  • id property: A unique identifier for the sandbox instance

According to the source code in protocol.py (lines 12-30 and 112-124), these methods must return an ExecuteResponse object containing the combined stdout/stderr output, exit code, and a truncated flag indicating whether output exceeded limits.

Provider Factory Pattern

Concrete implementations are instantiated through a factory pattern defined in libs/cli/deepagents_cli/integrations/sandbox_factory.py. The _get_provider() method (lines 58-86) maps provider names to specific implementations:

  • modal: Cloud-based containerized execution
  • runloop: Alternative cloud provider integration
  • daytona: Development environment sandboxing
  • langsmith: LangChain-specific execution backend

Each provider must implement the abstract SandboxProvider interface defined in libs/cli/deepagents_cli/integrations/sandbox_provider.py (lines 26-36), ensuring consistent lifecycle management across different backends.

Step-by-Step Configuration Guide

Select a Sandbox Provider

Choose a provider based on your infrastructure requirements. The provider name string determines which backend implementation the factory instantiates:


# Available providers: "modal", "runloop", "daytona", "langsmith"

provider_name = "modal"

Initialize the Sandbox with create_sandbox

Use the create_sandbox() context manager from sandbox_factory.py (lines 71-110) to handle setup, status reporting, and automatic cleanup:

from deepagents_cli.integrations.sandbox_factory import create_sandbox

# Context manager ensures proper resource cleanup

with create_sandbox("modal") as sandbox:
    # sandbox implements SandboxBackendProtocol

    pass

The context manager optionally accepts a setup_script_path parameter. When provided, the factory reads the script, substitutes environment variables (e.g., ${VAR}), and executes it inside the sandbox with a 5-minute timeout before yielding control.

Execute Tool Commands

Invoke commands through the execute() method for synchronous operations or aexecute() for async workflows. The BaseSandbox class in libs/deepagents/deepagents/backends/sandbox.py (lines 17-24) implements all file system operations (read, write, edit, grep_raw, glob_info) by delegating to shell snippets executed through these methods.


# Synchronous execution

result = sandbox.execute("python /workspace/analyze.py", timeout=60)

The optional timeout parameter is validated through the execute_accepts_timeout() helper in protocol.py (lines 70-89). If the concrete backend does not support timeout arguments, the parameter is safely ignored rather than raising an error.

Handle Execution Responses

Process the ExecuteResponse object returned by execution calls. Defined in sandbox.py (lines 95-106), this dataclass provides:

  • output: Combined stdout and stderr as a string
  • exit_code: Integer return code from the process
  • truncated: Boolean indicating whether output was truncated due to length limits
if result.exit_code == 0:
    print("Output:", result.output)
else:
    print("Error occurred, truncated:", result.truncated)

Practical Implementation Examples

Synchronous Tool Execution

Run commands in a Modal-hosted sandbox with immediate feedback:

from deepagents_cli.integrations.sandbox_factory import create_sandbox

with create_sandbox("modal") as sandbox:
    # Execute a file listing command

    result = sandbox.execute("ls -la /workspace")
    print(f"Exit code: {result.exit_code}")
    print(f"Output:\n{result.output}")

This example pulls the ModalProvider implementation and returns a SandboxBackendProtocol instance. The execute call runs inside the Modal container and returns an ExecuteResponse with full output capture.

Asynchronous Execution with Timeouts

Handle long-running tools without blocking the event loop:

import asyncio
from deepagents_cli.integrations.sandbox_factory import create_sandbox

async def run_long_task():
    async with create_sandbox("runloop") as sandbox:
        # 30-second timeout for the command

        resp = await sandbox.aexecute(
            "sleep 10 && echo 'Processing complete'", 
            timeout=30
        )
        
        if resp.exit_code == 0:
            print("Success:", resp.output.strip())
        else:
            print(f"Failed with code {resp.exit_code}")

asyncio.run(run_long_task())

The aexecute method automatically falls back to synchronous execution if the backend lacks native async support, ensuring compatibility across all providers.

Setup Script Configuration

Initialize the sandbox environment with custom dependencies before tool execution:

from deepagents_cli.integrations.sandbox_factory import create_sandbox

with create_sandbox(
    "daytona",
    setup_script_path="scripts/install_deps.sh"
) as sandbox:
    # Setup script runs first with env var substitution

    result = sandbox.execute("python -c 'import pandas; print(pandas.__version__)'")
    print(result.output)

The setup script execution occurs within the context manager initialization, ensuring the environment is ready before your tool commands run.

Accessing Sandbox Metadata

Inspect the sandbox identifier for logging or external monitoring:

with create_sandbox("langsmith") as sandbox:
    print(f"Sandbox ID: {sandbox.id}")
    # Use ID for external API calls or cleanup tracking

    result = sandbox.execute("echo 'Task started'")

The id property is required by the SandboxBackendProtocol specification and uniquely identifies the instance throughout its lifecycle.

Key Implementation Files and Architecture

Understanding the source structure helps debug configuration issues:

Summary

  • SandboxBackendProtocol extends BackendProtocol with execute(), aexecute(), and an id property for isolated command execution
  • Provider selection (modal, runloop, daytona, langsmith) occurs through sandbox_factory.py's _get_provider() mapping
  • Initialization uses the create_sandbox() context manager, which handles setup scripts and automatic resource cleanup
  • Execution returns ExecuteResponse objects containing output, exit_code, and truncation status
  • Timeout handling is optional and safely ignored if the backend implementation does not support it
  • File operations in BaseSandbox delegate to shell commands executed through the protocol methods

Frequently Asked Questions

What providers are supported for SandboxBackendProtocol?

The deepagents CLI supports four providers: modal, runloop, daytona, and langsmith. Each implements the SandboxProvider interface and returns a concrete SandboxBackendProtocol instance. The mapping from provider name to implementation class is defined in sandbox_factory.py (lines 58-86).

How does the timeout parameter work in execute() calls?

The timeout parameter is optional and passed directly to the backend's execute() or aexecute() method. According to protocol.py (lines 70-89), the system checks whether the concrete implementation accepts timeout arguments using execute_accepts_timeout(). If the backend does not support timeouts, the parameter is silently ignored rather than raising a TypeError.

Can I run setup scripts before executing my tools?

Yes. Pass the setup_script_path parameter to create_sandbox(). The factory reads the specified file, substitutes environment variables (format ${VAR}), and executes the script inside the sandbox with a 5-minute hard timeout before yielding the backend instance. This occurs in sandbox_factory.py (lines 71-110).

What information does ExecuteResponse contain?

ExecuteResponse is a dataclass defined in sandbox.py (lines 95-106) containing three fields: output (combined stdout and stderr as a string), exit_code (integer process return code), and truncated (boolean indicating whether the output exceeded length limits and was cut off).

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →