Metadata-Version: 2.4
Name: agentsandbox-sdk
Version: 0.1.0
Summary: Python SDK for the AgentSandbox API - sandbox execution service for Python/Bash code
Project-URL: Homepage, https://github.com/AgentSandboxCo/agentsandbox-python
Project-URL: Documentation, https://github.com/AgentSandboxCo/agentsandbox-python#readme
Project-URL: Repository, https://github.com/AgentSandboxCo/agentsandbox-python
Author-email: AgentSandbox <eishan@agentsandbox.co>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx>=0.25.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: dev
Requires-Dist: mypy>=1.0.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Description-Content-Type: text/markdown

# AgentSandbox Python SDK

A modern Python SDK for the AgentSandbox API - execute Python and Bash code in isolated sandbox environments.

## Installation

```bash
pip install agentsandbox
```

## Quick Start

```python
from agentsandbox import AgentSandbox

# Initialize the client
client = AgentSandbox(api_key="your-api-key")
# Or set AGENTSANDBOX_API_KEY environment variable

# Execute Python code
result = client.run("print('Hello, World!')")
print(result.stdout)  # Hello, World!
print(result.exit_code)  # 0
```

## Features

- **Sync and Async clients** - Use `AgentSandbox` or `AsyncAgentSandbox`
- **Session management** - Persistent `/workspace` directory across executions
- **File operations** - Upload, download, and manage files
- **Environment variables** - Inject env vars into sandbox executions
- **File injection** - Pre-load files into `/workspace` before execution
- **Context managers** - Automatic resource cleanup
- **Pydantic models** - Full type hints and validation

## Usage

### Basic Execution

```python
from agentsandbox import AgentSandbox, Language

client = AgentSandbox(api_key="your-api-key")

# Python execution
result = client.run("print(1 + 1)")
print(result.stdout)  # 2

# Bash execution
result = client.run("echo 'Hello' && ls -la", language=Language.BASH)
print(result.stdout)
```

### Environment Variables

Inject environment variables into the sandbox:

```python
result = client.run(
    """
import os
print(os.environ['API_KEY'])
print(os.environ['DEBUG'])
""",
    env_vars={"API_KEY": "secret123", "DEBUG": "true"}
)
```

### File Injection

Inject files into `/workspace` before execution:

```python
# Upload a file first
uploaded = client.files.upload(b"name,value\nfoo,1\nbar,2", filename="data.csv")

# Inject file into execution
result = client.run(
    """
import pandas as pd
df = pd.read_csv('/workspace/data.csv')
print(df)
""",
    file_ids=[uploaded.file_id]
)

# Clean up
client.files.delete(uploaded.file_id)
```

### Sessions with Persistent Workspace

**Important**: Each `run()` call executes in a fresh process. In-memory variables do NOT persist between executions. Sessions provide a persistent `/workspace` directory for sharing state via files.

```python
with client.sessions.context() as session:
    sid = session.session_id

    # Write state to a file (persists in session)
    client.run("""
import json
with open('/workspace/state.json', 'w') as f:
    json.dump({'counter': 42}, f)
""", session_id=sid)

    # Read state from file in next execution
    result = client.run("""
import json
with open('/workspace/state.json') as f:
    data = json.load(f)
print(data['counter'])
""", session_id=sid)
    print(result.stdout)  # 42

# Session is automatically deleted here
```

### Sessions with Pre-loaded Files and Env Vars

Create sessions with files and environment variables pre-configured:

```python
# Upload files
config = client.files.upload(b"db_host=localhost", filename="config.txt")
data = client.files.upload(b"id,name\n1,Alice", filename="users.csv")

# Create session with files and env vars pre-loaded
with client.sessions.context(
    file_ids=[config.file_id, data.file_id],
    env_vars={"APP_ENV": "production"}
) as session:
    result = client.run(
        "import os; print(os.listdir('/workspace'))",
        session_id=session.session_id
    )
    print(result.stdout)  # ['config.txt', 'users.csv']

# Clean up files
client.files.delete(config.file_id)
client.files.delete(data.file_id)
```

### Inject Files into Existing Sessions

```python
# Create a session
session = client.sessions.create()

# Upload a file
uploaded = client.files.upload(b"data content", filename="data.txt")

# Inject file into the existing session
client.sessions.inject_files(session.session_id, [uploaded.file_id])

# Now the file is available in the session's /workspace
result = client.run(
    "print(open('/workspace/data.txt').read())",
    session_id=session.session_id
)

# Clean up
client.sessions.delete(session.session_id)
client.files.delete(uploaded.file_id)
```

### File Operations

```python
# Upload a file from path
uploaded = client.files.upload("/path/to/data.csv")
print(f"Uploaded: {uploaded.file_id}")

# Upload from bytes
uploaded = client.files.upload(
    b"name,value\nfoo,1",
    filename="data.csv",
    content_type="text/csv"
)

# List files with pagination
files = client.files.list(limit=20, offset=0)
print(f"Total: {files.total}")

# Iterate all files (auto-pagination)
for file in client.files.list_all():
    print(f"  - {file.filename} ({file.size_bytes} bytes)")

# Download a file
content = client.files.download(file_id)
# Or download to disk
client.files.download_to(file_id, "/path/to/save.csv")

# Delete a file
client.files.delete(file_id)
```

### Async Client

```python
import asyncio
from agentsandbox import AsyncAgentSandbox

async def main():
    async with AsyncAgentSandbox(api_key="your-api-key") as client:
        # Basic execution with env vars
        result = await client.run(
            "import os; print(os.environ['MSG'])",
            env_vars={"MSG": "Hello async!"}
        )
        print(result.stdout)

        # Async session with pre-loaded files
        uploaded = await client.files.upload(b"async data", filename="data.txt")
        async with client.sessions.context(file_ids=[uploaded.file_id]) as session:
            result = await client.run(
                "print(open('/workspace/data.txt').read())",
                session_id=session.session_id
            )
        await client.files.delete(uploaded.file_id)

        # Async file iteration
        async for file in client.files.list_all():
            print(file.filename)

asyncio.run(main())
```

### Error Handling

```python
from agentsandbox import (
    AgentSandbox,
    AgentSandboxError,
    AuthenticationError,
    NotFoundError,
    ValidationError,
)

client = AgentSandbox(api_key="your-api-key")

try:
    result = client.run("print('hello')")
except AuthenticationError:
    print("Invalid API key")
except NotFoundError:
    print("Resource not found")
except ValidationError as e:
    print(f"Invalid request: {e.message}")
except AgentSandboxError as e:
    print(f"API error [{e.status_code}]: {e.message}")
```

### Execution Results

```python
result = client.run("print('hello')")

print(result.session_id)   # Session ID (auto-generated if not provided)
print(result.stdout)       # Standard output
print(result.stderr)       # Standard error
print(result.return_code)  # Return code (0 = success)
print(result.exit_code)    # Alias for return_code
print(result.success)      # True if return_code == 0
print(result.files)        # List of files created in /workspace
```

## Configuration

```python
from agentsandbox import AgentSandbox

client = AgentSandbox(
    api_key="your-api-key",           # Or set AGENTSANDBOX_API_KEY env var
    base_url="https://custom.api.com", # Or set AGENTSANDBOX_BASE_URL env var
    timeout=120.0,                     # Request timeout in seconds
)
```

## API Reference

### Clients

- `AgentSandbox` - Synchronous client
- `AsyncAgentSandbox` - Asynchronous client

### Resources

- `client.run(code, language, session_id, env_vars, file_ids)` - Execute code (convenience method)
- `client.execute.create(...)` - Execute code (full method)
- `client.sessions.create(env_vars, file_ids)` - Create a session
- `client.sessions.list()` - List sessions
- `client.sessions.get(id)` - Get session details
- `client.sessions.delete(id)` - Delete a session
- `client.sessions.inject_files(id, file_ids)` - Inject files into session
- `client.sessions.context(env_vars, file_ids)` - Context manager for session
- `client.files.upload(file, filename, content_type)` - Upload a file
- `client.files.list(limit, offset)` - List files (paginated)
- `client.files.list_all()` - Iterate all files
- `client.files.download(id)` - Download file content
- `client.files.download_to(id, path)` - Download to disk
- `client.files.delete(id)` - Delete a file
- `client.executions.get(id)` - Get execution log

### Types

- `Language` - Enum: `PYTHON`, `BASH`
- `ExecuteResponse` - Execution result
- `SessionInfo` - Session details
- `FileInfo` - File metadata
- `ExecutionLog` - Detailed execution log

### Exceptions

- `AgentSandboxError` - Base exception
- `AuthenticationError` - Invalid API key (401)
- `ForbiddenError` - Access denied (403)
- `NotFoundError` - Resource not found (404)
- `ValidationError` - Invalid request (422)
- `RateLimitError` - Rate limit exceeded (429)
- `ServerError` - Server error (500)
- `ServiceUnavailableError` - Service unavailable (503)

## License

MIT
