Das SDK ist eine dünne Schicht über der Sandbox-REST-API. Es erspart Ihnen drei Dinge: Anfragen von Hand zu bauen, sie zu wiederholen, wenn die Plattform ausgelastet ist, und das Löschen einer Sandbox zu vergessen, wenn Ihr Code abstürzt. Alles hier entspricht Version 0.2.0 beider Pakete.
Falls Sie noch nie eine Sandbox angelegt haben, holen Sie sich mit der 5-Minuten-Verbindungsanleitung zuerst ein Token. Was eine Sandbox ist und was darin steckt, steht unter Sandboxen.
Installation und Konfiguration
pip install eqvps # Python 3.8+
npm i @eqvps/sdk # Node.js 18+, Deno, Bun
export EQVPS_API_KEY=... # your EQVPS account token
Dasselbe Programm in beiden Sprachen: Sandbox anlegen, Code ausführen, löschen.
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
});
Sandboxen anlegen und finden
Sandbox.create(...) startet eine Sandbox, meist in etwa einer Sekunde. Python nimmt Keyword-Argumente, TypeScript ein Options-Objekt.
| Python | TypeScript | Standard | Bedeutung |
|---|---|---|---|
mode | mode | "ephemeral" | "ephemeral" (pro Sekunde) oder "persistent" (pro angefangener Stunde, behält die Platte) |
tariff | tariff | "small" | micro, small, standard, plus, pro, max |
idle_timeout | idleTimeout | 300 | Sekunden ohne Aktivität, bevor eine ephemere Sandbox gelöscht wird, bis 3600 |
ttl | ttl | — | maximale Lebensdauer in Sekunden: bis 86400 ephemer, 2592000 persistent |
env | env | — | Umgebungsvariablen für jeden Befehl, verschlüsselt gespeichert |
api_key, base_url | apiKey, baseUrl | Umgebungsvariablen | überschreiben EQVPS_API_KEY / EQVPS_API_URL |
timeout | timeoutMs | 70 s | HTTP-Timeout pro Anfrage |
max_retries | maxRetries | 3 | Wiederholungen bei 429/503 |
Sandbox.connect(id) verbindet sich mit einer bestehenden Sandbox, typischerweise einer persistenten von gestern. Sandbox.list() liefert alle Sandboxen des Kontos, laufende und pausierte.
Eigenschaften: id (sb_ + 24 Hex-Zeichen), mode, tariff, state (running, starting, paused, pausing, resuming, deleting, deleted), env_keys / envKeys (nur Namen, Werte kommen nie zurück) und info (das Rohobjekt). refresh() lädt sie neu.
kill() löscht die Sandbox und beendet die Abrechnung. Der Aufruf für eine bereits gelöschte Sandbox ist kein Fehler.
Code ausführen
run(code, language="python", timeout=30) schickt Code per stdin an Python 3.12, Node.js 22 oder bash ("python", "node", "bash"). exec(command, cwd=None, stdin=None, timeout=30) führt einen Shell-Befehl aus: Ein String läuft über bash -lc, eine Liste wird als argv ohne Shell ausgeführt.
Beide liefern ein ExecResult:
| Feld | Bedeutung |
|---|---|
exit_code | Exit-Code des Prozesses |
stdout, stderr | Ausgabe, bis 1 MiB pro Stream |
timed_out | der Befehl lief in sein Timeout |
truncated | die Ausgabe wurde gekürzt |
duration_ms | Laufzeit |
ok | exit_code == 0 und kein Timeout |
Ein synchroner Aufruf darf höchstens 55 Sekunden laufen. Beide Methoden nehmen zusätzlich env für genau diesen Aufruf; es überschreibt die beim Anlegen gesetzten Werte.
Lange Jobs: Hintergrund-Tasks
Übergeben Sie background=True (TypeScript: { background: true }), und Sie bekommen sofort einen Task. Er hat keine 55-Sekunden-Grenze und kann bis zum Ende der Sandbox-Lebensdauer laufen. Bis zu 8 Tasks pro 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) });
| Methode | Was sie tut |
|---|---|
task.logs() | neues stdout und stderr seit dem letzten Aufruf |
task.status() | Zustand, ohne Ausgabe zu verbrauchen: running, done, failed, killed, timeout |
task.wait(timeout, poll_interval=2, on_output) | fragt ab, bis der Task endet, liefert TaskResult |
task.kill() | stoppt den Task und seine Prozesse |
sb.task(id) / sb.tasks() | erneut an einen Task anhängen / Tasks auflisten |
Läuft das eigene Timeout von wait ab, wirft es SandboxTimeoutError — der Task läuft aber weiter. Ein laufender Task verhindert außerdem, dass eine ephemere Sandbox wegen Inaktivität gelöscht wird.
Dateien und Verbrauch
upload(path, content, mode=None) schreibt eine Datei an einen absoluten Pfad und liefert ihre Größe. download(path) liefert Bytes, download_text(path) / downloadText(path) einen String. Eine Übertragung ist auf 5 MB begrenzt.
usage() liefert Laufzeit in Sekunden, verbrauchte CPU-Sekunden, ausgehende Bytes, den Stundenpreis, billed_usd und estimated_total_usd. tariffs() ist eine einfache Funktion ohne Schlüssel und liefert aktuelle Preise und Limits. Die Abrechnungsregeln stehen unter Sandbox-Limits und Abrechnung.
Fehler
Jeder API-Fehler ist eine Unterklasse von EqvpsError mit status (HTTP), code (stabiler String) und body. retry_after / retryAfter ist gesetzt, wenn der Server es mitschickt.
| Klasse | HTTP | Typischer code | Was tun |
|---|---|---|---|
AuthenticationError | 401 | unauthenticated | Token prüfen |
InsufficientBalanceError | 402 | insufficient_balance | Guthaben aufladen |
NotFoundError | 404 | not_found | falsche id oder Datei existiert nicht |
SandboxPausedError | 409 | sandbox_paused | pausiert, weil das Guthaben leer war; läuft nach dem Aufladen weiter |
SandboxDeletedError | 410 | sandbox_deleted | endgültig weg |
FileTooLargeError | 413 | file_too_large | Übertragungen unter 5 MB halten |
ValidationError | 422 | invalid_request | Parameter korrigieren |
RateLimitError | 429 | too_many_concurrent, too_many_tasks, rate_limited | warten und wiederholen |
BudgetExceededError | 429 | budget_exceeded | Ihr Tages- oder Monatslimit für Sandboxen ist erreicht |
CapacityError | 503 | capacity | gleich noch einmal versuchen oder einen kleineren Tarif wählen |
SandboxTimeoutError | — | request_timeout, wait_timeout | die HTTP-Anfrage (oder wait) lief ab, nicht der Befehl |
Zwei Limits verursachen die meisten 429: Ein Konto führt 2 Befehle gleichzeitig aus und hält bis zu 20 Sandboxen. Das SDK wiederholt solche Anfragen, wenn der Server sagt, wie lange zu warten ist; nach drei Versuchen bekommen Sie die Exception.
Wann Sie das SDK nicht brauchen
Jede Sprache mit HTTP-Client kann die API direkt aufrufen; die Endpunkte stehen in der OpenAPI-Datei unter https://eqvps.com/openapi.json. Agenten in Claude, Cursor oder anderen MCP-Clients brauchen gar keinen Code: Der MCP-Server hat dieselben Sandbox-Werkzeuge. Und wer es einfach in Aktion sehen will, findet auf der Sandbox-Seite die Tarife und die $1-Testphase für neue Konten.
Kommentare
Noch keine Kommentare. Sei der Erste.