sandboxer-js
v0.1.3
Published
AI-ready SDK for sand-boxer - secure code execution with agentic tool support
Maintainers
Readme
sandboxer-js
AI-ready SDK for sand-boxer — secure, isolated sandbox execution with native agentic tool support.
Features
- 🤖 AI-Agent First: Built-in tool definitions for LLM function calling (OpenAI, Anthropic, etc.)
- 🚦 Blocking Detection: Auto-detects CLI approval prompts and suggests responses
- 🧪 Code Interpreter: Run Python, JavaScript, and TypeScript inline
- 🔒 Secure by Default: Path validation, timeout management, retry logic
- ⚡ Native Fetch: Zero external HTTP dependencies
- 🎯 TypeScript Native: Full type safety with comprehensive type definitions
- 🔄 Auto-Retry: Intelligent retry logic with exponential backoff
- ⏱️ Smart Timeouts: Auto-cutoff for stuck processes with configurable wait times
- 🌐 WebSocket Terminal: Interactive terminal sessions with connection lifecycle management
- 📦 Tree-Shakeable: ESM + CJS dual exports
Installation
npm install sandboxer-jsQuick Start
import { SandboxClient } from 'sandboxer-js';
const client = new SandboxClient({
baseUrl: 'http://localhost:8000',
apiKey: process.env.SANDBOX_API_KEY,
});
const sandbox = await client.sandboxes.create({ size: 'small', ttl: 30, ttl_unit: 'minutes' });
await client.files.write(sandbox.sandbox_id, 'script.py', 'print("Hello!")');
const result = await client.sandboxes.exec(sandbox.sandbox_id, { cmd: 'python3 script.py', timeout: 10 });
console.log(result.output); // "Hello!"
await client.sandboxes.delete(sandbox.sandbox_id);AI Agent Usage
The SDK ships ready-to-use tool definitions for LLM function calling:
import { SandboxClient, AgentToolExecutor, AGENT_TOOLS } from 'sandboxer-js';
const client = new SandboxClient({ baseUrl: 'http://localhost:8000' });
const executor = new AgentToolExecutor(client);
// Pass to your LLM (OpenAI, Anthropic, etc.)
const tools = AGENT_TOOLS; // 11 tools
// Execute when LLM calls a tool
const result = await executor.execute('sandbox_exec', {
sandbox_id: 'sbx_123',
command: 'python train.py',
timeout: 300,
});
console.log(result.output);
console.log(result.execution_time_ms);
console.log(result.suggestion); // AI-friendly error messagesAvailable Agent Tools
| Tool | Description |
|------|-------------|
| sandbox_create | Create isolated environment |
| sandbox_exec | Execute commands with smart timeout handling |
| sandbox_write_file | Write files to workspace |
| sandbox_read_file | Read files from workspace |
| sandbox_list | List all sandboxes |
| sandbox_get | Get sandbox details |
| sandbox_delete | Clean up sandbox |
| sandbox_logs | Get container logs |
| sandbox_snapshot_create | Save workspace state |
| sandbox_snapshot_restore | Restore workspace state |
| sandbox_snapshot_delete | Delete a snapshot |
Blocking Detection
The SDK automatically detects when a CLI command is waiting for user input (approval prompts, confirmations, etc.) and surfaces this to the AI agent.
Pattern Detection
import { detectBlocking, addAutoApprovalFlags } from 'sandboxer-js';
// Detect blocking in output
const result = detectBlocking('Are you sure? (yes/no)');
// { detected: true, message: 'CLI is waiting for user input: "(yes/no)"', suggestedResponse: 'yes' }
// Auto-add approval flags to commands
addAutoApprovalFlags('apt-get install nginx'); // → 'apt-get -y install nginx'
addAutoApprovalFlags('rm important.txt'); // → 'rm -f important.txt'Exec with Blocking Detection
exec automatically detects blocking in output and enriches the result:
const result = await client.sandboxes.exec(sandboxId, {
cmd: 'echo "Do you want to continue? [Y/n]"',
timeout: 10,
});
if (result.blocking_detected) {
console.log(result.blocking_message); // 'CLI is waiting for user input: "[Y/n]"'
console.log(result.suggested_response); // 'yes'
}Terminal with Blocking Detection
const terminal = client.terminal.connect(sandboxId, { detectBlocking: true });
terminal.on('blocking', (info) => {
console.log(info.message); // 'CLI is waiting for user input: "(yes/no)"'
console.log(info.suggestedResponse); // 'yes'
// Communicate to user and wait for input
});
await terminal.waitForConnection();
terminal.write('apt-get install nginx\n');Supported Patterns
[Y/n]/[y/N]— yes/no prompts with default(yes/no)/(y/n)— explicit yes/no promptsAre you sure?/Confirm/Continue?Do you want to continue/proceed?Type "yes" to confirmPress Y to continueProceed with installation/deletion/removal?
Auto-Approval Flags
Use these flags to avoid blocking entirely:
import { suggestAutoApprovalCommand } from 'sandboxer-js';
suggestAutoApprovalCommand('apt-get install nginx'); // 'apt-get -y install nginx'
suggestAutoApprovalCommand('npm install express'); // 'npm -y install express'
suggestAutoApprovalCommand('docker rm container'); // 'docker -f rm container'Supported commands: apt-get, apt, yum, dnf, npm, yarn, pip, pip3, cargo, gem, docker, rm, git
Code Interpreter
Run code inline without writing files manually:
const interpreter = client.interpreter(sandboxId);
// Python
const py = await interpreter.python('print(1 + 2)');
console.log(py.output); // '3'
console.log(py.execution_time_ms);
// JavaScript
const js = await interpreter.javascript('console.log(new Date().toISOString())');
// TypeScript (uses tsx)
const ts = await interpreter.typescript(`
const greet = (name: string): string => \`Hello, \${name}!\`;
console.log(greet('World'));
`);
// Generic
const result = await interpreter.interpret({
language: 'python',
code: 'import sys; print(sys.version)',
timeout: 30,
});Blocking Mechanism
The interpreter supports a blocking mechanism for human-in-the-loop workflows:
const result = await interpreter.interpret({
language: 'python',
code: 'delete_all_files()',
blocking: {
enabled: true,
message: 'About to delete all files. Confirm?',
context: { action: 'delete', count: 100 },
},
});
if (result.blocked) {
// Surface result.blocking_message to user and wait for approval
}API Reference
Client Configuration
const client = new SandboxClient({
baseUrl: 'http://localhost:8000',
apiKey: 'your-api-key', // optional
timeout: 30000, // HTTP timeout (ms), default 30s
retries: 3, // Retry attempts, default 3
defaultWaitTimeout: 300000, // Default exec timeout for AI agents (ms), default 300s
});Sandboxes
// Create
const sandbox = await client.sandboxes.create({
size: 'small' | 'medium' | 'large',
network_access: true,
ttl: 30,
ttl_unit: 'seconds' | 'minutes' | 'hours',
storage_mounts: [{
type: 's3',
target_path: '/workspace/data',
access_mode: 'readonly',
s3_bucket: 'my-bucket',
credential_ref: 'vault://...',
}],
});
// List / Get / Delete
await client.sandboxes.list();
await client.sandboxes.get(sandboxId);
await client.sandboxes.delete(sandboxId);
// Execute
const result = await client.sandboxes.exec(sandboxId, {
cmd: 'python3 script.py',
timeout: 60, // seconds
workdir: '/workspace',
});
// result: { exit_code, output, blocking_detected?, blocking_message?, suggested_response? }
// AI-optimized execution with auto-cutoff and retry
const agenticResult = await client.sandboxes.agenticExec(sandboxId, 'npm test', {
timeout: 300,
maxRetries: 2,
autoCutoff: true,
});
// agenticResult: { ...ExecResult, execution_time_ms, retry_count, auto_terminated?, suggestion? }
// Logs & resource monitoring
const logs = await client.sandboxes.logs(sandboxId, 100);
const resourceSnapshot = await client.sandboxes.snapshotResources(sandboxId);
const resourceHistory = await client.sandboxes.resourceLogs(sandboxId, 60);
// Available sizes
const sizes = await client.sandboxes.sizes();
// Network
await client.sandboxes.toggleNetwork(sandboxId, { enabled: false });
// Lifecycle
await client.sandboxes.refresh(sandboxId);
await client.sandboxes.hotReload(sandboxId);
await client.sandboxes.factoryReset(sandboxId, true); // refreshImage = trueFiles
await client.files.write(sandboxId, 'script.py', 'print("hello")');
const content = await client.files.read(sandboxId, 'output.txt');
// Low-level
await client.files.upload(sandboxId, Buffer.from('data'), 'file.bin');
const data = await client.files.download(sandboxId, 'result.json');Snapshots
const snapshot = await client.snapshots.create(sandboxId, { label: 'baseline', secure: true });
const snapshots = await client.snapshots.list(sandboxId);
await client.snapshots.restore(sandboxId, snapshotId, { clear_workspace: true });
await client.snapshots.delete(sandboxId, snapshotId);Terminal (WebSocket)
const terminal = client.terminal.connect(sandboxId, {
detectBlocking: true, // optional, default true
});
terminal.on('data', (data) => process.stdout.write(data));
terminal.on('blocking', (info) => console.log(info.message, info.suggestedResponse));
terminal.on('error', (err) => console.error(err));
terminal.on('close', () => console.log('closed'));
// Always wait for connection before writing
await terminal.waitForConnection();
terminal.write('ls -la\n');
terminal.resize(24, 80);
terminal.close();Images
await client.images.registryStatus();
await client.images.build({
image: 'sandbox-custom:latest',
profile: 'auto' | 'light' | 'standard' | 'heavy',
dockerfile: 'Dockerfile.sandbox',
ttl_seconds: 21600,
});
await client.images.refresh({ image: 'sandbox:latest', profile: 'standard' });Webhooks
const sub = await client.webhooks.createSubscription({
target_url: 'https://example.com/webhook',
events: ['sandbox.lifecycle.*'],
secret: 'webhook-secret',
enabled: true,
});
const subs = await client.webhooks.listSubscriptions();
await client.webhooks.deleteSubscription(subId);
await client.webhooks.emitTest();Error Handling
import {
SandboxError,
SandboxTimeoutError,
SandboxNotFoundError,
SandboxAuthError,
SandboxValidationError,
AgenticExecutionError,
} from 'sandboxer-js';
try {
await client.sandboxes.exec(sandboxId, { cmd: 'long-task', timeout: 5 });
} catch (error) {
if (error instanceof SandboxTimeoutError) {
console.log(`Timed out after ${error.timeoutMs}ms`);
} else if (error instanceof AgenticExecutionError) {
console.log(error.suggestion);
console.log(`Retries: ${error.retryCount}, Time: ${error.executionTimeMs}ms`);
} else if (error instanceof SandboxNotFoundError) {
console.log('Sandbox does not exist');
} else if (error instanceof SandboxError) {
console.log(`${error.message} (status: ${error.status})`);
}
}Security
- ✅ Native fetch (no axios supply chain risk)
- ✅ Path traversal protection on file operations
- ✅ Timeout enforcement on all requests
- ✅ API key authentication support
- ✅ Minimal dependencies (only
wsfor WebSocket)
Requirements
- Node.js >= 18.0.0
License
MIT
