O SDK é uma camada fina sobre a API REST de sandboxes. Ele poupa você de três coisas: montar requisições à mão, repeti-las quando a plataforma está ocupada e esquecer de apagar uma sandbox quando o código lança uma exceção. Tudo aqui corresponde à versão 0.2.0 dos dois pacotes.
Se você nunca criou uma sandbox, o guia de conexão em 5 minutos entrega um token primeiro. O que é uma sandbox e o que tem dentro está em Sandboxes.
Instalar e configurar
pip install eqvps # Python 3.8+
npm i @eqvps/sdk # Node.js 18+, Deno, Bun
export EQVPS_API_KEY=... # your EQVPS account token
O mesmo programa nas duas linguagens: criar uma sandbox, rodar código, apagá-la.
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
});
Criar e encontrar sandboxes
Sandbox.create(...) inicia uma sandbox, normalmente em cerca de um segundo. Python recebe argumentos nomeados; TypeScript, um objeto de opções.
| Python | TypeScript | Padrão | Significado |
|---|---|---|---|
mode | mode | "ephemeral" | "ephemeral" (por segundo) ou "persistent" (por hora iniciada, mantém o disco) |
tariff | tariff | "small" | micro, small, standard, plus, pro, max |
idle_timeout | idleTimeout | 300 | segundos sem atividade antes de apagar uma sandbox efêmera, até 3600 |
ttl | ttl | — | vida máxima em segundos: até 86400 na efêmera, 2592000 na persistente |
env | env | — | variáveis de ambiente para todos os comandos, guardadas criptografadas |
api_key, base_url | apiKey, baseUrl | variáveis de ambiente | substituem EQVPS_API_KEY / EQVPS_API_URL |
timeout | timeoutMs | 70 s | tempo limite HTTP por requisição |
max_retries | maxRetries | 3 | novas tentativas em 429/503 |
Sandbox.connect(id) se conecta a uma sandbox existente, em geral uma persistente que você criou ontem. Sandbox.list() devolve todas as sandboxes da conta, ativas e pausadas.
Propriedades: id (sb_ + 24 caracteres hexadecimais), mode, tariff, state (running, starting, paused, pausing, resuming, deleting, deleted), env_keys / envKeys (só os nomes; os valores nunca voltam) e info (o objeto bruto). refresh() recarrega tudo.
kill() apaga a sandbox e para a cobrança. Chamar em uma sandbox que já não existe não é erro.
Rodar código
run(code, language="python", timeout=30) manda o código pelo stdin para Python 3.12, Node.js 22 ou bash ("python", "node", "bash"). exec(command, cwd=None, stdin=None, timeout=30) executa um comando de shell: uma string passa por bash -lc, uma lista é executada como argv sem shell.
Os dois devolvem um ExecResult:
| Campo | Significado |
|---|---|
exit_code | código de saída do processo |
stdout, stderr | saída, até 1 MiB por fluxo |
timed_out | o comando estourou o tempo |
truncated | a saída foi cortada |
duration_ms | quanto tempo levou |
ok | exit_code == 0 e sem estouro de tempo |
Uma chamada síncrona roda por no máximo 55 segundos. Os dois métodos também aceitam env só para aquela chamada; ele substitui os valores definidos na criação.
Trabalhos longos: tarefas em segundo plano
Passe background=True (TypeScript: { background: true }) e você recebe uma Task na hora. Ela não tem o limite de 55 segundos e pode rodar até o fim da vida da sandbox. Até 8 tarefas 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 | O que faz |
|---|---|
task.logs() | stdout e stderr novos desde a chamada anterior |
task.status() | estado sem consumir a saída: running, done, failed, killed, timeout |
task.wait(timeout, poll_interval=2, on_output) | consulta até a tarefa terminar, devolve TaskResult |
task.kill() | para a tarefa e seus processos |
sb.task(id) / sb.tasks() | reconectar a uma tarefa / listar tarefas |
Se o wait estourar o próprio tempo, ele lança SandboxTimeoutError, mas a tarefa continua rodando. Uma tarefa em andamento também impede que uma sandbox efêmera seja apagada por inatividade.
Arquivos e consumo
upload(path, content, mode=None) grava um arquivo em um caminho absoluto e devolve o tamanho. download(path) devolve bytes; download_text(path) / downloadText(path), uma string. Uma transferência é limitada a 5 MB.
usage() devolve os segundos em execução, os segundos de CPU usados, os bytes de saída, o preço por hora, billed_usd e estimated_total_usd. tariffs() é uma função simples que não precisa de chave e devolve preços e limites atuais. As regras de cobrança estão em Limites e cobrança de sandboxes.
Erros
Todo erro da API é uma subclasse de EqvpsError com status (HTTP), code (string estável) e body. retry_after / retryAfter vem preenchido quando o servidor o envia.
| Classe | HTTP | code típico | O que fazer |
|---|---|---|---|
AuthenticationError | 401 | unauthenticated | conferir o token |
InsufficientBalanceError | 402 | insufficient_balance | recarregar o saldo |
NotFoundError | 404 | not_found | id errado ou arquivo inexistente |
SandboxPausedError | 409 | sandbox_paused | pausada porque o saldo acabou; volta após a recarga |
SandboxDeletedError | 410 | sandbox_deleted | apagada de vez |
FileTooLargeError | 413 | file_too_large | manter as transferências abaixo de 5 MB |
ValidationError | 422 | invalid_request | corrigir os parâmetros |
RateLimitError | 429 | too_many_concurrent, too_many_tasks, rate_limited | esperar e tentar de novo |
BudgetExceededError | 429 | budget_exceeded | o limite diário ou mensal de sandboxes foi atingido |
CapacityError | 503 | capacity | tentar de novo em instantes ou escolher um plano menor |
SandboxTimeoutError | — | request_timeout, wait_timeout | estourou o tempo da requisição HTTP (ou do wait), não do comando |
Dois limites causam a maioria dos 429: uma conta executa 2 comandos ao mesmo tempo e mantém até 20 sandboxes. O SDK repete essas requisições quando o servidor diz quanto esperar; depois de três tentativas, você recebe a exceção.
Quando dispensar o SDK
Qualquer linguagem com um cliente HTTP pode chamar a API diretamente; os endpoints estão no arquivo OpenAPI em https://eqvps.com/openapi.json. Agentes no Claude, Cursor ou outros clientes MCP não precisam de código nenhum: o servidor MCP tem as mesmas ferramentas de sandbox. E se você só quer ver funcionando, a página de sandboxes mostra os planos e o teste de $1 para contas novas.
Comentários
Nenhum comentário ainda. Seja o primeiro.