El SDK es una capa fina sobre la API REST de sandboxes. Te ahorra tres cosas: construir peticiones a mano, reintentarlas cuando la plataforma está ocupada y olvidarte de borrar una sandbox cuando tu código lanza una excepción. Todo lo de aquí corresponde a la versión 0.2.0 de ambos paquetes.
Si nunca has creado una sandbox, la guía de conexión en 5 minutos te da primero un token. Qué es una sandbox y qué lleva dentro se explica en Sandboxes.
Instalar y configurar
pip install eqvps # Python 3.8+
npm i @eqvps/sdk # Node.js 18+, Deno, Bun
export EQVPS_API_KEY=... # your EQVPS account token
El mismo programa en los dos lenguajes: crear una sandbox, ejecutar código, borrarla.
from eqvps import Sandbox
with Sandbox.create(tariff="small") as sb:
r = sb.run("print(2 + 2)")
print(r.exit_code, r.stdout) # 0 4
import { Sandbox } from "@eqvps/sdk";
await Sandbox.with({ tariff: "small" }, async (sb) => {
const r = await sb.run("print(2 + 2)");
console.log(r.exit_code, r.stdout); // 0 4
});
Crear y encontrar sandboxes
Sandbox.create(...) arranca una sandbox, normalmente en alrededor de un segundo. Python recibe argumentos con nombre; TypeScript, un objeto de opciones.
| Python | TypeScript | Por defecto | Significado |
|---|---|---|---|
mode | mode | "ephemeral" | "ephemeral" (por segundo) o "persistent" (por hora iniciada, conserva su disco) |
tariff | tariff | "small" | micro, small, standard, plus, pro, max |
idle_timeout | idleTimeout | 300 | segundos sin actividad antes de borrar una sandbox efímera, hasta 3600 |
ttl | ttl | — | vida máxima en segundos: hasta 86400 en efímeras, 2592000 en persistentes |
env | env | — | variables de entorno para todos los comandos, guardadas cifradas |
api_key, base_url | apiKey, baseUrl | variables de entorno | sustituyen EQVPS_API_KEY / EQVPS_API_URL |
timeout | timeoutMs | 70 s | tiempo de espera HTTP por petición |
max_retries | maxRetries | 3 | reintentos ante 429/503 |
Sandbox.connect(id) se conecta a una sandbox existente, normalmente una persistente que creaste ayer. Sandbox.list() devuelve todas las sandboxes de la cuenta, en marcha y en pausa.
Propiedades: id (sb_ + 24 caracteres hexadecimales), mode, tariff, state (running, starting, paused, pausing, resuming, deleting, deleted), env_keys / envKeys (solo nombres; los valores nunca vuelven) e info (el objeto en bruto). refresh() los recarga.
kill() borra la sandbox y detiene la facturación. Llamarlo sobre una sandbox que ya no existe no es un error.
Ejecutar código
run(code, language="python", timeout=30) envía código por stdin a Python 3.12, Node.js 22 o bash ("python", "node", "bash"). exec(command, cwd=None, stdin=None, timeout=30) ejecuta un comando de shell: una cadena pasa por bash -lc, una lista se ejecuta como argv sin shell.
Los dos devuelven un ExecResult:
| Campo | Significado |
|---|---|
exit_code | código de salida del proceso |
stdout, stderr | salida, hasta 1 MiB por flujo |
timed_out | el comando agotó su tiempo |
truncated | la salida se recortó |
duration_ms | cuánto duró |
ok | exit_code == 0 y sin agotar el tiempo |
Una llamada síncrona dura como máximo 55 segundos. Ambos métodos aceptan también env para esa llamada; sustituye los valores fijados al crear.
Trabajos largos: tareas en segundo plano
Pasa background=True (en TypeScript { background: true }) y recibes una Task al instante. No tiene el límite de 55 segundos y puede durar hasta que termine la vida de la sandbox. Hasta 8 tareas por sandbox.
task = sb.exec("cd /root/app && python3 -m pytest -q", background=True)
result = task.wait(on_output=lambda out, err: print(out, end=""))
print(result.state, result.exit_code) # done 0
const task = await sb.exec("cd /root/app && npm test", { background: true });
const result = await task.wait({ onOutput: (out) => process.stdout.write(out) });
| Método | Qué hace |
|---|---|
task.logs() | stdout y stderr nuevos desde la llamada anterior |
task.status() | estado sin consumir la salida: running, done, failed, killed, timeout |
task.wait(timeout, poll_interval=2, on_output) | consulta hasta que la tarea termina, devuelve TaskResult |
task.kill() | detiene la tarea y sus procesos |
sb.task(id) / sb.tasks() | volver a conectarse a una tarea / listar tareas |
Si wait agota su propio tiempo, lanza SandboxTimeoutError, pero la tarea sigue en marcha. Una tarea en curso también impide que una sandbox efímera se borre por inactividad.
Archivos y consumo
upload(path, content, mode=None) escribe un archivo en una ruta absoluta y devuelve su tamaño. download(path) devuelve bytes; download_text(path) / downloadText(path), una cadena. Una transferencia está limitada a 5 MB.
usage() devuelve los segundos en marcha, los segundos de CPU usados, los bytes salientes, el precio por hora, billed_usd y estimated_total_usd. tariffs() es una función simple que no necesita clave y devuelve los precios y límites actuales. Las reglas de facturación están en Límites y facturación de sandboxes.
Errores
Cada error de la API es una subclase de EqvpsError con status (HTTP), code (cadena estable) y body. retry_after / retryAfter se rellena cuando el servidor lo envía.
| Clase | HTTP | code típico | Qué hacer |
|---|---|---|---|
AuthenticationError | 401 | unauthenticated | revisar el token |
InsufficientBalanceError | 402 | insufficient_balance | recargar el saldo |
NotFoundError | 404 | not_found | id equivocado o archivo que no existe |
SandboxPausedError | 409 | sandbox_paused | en pausa porque se acabó el saldo; se reanuda tras recargar |
SandboxDeletedError | 410 | sandbox_deleted | borrada para siempre |
FileTooLargeError | 413 | file_too_large | mantener las transferencias por debajo de 5 MB |
ValidationError | 422 | invalid_request | corregir los parámetros |
RateLimitError | 429 | too_many_concurrent, too_many_tasks, rate_limited | esperar y reintentar |
BudgetExceededError | 429 | budget_exceeded | se alcanzó tu límite diario o mensual de sandboxes |
CapacityError | 503 | capacity | probar de nuevo en breve o elegir una tarifa menor |
SandboxTimeoutError | — | request_timeout, wait_timeout | expiró la petición HTTP (o wait), no el comando |
Dos límites causan la mayoría de los 429: una cuenta ejecuta 2 comandos a la vez y mantiene hasta 20 sandboxes. El SDK los reintenta cuando el servidor dice cuánto esperar; tras tres intentos recibes la excepción.
Cuándo no necesitas el SDK
Cualquier lenguaje con un cliente HTTP puede llamar a la API directamente; los endpoints están en el archivo OpenAPI en https://eqvps.com/openapi.json. Los agentes en Claude, Cursor u otros clientes MCP no necesitan código: el servidor MCP tiene las mismas herramientas de sandbox. Y si solo quieres verlo funcionar, la página de sandboxes muestra las tarifas y la prueba de $1 para cuentas nuevas.
Comentarios
Aún no hay comentarios. Sé el primero.