Metadata-Version: 2.4
Name: sandbox-agent-sdk
Version: 0.1.5
Summary: Python client SDK for Sandbox Agent — universal API for automatic coding agents in sandboxes
Project-URL: Homepage, https://github.com/kevinhill/sandbox-agent-python
Project-URL: Repository, https://github.com/kevinhill/sandbox-agent-python
Author: Kevin Hill
License: Apache-2.0
Keywords: acp,agent,ai,coding,sandbox,sdk
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: aiortc<2,>=1.9.0
Requires-Dist: httpx<1,>=0.27
Requires-Dist: pydantic<3,>=2.0
Requires-Dist: websockets<14,>=12.0
Description-Content-Type: text/markdown

# sandboxagent

Python client SDK for [Sandbox Agent](https://github.com/rivet-dev/sandbox-agent) — the universal API for automatic coding agents in sandboxes.

## Installation

```bash
pip install sandbox-agent-sdk
```

## Quick Start

```python
import asyncio
from sandboxagent import SandboxAgent

async def main():
    # Connect to a running sandbox-agent server
    agent = await SandboxAgent.connect("http://localhost:2468")
    
    # Check health
    health = await agent.health()
    print(f"Health: {health}")
    
    # Filesystem operations
    await agent.write_file("/tmp/hello.txt", "Hello from Python!")
    content = await agent.read_file("/tmp/hello.txt")
    print(f"File content: {content}")
    
    # Run a process
    result = await agent.run_process({
        "command": "/bin/echo",
        "args": ["hello", "world"],
        "cwd": "/tmp"
    })
    print(f"stdout: {result['stdout']}")
    
    # List available agents
    agents = await agent.list_agents()
    print(f"Available agents: {[a['id'] for a in agents]}")
    
    # Get inspector URL
    print(f"Inspector: {agent.inspector_url}")
    
    await agent.dispose()

asyncio.run(main())
```

## Starting a Local Server

```python
from sandboxagent import SandboxAgent

# Download and start a local sandbox-agent binary
agent = await SandboxAgent.start()
print(f"Server running at {agent._base_url}")
print(f"Inspector: {agent.inspector_url}")

# ... use the agent ...

await agent.dispose()
```

## ACP Sessions

```python
# Create an ACP session with an agent
session = await agent.create_session(agent="claude")

# Send a prompt
response = await session.prompt("Write a Python function to calculate factorial")
print(response)

# Configure session settings
await session.set_model("claude-sonnet-4-20250514")
await session.set_mode("code")

# Destroy the session
await agent.destroy_session(session.id)
```

## Workspace Configuration

Inject config files and environment variables into sandboxes during startup:

```python
from sandboxagent import SandboxAgent
from sandboxagent.workspace_config import WorkspaceConfig

# Generate config content
auth_content = WorkspaceConfig.auth_json({
    "openai_api_key": "sk-...",
    "anthropic_api_key": "sk-ant-..."
})

# Start sandbox with workspace files
agent = await SandboxAgent.start(
    workspace_files={
        "auth.json": auth_content,
        ".env": "API_KEY=secret\nDEBUG=1"
    },
    workspace_env={"FOO": "bar"}
)
```

## Git Repository Cloning

Clone git repositories at runtime or during sandbox startup:

### Runtime Cloning

Clone repositories into a running sandbox using secure credential handling:

```python
from sandboxagent import SandboxAgent, GitCloneError

# Clone public repository
result = await agent.clone_repo("https://github.com/owner/public-repo.git")

# Clone private repository with personal access token
result = await agent.clone_repo(
    "https://github.com/owner/private-repo.git",
    token=os.environ["GITHUB_TOKEN"],
    path="/workspace/my-project",
    branch="main",
    depth=1
)

# Handle errors
from sandboxagent import GitCloneError

try:
    await agent.clone_repo("https://github.com/owner/repo.git", token="ghp_xxx")
except GitCloneError as e:
    if e.category == "auth":
        print("Authentication failed - check your token")
    elif e.category == "not_found":
        print("Repository not found")
    elif e.category == "network":
        print("Network error - check connectivity")
```

Security features:
- Token never appears in URLs or command-line arguments (uses `GIT_ASKPASS`)
- Token is automatically redacted from error messages
- Temporary credential script is deleted immediately after cloning

### Bootstrap-time Cloning

Clone repositories during sandbox startup using workspace configuration:

```python
from sandboxagent import SandboxAgent
from sandboxagent.workspace_config import WorkspaceConfig

# Generate git clone scripts
clone_script = WorkspaceConfig.git_clone_script([
    {"url": "https://github.com/owner/repo1.git", "path": "/workspace/r1", "branch": "main"},
    {"url": "https://github.com/owner/repo2.git", "path": "/workspace/r2", "depth": 1},
], token=os.environ.get("GITHUB_TOKEN"))

# Start sandbox with clone script
agent = await SandboxAgent.start(
    workspace_files={
        "clone-repos.sh": clone_script,
    }
)

# The script runs automatically on startup
```

### Git Askpass Helper

Generate a standalone `GIT_ASKPASS` script for custom authentication flows:

```python
from sandboxagent.workspace_config import WorkspaceConfig

# Create askpass script for git operations
askpass_script = WorkspaceConfig.git_askpass_script(token="ghp_xxx")
await agent.write_file("/workspace/.git-askpass", askpass_script)

# Use with any git command
result = await agent.run_process({
    "command": "git",
    "args": ["clone", "https://github.com/owner/private.git"],
    "env": {
        "GIT_ASKPASS": "/workspace/.git-askpass",
        "GIT_TOKEN": "ghp_xxx",
        "GIT_TERMINAL_PROMPT": "0"
    }
})
```

## API Coverage

### Core APIs
- **Health**: `health()`, `wait_for_health()`
- **Filesystem**: `read_file()`, `write_file()`, `list_entries()`, `stat()`, `move()`, `delete_entry()`, `mkdir_fs()`
- **Processes**: `create_process()`, `run_process()`, `list_processes()`, `get_process()`, `stop_process()`, `kill_process()`, `delete_process()`
- **Git**: `clone_repo()` — Clone repositories with secure token handling
- **Agents**: `list_agents()`, `get_agent()`, `install_agent()`
- **Config**: `get_mcp_config()`, `set_mcp_config()`, `get_skills_config()`, `set_skills_config()`, `get_process_config()`, `set_process_config()`

### Session Management
- `create_session()`, `resume_session()`, `destroy_session()`, `list_sessions()`, `get_session()`
- Session helpers: `prompt()`, `set_model()`, `set_mode()`, `set_thought_level()`, `set_config_option()`

### Process Helpers
- **Logs**: `follow_process_logs()` — SSE streaming with log subscription
- **Terminal**: `connect_process_terminal()` — WebSocket interactive terminal

### Sandbox Lifecycle
- `pause_sandbox()`, `resume_sandbox()`, `restart_sandbox()`, `destroy_sandbox()`, `kill_sandbox()`

### Workspace Configuration Helpers
- `WorkspaceConfig.auth_json()` — Generate auth.json content
- `WorkspaceConfig.git_askpass_script()` — Generate GIT_ASKPASS script
- `WorkspaceConfig.git_clone_script()` — Generate multi-repo clone script
- `WorkspaceConfig.oh_my_openagent_config()` — Generate oh-my-openagent.jsonc
- `WorkspaceConfig.opencode_config()` — Generate opencode.json

## Development

```bash
# Setup
uv sync

# Run tests
uv run pytest

# Run integration tests (requires local server)
uv run pytest -m integration

# Lint and format
uv run ruff check
uv run ruff format

# Type check
uv run mypy sandboxagent
```

## License

Apache-2.0
