Skip to main content

Python SDK for VoidRun AI Sandbox

Project description

VoidRun Python SDK

A powerful Python SDK for interacting with VoidRun AI Sandboxes. Execute code, manage files, watch file changes, and interact with pseudo-terminals in isolated environments.

PyPI version License: MIT

Features

  • 🏗️ Sandbox Management - Create, list, start, stop, pause, resume, and remove sandboxes
  • 🚀 Code Execution - Execute commands with real-time streaming output capture
  • 📁 File Operations - Create, read, delete, compress, and extract files
  • 👀 File Watching - Monitor file changes in real-time via WebSocket
  • 💻 Pseudo-Terminal (PTY) - Interactive terminal sessions (ephemeral & persistent)
  • 🧠 Code Interpreter - Easy multi-language code execution (Python, JavaScript, Bash)
  • Background Commands - Run, list, kill, and attach to background processes
  • 🎯 Sync & Async - Both synchronous and asynchronous APIs

Installation

With pip:

pip install voidrun

With Poetry:

poetry add voidrun

Quick Start

Basic Usage (Sync)

from voidrun import VoidRun

# Initialize the SDK with your credentials
vr = VoidRun(api_key="your-api-key-here")

# Create a sandbox
sandbox = vr.sandboxes.create(mem=1024, cpu=1).data

# Execute a command
result = sandbox.exec('echo "Hello from VoidRun"')
print(result.data.data.stdout)

# Clean up
sandbox.delete()

Basic Usage (Async)

import asyncio
from voidrun import AsyncVoidRun

async def main():
    vr = AsyncVoidRun(api_key="your-api-key-here")
    
    sandbox = await vr.sandboxes.create(mem=1024, cpu=1)
    
    result = sandbox.exec('echo "Hello from VoidRun"')
    print(result.data.data.stdout)
    
    await sandbox.delete_async()
    await vr.aclose()

asyncio.run(main())

Core Concepts

Sandboxes

An isolated environment where you can execute code, manage files, and run terminals.

# Create a sandbox with options (sync)
sandbox = vr.sandboxes.create(
    name="my-sandbox",       # Optional: Sandbox name
    mem=1024,               # Memory in MB (optional, has defaults)
    cpu=1,                  # CPU cores (optional, has defaults)
    image="template-id",  # Optional: Image ID
    env_vars={              # Optional: Environment variables
        "DEBUG": "true",
        "LOG_LEVEL": "info"
    }
).data

# Using context manager (auto-cleanup)
with vr.sandboxes.create(name="my-sandbox").data as sandbox:
    # Work with sandbox
    pass
# Sandbox automatically deleted

# List all sandboxes
resp = vr.sandboxes.list()
sandboxes = resp.data
print(f"Total sandboxes: {len(sandboxes)}")

# Get a specific sandbox
existing = vr.sandboxes.get(sandbox_id).data

# Sandbox lifecycle management
sandbox.start()    # Start a stopped sandbox
sandbox.stop()     # Stop a running sandbox
sandbox.pause()    # Pause a running sandbox
sandbox.resume()   # Resume a paused sandbox

# Remove a sandbox
sandbox.delete()

Code Execution

Execute commands and capture output, errors, and exit codes.

Synchronous Execution

result = sandbox.exec("ls -la /home")

print(result.data.data.stdout)   # standard output
print(result.data.data.stderr)   # standard error
print(result.data.data.exit_code)  # exit code

Streaming Execution (SSE)

For real-time output, provide streaming handlers:

def on_stdout(data):
    print("stdout:", data)

def on_stderr(data):
    print("stderr:", data)

def on_exit(result):
    print("exit:", result)

def on_error(error):
    print("error:", error)

sandbox.exec_stream(
    "seq 1 10 | while read i; do echo \"Line $i\"; sleep 1; done",
    on_stdout=on_stdout,
    on_stderr=on_stderr,
    on_exit=on_exit,
    on_error=on_error
)

Execution with Options

result = sandbox.exec(
    "echo $MY_VAR && pwd",
    cwd="/tmp",                    # Working directory
    env={"MY_VAR": "test_value"},  # Environment variables
    timeout=30                     # Timeout in seconds
)

Code Interpreter

Execute code in multiple programming languages with a simple, intuitive API.

# Execute Python code
result = sandbox.interpreter.run('print(2 + 2)', language="python")
print(result.data.stdout.strip())  # "4"
print(result.data.success)         # True

# Execute JavaScript code
js_result = sandbox.interpreter.run('console.log("Hello")', language="javascript")

# Check execution result
print(result.data.exit_code)   # 0 for success
print(result.data.results)     # Parsed results
print(result.data.logs)        # {"stdout": [...], "stderr": [...]}

Supported Languages: python, javascript, typescript, node, bash, sh

Background Commands

Run long-running processes in the background and manage them.

# Start a background process
run_result = sandbox.commands.run(
    "sleep 100 && echo 'Done'",  # command
    {"DEBUG": "true"},            # env (optional)
    "/tmp",                      # cwd (optional)
    0                            # timeout (0 = no timeout)
)
print(run_result.data.pid)  # Process ID

# List all running processes
list_result = sandbox.commands.list()
print(list_result.data)  # Array of ProcessInfo

# Attach to a process and stream output
def on_stdout(data):
    print(data)

def on_stderr(data):
    print(data)

def on_exit(result):
    print("Process exited:", result)

sandbox.commands.connect(
    run_result.data.pid,
    on_stdout=on_stdout,
    on_stderr=on_stderr,
    on_exit=on_exit
)

# Wait for a process to complete
wait_result = sandbox.commands.wait(run_result.data.pid)
print(wait_result.data.exit_code)

# Kill a running process
kill_result = sandbox.commands.kill(run_result.data.pid)
print(kill_result.data.success)

File Operations

Create, read, update, and manage files in the sandbox.

# Create a file
sandbox.fs.create_file("/tmp/hello.txt")

# Upload content to file
sandbox.fs.upload_file("/tmp/hello.txt", "Hello, World!")

# Upload from local file path
sandbox.fs.upload_file_from_path("/tmp/remote.txt", "/local/file.txt")

# Read a file
data = sandbox.fs.download_file("/tmp/hello.txt")
content = data.decode("utf-8")

# Delete a file
sandbox.fs.delete_file("/tmp/hello.txt")

# List directory
result = sandbox.fs.list_files("/tmp")
files = result.data
print([f.name for f in files])

# Get file stats
stats = sandbox.fs.stat_file("/tmp/hello.txt")

# Create directory
sandbox.fs.create_directory("/tmp/mydir")

# Move file
sandbox.fs.move_file("/tmp/file.txt", "/tmp/newfile.txt")

# Copy file
sandbox.fs.copy_file("/tmp/file.txt", "/tmp/copy.txt")

# Change permissions
sandbox.fs.change_permissions("/tmp/file.txt", "755")

# Head/Tail - read first or last lines
head = sandbox.fs.head_tail("/tmp/file.txt", head=True, lines=10)
tail = sandbox.fs.head_tail("/tmp/file.txt", head=False, lines=10)

# Search files by pattern
search = sandbox.fs.search_files("/tmp", "*.txt")

# Get folder size
size = sandbox.fs.disk_usage("/tmp")

# Compress files
archive = sandbox.fs.compress_file("/tmp", "tar.gz")
print(archive.data)

# Extract archive
sandbox.fs.extract_archive("/tmp/archive.tar.gz", "/tmp/extracted")

File Watching (Async)

Monitor file changes in real-time.

import asyncio
from voidrun import AsyncVoidRun

async def watch_tmp():
    vr = AsyncVoidRun()
    sandbox = await vr.sandboxes.create()
    
    watcher = await sandbox.fs.watch(
        "/app",
        recursive=True,
        on_event=lambda evt: print(f"File changed: {evt.get('path')} - {evt.get('type')}"),
        on_error=lambda err: print("Watch error:", err),
    )

    # Keep watching for a while
    await asyncio.sleep(60)
    
    # Stop watching
    watcher.close()
    
    await sandbox.delete_async()
    await vr.aclose()

asyncio.run(watch_tmp())

Pseudo-Terminal (PTY)

Interactive terminal sessions with two modes:

Ephemeral Sessions (Temporary)

import asyncio
from voidrun import AsyncVoidRun

async def ephemeral_pty():
    vr = AsyncVoidRun()
    sandbox = await vr.sandboxes.create()
    
    # Connect to ephemeral PTY (no session management - temporary shell)
    pty = await sandbox.pty.connect(
        on_data=lambda data: print(data, end=""),
        on_error=lambda err: print("PTY error:", err),
    )

    # Send commands
    pty.send_input('echo "Hello"\n')
    pty.send_input("pwd\n")

    await asyncio.sleep(2)
    
    # Close connection
    await pty.close()
    
    await sandbox.delete_async()
    await vr.aclose()

asyncio.run(ephemeral_pty())

Persistent Sessions

import asyncio
from voidrun import AsyncVoidRun

async def persistent_pty():
    vr = AsyncVoidRun()
    sandbox = await vr.sandboxes.create()
    
    # Create a persistent session
    response = sandbox.pty.create_session()
    session_id = response.data.data.session_id

    # Connect to the session
    pty = await sandbox.pty.connect(
        session_id=session_id,
        on_data=lambda data: print(data, end=""),
    )

    # Send commands
    pty.send_input('echo "Hello"\n')

    # Close connection (session persists)
    await pty.close()

    # Reconnect later - session and output persist
    reconnected = await sandbox.pty.connect(
        session_id=session_id,
        on_data=lambda data: print(data, end=""),  # Includes buffered output
    )
    
    await reconnected.close()
    
    # Delete the session when done
    sandbox.pty.delete_session(session_id)
    
    await sandbox.delete_async()
    await vr.aclose()

asyncio.run(persistent_pty())

Interactive Commands

Run commands with automatic prompt detection:

pty = await sandbox.pty.connect(session_id=session_id)

output = await pty.run_command(
    "ls -la",
    timeout=5000,
    prompt="# "  # Prompt to detect (default: "# ")
)

print("Output:", output)

Resize Terminal

await pty.resize(80, 24)  # columns, rows

Session Management

# List all sessions
sessions = sandbox.pty.list()

# Delete a session
sandbox.pty.delete_session(session_id)

API Reference

VoidRun Class

Main synchronous client for interacting with the API.

vr = VoidRun(api_key="...")

Options:

  • api_key: str - API key (defaults to os.environ.get("VR_API_KEY"))

Properties:

  • sandboxes: SandboxesFacade - Sandbox management interface

Methods:

  • sandboxes.create(...) - Create a new sandbox
    • name?: str - Sandbox name
    • cpu?: int - CPU cores
    • mem?: int - Memory in MB
    • image?: str - Image ID
    • env_vars?: dict - Environment variables
  • sandboxes.list(page=1, limit=50) - List all sandboxes
  • sandboxes.get(id: str) - Get a specific sandbox
  • sandboxes.delete(id: str) - Delete a sandbox

AsyncVoidRun Class

Main asynchronous client for interacting with the API.

vr = AsyncVoidRun(api_key="...")

Options: Same as VoidRun

Methods:

  • sandboxes.create(...) - Create a new sandbox (async)
  • sandboxes.list(...) - List all sandboxes (async)
  • sandboxes.get(id) - Get a specific sandbox (async)
  • sandboxes.delete(id) - Delete a sandbox (async)
  • aclose() - Close the async client

Sandbox Class

Represents an isolated sandbox environment.

Properties:

  • id: str - Sandbox ID
  • name: str - Sandbox name
  • cpu: int - CPU cores
  • mem: int - Memory in MB
  • org_id: str - Organization ID
  • status: str - Sandbox status
  • env_vars: dict - Environment variables
  • fs: FS - File system interface
  • pty: PTY - PTY interface
  • interpreter: Interpreter - Code interpreter
  • commands: Commands - Background commands interface

Methods:

  • exec(command: str, timeout=30, env=None, cwd=None) - Execute a command
  • exec_stream(command: str, timeout=30, env=None, cwd=None, on_stdout=None, on_stderr=None, on_exit=None, on_error=None) - Streaming execution
  • interpreter.run(code: str, language="python", timeout=60) - Execute code
  • start() - Start the sandbox
  • stop() - Stop the sandbox
  • pause() - Pause the sandbox
  • resume() - Resume the sandbox
  • delete() - Delete the sandbox
  • delete_async() - Delete the sandbox (async)

Exec Response:

{
    data: {
        stdout: str,     # standard output
        stderr: str,    # standard error
        exit_code: int  # exit code
    }
}

Code Execution Result:

{
    success: bool,
    results: Any,          # Parsed results
    stdout: str,           # Combined stdout
    stderr: str,           # Combined stderr
    error: Optional[str],  # Error message if any
    exit_code: Optional[int],  # Process exit code
    logs: {
        stdout: List[str],  # Individual stdout lines
        stderr: List[str]  # Individual stderr lines
    }
}

Commands Class

Background process management.

Methods:

  • run(command: str, env=None, cwd=None, timeout=0) - Start a background process
  • list() - List all running processes
  • kill(pid: int) - Kill a process
  • connect(pid: int, on_stdout=None, on_stderr=None, on_exit=None, on_error=None) - Attach to process output stream
  • wait(pid: int) - Wait for process to complete

FS Class

Manage files and directories.

Methods:

  • create_file(path: str) - Create a file
  • upload_file(path: str, content: str) - Upload file content
  • upload_file_from_path(path: str, file_path: str) - Upload from local path
  • download_file(path: str) - Download file as bytes
  • delete_file(path: str) - Delete a file/directory
  • list_files(path: str) - List directory contents
  • stat_file(path: str) - Get file metadata
  • create_directory(path: str) - Create a directory
  • compress_file(path: str, format="tar.gz") - Create archive
  • extract_archive(archive: str, dest=None) - Extract archive
  • move_file(source: str, destination: str) - Move/rename file
  • copy_file(source: str, destination: str) - Copy file
  • change_permissions(path: str, mode: str) - Change file permissions
  • head_tail(path: str, lines=10, head=True) - Read file head/tail
  • search_files(path: str, pattern: str) - Search files by pattern
  • disk_usage(path: str) - Get folder size
  • watch(path: str, recursive=True, ignore_hidden=True, on_event=None, on_error=None) - Watch for file changes (async)

PTY Class

Pseudo-terminal operations.

Methods:

  • list() - List active sessions
  • create_session(cols=80, rows=24) - Create a persistent session
  • connect(session_id=None, on_data=None, on_close=None, on_error=None) - Connect to PTY
  • delete_session(session_id: str) - Delete a session

PtySession Methods

  • send_input(data: str) - Send data to terminal
  • run_command(cmd: str, timeout=30000, prompt="# ") - Execute with prompt detection
  • resize(cols: int, rows: int) - Resize terminal
  • close() - Close connection

Examples

Execute Python Script

from voidrun import VoidRun

vr = VoidRun()
sandbox = vr.sandboxes.create(mem=1024, cpu=1).data

# Create Python script
sandbox.fs.create_file("/tmp/script.py")
sandbox.fs.upload_file(
    "/tmp/script.py",
    """
import sys
print("Python version:", sys.version)
print("Hello from Python!")
"""
)

result = sandbox.exec("python3 /tmp/script.py")
print(result.data.data.stdout)

sandbox.delete()

Code Interpreter Workflow

sandbox = vr.sandboxes.create(name="interpreter-demo").data

# Python data analysis
result = sandbox.interpreter.run("""
import json
data = [1, 2, 3, 4, 5]
result = {
    "sum": sum(data),
    "avg": sum(data) / len(data),
    "max": max(data)
}
print(json.dumps(result))
""", language="python")

print(result.data.results)  # Parsed JSON output

# JavaScript
js_result = sandbox.interpreter.run("""
const fib = (n) => n <= 1 ? n : fib(n-1) + fib(n-2);
console.log(fib(10));
""", language="javascript")

sandbox.delete()

Background Process Management

sandbox = vr.sandboxes.create().data

# Start a long-running process
run_result = sandbox.commands.run("tail -f /var/log/syslog")
pid = run_result.data.pid

# Attach to stream output
sandbox.commands.connect(
    pid,
    on_stdout=lambda data: print(data),
    on_exit=lambda result: print("Exited:", result)
)

# Later, kill the process
sandbox.commands.kill(pid)

sandbox.delete()

Monitor Code Changes

import asyncio
from voidrun import AsyncVoidRun

async def watch_changes():
    vr = AsyncVoidRun()
    sandbox = await vr.sandboxes.create(mem=1024, cpu=1)
    
    # Watch for file changes
    watcher = await sandbox.fs.watch(
        "/app/src",
        recursive=True,
        on_event=lambda event: print(f"File {event.get('type')}: {event.get('path')}"),
    )
    
    # Keep watching for a while
    await asyncio.sleep(60)
    
    watcher.close()
    await sandbox.delete_async()
    await vr.aclose()

asyncio.run(watch_changes())

Build & Test Workflow

sandbox = vr.sandboxes.create(mem=2048, cpu=2).data

# Upload source code
sandbox.fs.create_file("/app/main.js")
sandbox.fs.upload_file("/app/main.js", "console.log('Hello World');")

# Install dependencies
result = sandbox.exec("npm install")
if result.data.data.exit_code != 0:
    raise Error("Install failed")

# Run tests
result = sandbox.exec("npm test")
print("Test output:", result.data.data.stdout)

# Build
result = sandbox.exec("npm run build")
print("Build output:", result.data.data.stdout)

sandbox.delete()

Configuration

The SDK can be configured by passing options to the constructor or using environment variables:

vr = VoidRun(
    api_key="your-api-key",              # Required: Your API key
)

Environment variables:

export VR_API_KEY="your-api-key"

Error Handling

from voidrun import VoidRun

try:
    sandbox = vr.sandboxes.create(mem=256, cpu=0.5)
except Exception as e:
    print("Error:", str(e))

Common errors:

  • Validation Error - Invalid sandbox parameters
  • Authentication Error - Invalid or missing API key
  • Not Found - Sandbox or session doesn't exist
  • Timeout - Operation took too long

Testing

Run the examples:

# Set your API key
export VR_API_KEY="your-api-key"

# Run sync example
python -m examples.sync_usage

# Run async example
python -m examples.async_usage

# Run other examples
python -m examples.test_sandbox_exec
python -m examples.test_sandbox_fs
python -m examples.test_sandbox_lifecycle
python -m examples.test_pty
python -m examples.test_background_exec
python -m examples.code_interpreter_example

Building from Source

# Install dependencies
pip install -e .

# Or with poetry
poetry install

Publishing

# Build and publish to PyPI
poetry build
poetry publish

Troubleshooting

"API key is required (pass it or set VR_API_KEY/API_KEY)"

Pass your API key in the constructor:

vr = VoidRun(api_key="your-api-key")

Or set environment variable:

export VR_API_KEY="your-api-key"

"Sandbox creation failed"

Ensure your sandbox parameters are valid:

  • mem: minimum 1024 MB
  • cpu: minimum 1 core
sandbox = vr.sandboxes.create(
    mem=1024,  # At least 1GB
    cpu=1,     # At least 1 core
)

"PTY Connection Timeout"

Increase timeout for slow systems:

pty = await sandbox.pty.connect(
    session_id=session_id,
    on_data=lambda data: print(data),
)

# For run_command
output = await pty.run_command("slow-command", timeout=30000)  # 30 seconds

"File Not Found"

Check the file path:

# List files to verify path
files = sandbox.fs.list_files("/app")
print([f.name for f in files.data])

# Then access specific file
content = sandbox.fs.download_file("/app/file.txt")

API Documentation

Full API documentation is available at the VoidRun docs site.

Contributing

Contributions are welcome! Please check the main repository for guidelines.

License

MIT License - See LICENSE file for details

Support


Made with ❤️ by VoidRun

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

voidrun-0.0.6.tar.gz (58.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

voidrun-0.0.6-py3-none-any.whl (146.7 kB view details)

Uploaded Python 3

File details

Details for the file voidrun-0.0.6.tar.gz.

File metadata

  • Download URL: voidrun-0.0.6.tar.gz
  • Upload date:
  • Size: 58.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for voidrun-0.0.6.tar.gz
Algorithm Hash digest
SHA256 b3f81215e4f25f68a697f36d0cd4f68d9f1ae93febdb4c30c0b5bec95eb2f33e
MD5 6c5a11627e94f63fe5c78d259192541d
BLAKE2b-256 a12cc3b2ffdfd985b9e68518a7d0e3f5dc4d287e17b631dd95e8f8acfbc2fc88

See more details on using hashes here.

File details

Details for the file voidrun-0.0.6-py3-none-any.whl.

File metadata

  • Download URL: voidrun-0.0.6-py3-none-any.whl
  • Upload date:
  • Size: 146.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for voidrun-0.0.6-py3-none-any.whl
Algorithm Hash digest
SHA256 56d0fba6d1feea12624e3cdaa26a704bb99bcd6f5dd67131da861a9040eef2b7
MD5 077e8e4226a811bca10b02ef7e8be804
BLAKE2b-256 733e558df907d09918fd7d628120472e7733f952e0eb19104cbbbd5ca81d67ec

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page