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.
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 toos.environ.get("VR_API_KEY"))
Properties:
sandboxes: SandboxesFacade- Sandbox management interface
Methods:
sandboxes.create(...)- Create a new sandboxname?: str- Sandbox namecpu?: int- CPU coresmem?: int- Memory in MBimage?: str- Image IDenv_vars?: dict- Environment variables
sandboxes.list(page=1, limit=50)- List all sandboxessandboxes.get(id: str)- Get a specific sandboxsandboxes.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 IDname: str- Sandbox namecpu: int- CPU coresmem: int- Memory in MBorg_id: str- Organization IDstatus: str- Sandbox statusenv_vars: dict- Environment variablesfs: FS- File system interfacepty: PTY- PTY interfaceinterpreter: Interpreter- Code interpretercommands: Commands- Background commands interface
Methods:
exec(command: str, timeout=30, env=None, cwd=None)- Execute a commandexec_stream(command: str, timeout=30, env=None, cwd=None, on_stdout=None, on_stderr=None, on_exit=None, on_error=None)- Streaming executioninterpreter.run(code: str, language="python", timeout=60)- Execute codestart()- Start the sandboxstop()- Stop the sandboxpause()- Pause the sandboxresume()- Resume the sandboxdelete()- Delete the sandboxdelete_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 processlist()- List all running processeskill(pid: int)- Kill a processconnect(pid: int, on_stdout=None, on_stderr=None, on_exit=None, on_error=None)- Attach to process output streamwait(pid: int)- Wait for process to complete
FS Class
Manage files and directories.
Methods:
create_file(path: str)- Create a fileupload_file(path: str, content: str)- Upload file contentupload_file_from_path(path: str, file_path: str)- Upload from local pathdownload_file(path: str)- Download file as bytesdelete_file(path: str)- Delete a file/directorylist_files(path: str)- List directory contentsstat_file(path: str)- Get file metadatacreate_directory(path: str)- Create a directorycompress_file(path: str, format="tar.gz")- Create archiveextract_archive(archive: str, dest=None)- Extract archivemove_file(source: str, destination: str)- Move/rename filecopy_file(source: str, destination: str)- Copy filechange_permissions(path: str, mode: str)- Change file permissionshead_tail(path: str, lines=10, head=True)- Read file head/tailsearch_files(path: str, pattern: str)- Search files by patterndisk_usage(path: str)- Get folder sizewatch(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 sessionscreate_session(cols=80, rows=24)- Create a persistent sessionconnect(session_id=None, on_data=None, on_close=None, on_error=None)- Connect to PTYdelete_session(session_id: str)- Delete a session
PtySession Methods
send_input(data: str)- Send data to terminalrun_command(cmd: str, timeout=30000, prompt="# ")- Execute with prompt detectionresize(cols: int, rows: int)- Resize terminalclose()- 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 MBcpu: 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
- 📧 Email: support@void-run.com
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b3f81215e4f25f68a697f36d0cd4f68d9f1ae93febdb4c30c0b5bec95eb2f33e
|
|
| MD5 |
6c5a11627e94f63fe5c78d259192541d
|
|
| BLAKE2b-256 |
a12cc3b2ffdfd985b9e68518a7d0e3f5dc4d287e17b631dd95e8f8acfbc2fc88
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
56d0fba6d1feea12624e3cdaa26a704bb99bcd6f5dd67131da861a9040eef2b7
|
|
| MD5 |
077e8e4226a811bca10b02ef7e8be804
|
|
| BLAKE2b-256 |
733e558df907d09918fd7d628120472e7733f952e0eb19104cbbbd5ca81d67ec
|