Skip to main content

langchain-acasandbox

langchain-acasandbox is an async Azure Container Apps Sandbox provider for LangChain Deep Agents. It provisions a restricted sandbox, exposes command and file operations through the Deep Agents BaseSandbox contract, and confirms deletion when the session ends.

The library is intentionally small. A complete hello-world Deep Agent lives in samples/basic.

The Azure Container Apps sandbox SDK is a preview dependency. Pin and test this library before using it in production.

Requirements

  • Python 3.13 or later
  • An Azure subscription and tenant
  • An existing Azure Container Apps sandbox group
  • Azure CLI authentication for local development, or workload identity in Azure
  • Permission to create, inspect, and delete sandboxes in the group

This project never accepts account keys or client secrets. Credentials stay in the host process and are not forwarded to sandbox commands.

Installation

From PyPI after publication:

uv add langchain-acasandbox

From this checkout:

uv sync --locked

Configuration

Create SandboxConfig directly when values already come from your application configuration:

from langchain_acasandbox import SandboxConfig

config = SandboxConfig(
    subscription_id="00000000-0000-0000-0000-000000000000",
    resource_group="sandbox-rg",
    sandbox_group="agents",
    tenant_id="00000000-0000-0000-0000-000000000000",
    location="swedencentral",
)

Alternatively, SandboxConfig.from_env() reads these variables:

Variable Required Default Meaning
AZURE_SUBSCRIPTION_ID yes Azure subscription
AZURE_TENANT_ID yes Microsoft Entra tenant
SANDBOX_RESOURCE_GROUP yes Resource group containing the sandbox group
SANDBOX_GROUP_NAME yes Sandbox group name
SANDBOX_LOCATION no swedencentral Azure region
AZURE_AUTH_MODE no cli cli or workload
SANDBOX_DISK no ubuntu Base disk name when no disk ID is supplied
SANDBOX_DISK_ID no Existing disk image ID
SANDBOX_SNAPSHOT_ID no Existing snapshot ID; mutually exclusive with disk ID
SANDBOX_IDLE_TIMEOUT_SECONDS no 600 Azure auto-suspend interval
SANDBOX_AUTO_DELETE_SECONDS no 172800 Azure fallback auto-delete interval

Local authentication uses the selected tenant:

az login --tenant "$AZURE_TENANT_ID"

Basic Usage

Always open manager-owned sandboxes with async with. Exiting the block quarantines the backend, deletes the sandbox, and verifies that Azure reports it absent.

import asyncio

from langchain_acasandbox import SandboxConfig, SandboxManager


async def main() -> None:
    manager = SandboxManager(SandboxConfig.from_env())

    async with manager.open() as session:
        result = await session.backend.aexecute("printf 'hello from Azure'", timeout=20)
        if result.exit_code != 0:
            raise RuntimeError(result.output)
        print(result.output)


asyncio.run(main())

The public backend methods are async-only:

backend = session.backend

uploads = await backend.aupload_files([
    ("/workspace/input.txt", b"sandbox input\n"),
])
result = await backend.aexecute(
    "wc -c /workspace/input.txt > /workspace/count.txt",
    timeout=30,
)
downloads = await backend.adownload_files(["/workspace/count.txt"])

if uploads[0].error or result.exit_code or downloads[0].error:
    raise RuntimeError("Sandbox operation failed")

print(downloads[0].content.decode())

Paths must be absolute. File operations return one response per requested path, with a normalized error such as file_not_found, invalid_path, is_directory, or permission_denied.

Deep Agents

Pass the backend directly to create_deep_agent and invoke the graph asynchronously:

from deepagents import create_deep_agent
from langchain_openai import ChatOpenAI

from langchain_acasandbox import SandboxConfig, SandboxManager


async def run_agent() -> None:
    manager = SandboxManager(SandboxConfig.from_env())
    model = ChatOpenAI(model="your-model")

    async with manager.open() as session:
        agent = create_deep_agent(model=model, backend=session.backend)
        result = await agent.ainvoke({
            "messages": [{"role": "user", "content": "Create /workspace/result.txt"}]
        })
        print(result["messages"][-1].content)

The backend implements Deep Agents async execution and file-transfer methods. Its synchronous execute, upload_files, and download_files methods deliberately raise an error.

Lifecycle And Failure Behavior

SandboxManager.open() creates a sandbox with:

  • deny-by-default egress with full traffic inspection
  • no ingress ports or connections
  • auto-suspend after the configured idle interval
  • Azure-side auto-delete as a fallback
  • ownership and expiry labels used by the janitor
  • a prepared /workspace directory

Operations are serialized per backend. The defaults allow a 60-second operation timeout, a 120-second maximum requested timeout, 1 MiB of captured command output, 10 MiB per file, and 100 files per batch.

An unexpected Azure error, cancellation, response-limit breach, or operation timeout quarantines the backend. Later operations fail with SandboxUnavailable; do not reuse a quarantined session. A timeout also means remote command termination is unconfirmed, so the manager proceeds to deletion.

Manager-owned sessions have a 30-minute maximum lifetime and a 10-minute inactivity lifetime. Cleanup is idempotent and deletion must be confirmed. Expiry-task cleanup failures are available as session.cleanup_error; explicit close failures are raised to the caller. Run the janitor after interrupted processes or uncertain cleanup.

If you instantiate AzureContainerAppsSandbox directly around an SDK SandboxClient, the adapter borrows that client. You own the client lifecycle and deletion of the Azure resource.

Operator Commands

Commands use the same environment configuration:

uv run --env-file .env acasandbox smoke
uv run --env-file .env acasandbox janitor
uv run --env-file .env acasandbox inventory
uv run --env-file .env acasandbox image-import
  • smoke provisions a sandbox, verifies required tools and binary file transfer, then deletes it.
  • janitor deletes expired sandboxes carrying the library ownership label.
  • inventory lists sandboxes and disk images in the configured group.
  • image-import imports the Python 3.13 image pinned in src/langchain_acasandbox/cli.py. This creates a billable Azure resource.

Development

make check

This runs Ruff, Pyright, and all non-live unit tests. Azure integration tests are opt-in and may incur charges:

RUN_SANDBOX_LIVE=1 uv run pytest tests/integration_tests -q -m live

Infrastructure is under infra. Start with the basic hello-world agent.

Publishing

Releases publish to PyPI through GitHub Actions trusted publishing. Configure a PyPI trusted publisher with:

Setting Value
Owner danigian
Repository langchain-acasandbox
Workflow publish.yml
Environment pypi

No PyPI token is stored in GitHub. To publish, update the version in pyproject.toml, push main, and publish a GitHub release whose tag is exactly v<version>, such as v0.1.0. The workflow runs all checks, builds and validates both distributions, and publishes the tested artifacts only after the pypi environment gate.

Metadata

Release files for langchain-acasandbox 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for langchain-acasandbox 0.1.0
File Size Uploaded
langchain_acasandbox-0.1.0.tar.gz 91.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for langchain-acasandbox 0.1.0
File Interpreter ABI Platform
langchain_acasandbox-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 107.7 kB

Release files / langchain_acasandbox-0.1.0.tar.gz

Download URL langchain_acasandbox-0.1.0.tar.gz
Size 91.9 kB
Tags Source
SHA-256 checksum
How to use checksums
d9d7bcb269ce5dab25ede88b4e57c8967edeb49a05f29fdb6f683c2a55b9b171
BLAKE2b-256 checksum
How to use checksums
f8ea4250ac45b0c97b3109ef10fd0204bbfd051a3efda666200ea7147238a015
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / langchain_acasandbox-0.1.0-py3-none-any.whl

Download URL langchain_acasandbox-0.1.0-py3-none-any.whl
Size 15.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4293d52be3de5ac22d21c49b7f4c7ee1d277660746693330986f64d75fb42794
BLAKE2b-256 checksum
How to use checksums
73e7fb1deff6813c29d087b0ed041ed5112444343b876209fd47ea89afed342c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page