SDK 是沙箱 REST API 之上的一层薄封装。它替你省掉三件事:手工拼请求、平台繁忙时重试、代码抛异常后忘记删除沙箱。本页内容对应两个包的 0.2.0 版本。
如果你从没创建过沙箱,先看 5 分钟连接指南 拿到 token。沙箱是什么、里面有什么,见 沙箱。
安装与配置
pip install eqvps # Python 3.8+
npm i @eqvps/sdk # Node.js 18+, Deno, Bun
export EQVPS_API_KEY=... # your EQVPS account token
两种语言写的同一个程序:创建沙箱、运行代码、删除沙箱。
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
});
创建与查找沙箱
Sandbox.create(...) 启动一个沙箱,通常约一秒。Python 使用关键字参数,TypeScript 使用一个选项对象。
| Python | TypeScript | 默认值 | 含义 |
|---|---|---|---|
mode | mode | "ephemeral" | "ephemeral"(按秒)或 "persistent"(按已开始的小时计费,保留磁盘) |
tariff | tariff | "small" | micro、small、standard、plus、pro、max |
idle_timeout | idleTimeout | 300 | 临时沙箱无活动多少秒后被删除,最长 3600 |
ttl | ttl | — | 最长存活时间(秒):临时沙箱最多 86400,持久沙箱最多 2592000 |
env | env | — | 所有命令可用的环境变量,加密存储 |
api_key、base_url | apiKey、baseUrl | 环境变量 | 覆盖 EQVPS_API_KEY / EQVPS_API_URL |
timeout | timeoutMs | 70 秒 | 每个请求的 HTTP 超时 |
max_retries | maxRetries | 3 | 遇到 429/503 时的重试次数 |
Sandbox.connect(id) 连接到已有沙箱,通常是你昨天创建的持久沙箱。Sandbox.list() 返回账户下的全部沙箱,包括运行中和已暂停的。
属性:id(sb_ + 24 位十六进制字符)、mode、tariff、state(running、starting、paused、pausing、resuming、deleting、deleted)、env_keys / envKeys(只有名称,值永远不会返回)以及 info(原始对象)。refresh() 会重新加载这些属性。
kill() 删除沙箱并停止计费。对已经不存在的沙箱调用它不算错误。
运行代码
run(code, language="python", timeout=30) 通过 stdin 把代码交给 Python 3.12、Node.js 22 或 bash("python"、"node"、"bash")。exec(command, cwd=None, stdin=None, timeout=30) 执行 shell 命令:字符串经 bash -lc 执行,列表则作为 argv 直接执行、不经过 shell。
两者都返回 ExecResult:
| 字段 | 含义 |
|---|---|
exit_code | 进程退出码 |
stdout、stderr | 输出,每个流最多 1 MiB |
timed_out | 命令触发了超时 |
truncated | 输出被截断 |
duration_ms | 运行时长 |
ok | exit_code == 0 且没有超时 |
一次同步调用 最长 55 秒。两个方法都接受只作用于本次调用的 env,它会覆盖创建时设置的值。
长任务:后台任务
传入 background=True(TypeScript:{ background: true }),立即得到一个 Task。它没有 55 秒限制,可以一直运行到沙箱生命周期结束。每个沙箱最多 8 个任务。
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) });
| 方法 | 作用 |
|---|---|
task.logs() | 自上次调用以来新增的 stdout 和 stderr |
task.status() | 查看状态而不消费输出:running、done、failed、killed、timeout |
task.wait(timeout, poll_interval=2, on_output) | 轮询直到任务结束,返回 TaskResult |
task.kill() | 停止任务及其进程 |
sb.task(id) / sb.tasks() | 重新连接某个任务 / 列出任务 |
如果 wait 自身超时,会抛出 SandboxTimeoutError,但任务仍在运行。运行中的任务还会阻止临时沙箱因空闲被删除。
文件与用量
upload(path, content, mode=None) 把文件写到绝对路径并返回其大小。download(path) 返回字节,download_text(path) / downloadText(path) 返回字符串。单次传输上限 5 MB。
usage() 返回运行秒数、已用 CPU 秒数、出站字节、每小时价格、billed_usd 和 estimated_total_usd。tariffs() 是一个无需密钥的普通函数,返回当前价格和限制。计费规则见 沙箱限制与计费。
错误
所有 API 错误都是 EqvpsError 的子类,带有 status(HTTP 状态)、code(稳定的字符串)和 body。服务器返回时会填充 retry_after / retryAfter。
| 类 | HTTP | 典型 code | 处理方式 |
|---|---|---|---|
AuthenticationError | 401 | unauthenticated | 检查 token |
InsufficientBalanceError | 402 | insufficient_balance | 充值余额 |
NotFoundError | 404 | not_found | id 错误或文件不存在 |
SandboxPausedError | 409 | sandbox_paused | 因余额耗尽而暂停,充值后恢复 |
SandboxDeletedError | 410 | sandbox_deleted | 已被永久删除 |
FileTooLargeError | 413 | file_too_large | 单次传输保持在 5 MB 以下 |
ValidationError | 422 | invalid_request | 修正参数 |
RateLimitError | 429 | too_many_concurrent、too_many_tasks、rate_limited | 等待后重试 |
BudgetExceededError | 429 | budget_exceeded | 达到沙箱的每日或每月支出上限 |
CapacityError | 503 | capacity | 稍后重试或改用更小的套餐 |
SandboxTimeoutError | — | request_timeout、wait_timeout | 超时的是 HTTP 请求(或 wait),不是命令 |
大多数 429 来自两个限制:一个账户 同时最多执行 2 条命令,最多持有 20 个沙箱。服务器告知等待时间时 SDK 会自动重试,三次之后抛出异常。
什么时候不需要 SDK
任何有 HTTP 客户端的语言都可以直接调用 API,接口定义在 https://eqvps.com/openapi.json 的 OpenAPI 文件里。在 Claude、Cursor 或其他 MCP 客户端里运行的代理完全不需要写代码:MCP 服务器 提供同样的沙箱工具。如果只是想看看效果,沙箱页面 列出了套餐以及新账户的 $1 试用。
评论
暂无评论。来做第一个吧。