Capsule 是一个在隔离环境中执行不受信任代码的运行时。每个任务都在自己的 WebAssembly 沙箱中运行,提供:
只需用 @task 装饰器注解你的 Python 函数:
from capsule import task
@task(name="analyze_data", compute="MEDIUM", ram="512MB", timeout="30s", max_retries=1)
def analyze_data(dataset: list) -> dict:
"""在隔离、资源控制的环境中处理数据。"""
# 你的代码在 Wasm 沙箱中安全运行
return {"processed": len(dataset), "status": "complete"}
使用 task() 包装函数,可完全访问 npm 生态系统:
import { task } from "@capsule-run/sdk";
export const analyzeData = task({
name: "analyze_data",
compute: "MEDIUM",
ram: "512MB",
timeout: "30s",
maxRetries: 1
}, (dataset: number[]): object => {
// 你的代码在 Wasm 沙箱中安全运行
return { processed: dataset.length, status: "complete" };
});
[!NOTE] 运行时需要一个名为
"main"的任务作为入口点。如果未定义,Python 将自动创建一个,但建议显式设置。
当你运行 capsule run main.py(或 main.ts)时,你的代码会被编译成 WebAssembly 模块并在隔离沙箱中执行。
每个任务都在其自己的沙箱中运行,具有可配置的资源限制,确保故障被隔离,不会级联到工作流的其他部分。主机系统控制执行的每个方面,从通过 Wasm 燃料计量的 CPU 分配到内存限制和超时强制。
pip install capsule-run
创建 hello.py:
from capsule import task
@task(name="main", compute="LOW", ram="64MB")
def main() -> str:
return "Hello from Capsule!"
运行它:
capsule run hello.py
npm install -g @capsule-run/cli
npm install @capsule-run/sdk
创建 hello.ts:
import { task } from "@capsule-run/sdk";
export const main = task({
name: "main",
compute: "LOW",
ram: "64MB"
}, (): string => {
return "Hello from Capsule!";
});
运行它:
capsule run hello.ts
[!TIP] 添加
--verbose以查看实时任务执行详情。
run() 函数允许你从代码中以编程方式执行任务,而不是使用 CLI。args 会自动作为参数转发给 main 任务。
from capsule import run
result = await run(
file="./sandbox.py",
args=["code to execute"]
)
创建 sandbox.py:
from capsule import task
@task(name="main", compute="LOW", ram="64MB")
def main(code: str) -> str:
return eval(code)
[!IMPORTANT] 你的依赖中需要
@capsule-run/cli才能在 TypeScript 中使用 runner 函数。
import { run } from '@capsule-run/sdk/runner';
const result = await run({
file: './sandbox.ts',
args: ['code to execute']
});
创建 sandbox.ts:
import { task } from "@capsule-run/sdk";
export const main = task({
name: "main",
compute: "LOW",
ram: "64MB"
}, (code: string): string => {
return eval(code);
});
[!TIP] 如果你在寻找预配置、开箱即用的解决方案,请查看 Python 适配器 或 TypeScript 适配器。
使用以下参数配置你的任务:
| 参数 | 描述 | 类型 | 默认值 | 示例 |
|---|---|---|---|---|
name | 任务标识符 | str | 函数名 (Python) / 必填 (TS) | "process_data" |
compute | CPU 分配级别:"LOW"、"MEDIUM" 或 "HIGH" | str | "MEDIUM" | "HIGH" |
ram | 任务的内存限制 | str | 无限制 | "512MB", "2GB" |
timeout | 最大执行时间 | str | 无限制 | "30s", "5m", "1h" |
max_retries / maxRetries | 失败时的重试次数 | int | 0 | 3 |
allowed_files / allowedFiles | 沙箱中可访问的文件夹(带有可选访问模式) | list | [] | ["./data"], [{"path": "./data", "mode": "ro"}] |
allowed_hosts / allowedHosts | 沙箱中可访问的域名 | list | [] | ["api.openai.com", "*.anthropic.com"] |
env_variables / envVariables | 沙箱中可访问的环境变量 | list | [] | ["API_KEY"] |
Capsule 通过 WebAssembly 的燃料机制控制 CPU 使用量,该机制对指令执行进行计量。计算级别决定了你的任务获得多少燃料。
compute="1000000"),以便精确控制执行限制。每个任务返回一个结构化的 JSON 信封,包含结果和执行元数据:
{
"success": true,
"result": "Hello from Capsule!",
"error": null,
"execution": {
"task_name": "data_processor",
"duration_ms": 1523,
"retries": 0,
"fuel_consumed": 45000,
"ram_used": 1200000,
"host_requests": [{...}]
}
}
响应字段:
success — 布尔值,指示任务是否成功完成result — 任务的实际返回值(json、字符串,失败时为 null 等)error — 任务失败时的错误详情({ error_type: string, message: string })execution — 性能指标:
task_name — 执行的任务名称duration_ms — 执行时间(毫秒)retries — 发生的重试次数fuel_consumed — 使用的 CPU 资源(参见 计算级别)ram_used — 峰值内存使用量(字节)host_requests — 任务发出的主机请求列表任务可以对 allowed_hosts 中指定的域名发起 HTTP 请求。默认情况下,不允许出站请求([])。提供域名允许列表以授予访问权限,或使用 ["*"] 允许所有域名。
import json
from capsule import task
from urllib.request import urlopen
@task(name="main", allowed_hosts=["api.openai.com", "*.anthropic.com"])
def main() -> dict:
with urlopen("https://api.openai.com/v1/models") as response:
return json.loads(response.read().decode("utf-8"))
import { task } from "@capsule-run/sdk";
export const main = task({
name: "main",
allowedHosts: ["api.openai.com", "*.anthropic.com"]
}, async () => {
const response = await fetch("https://api.openai.com/v1/models");
return response.json();
});
任务可以读取和写入 allowed_files 中指定目录内的文件。尝试访问这些目录之外的文件是不可能的。
[!NOTE]
allowed_files仅支持目录路径,不支持单个文件。
每个条目可以是普通路径(默认为读写)或带有显式 mode 的结构化对象:
"read-only"(或 "ro")"read-write"(或 "rw")Python 的标准文件操作正常工作。使用 open()、os、pathlib 或任何文件操作库。
from capsule import task
@task(name="main", allowed_files=[
{"path": "./data", "mode": "read-only"},
{"path": "./output", "mode": "read-write"},
])
def main() -> str:
with open("./data/input.txt") as f:
content = f.read()
with open("./output/result.txt", "w") as f:
f.write(content)
return content
普通字符串仍然接受:allowed_files=["./output"] 默认为读写。
常见的 Node.js 内置模块可用。使用标准 fs 模块:
import { task } from "@capsule-run/sdk";
import fs from "fs/promises";
export const main = task({
name: "main",
allowedFiles: [
{ path: "./data", mode: "read-only" },
{ path: "./output", mode: "read-write" },
]
}, async () => {
const content = await fs.readFile("./data/input.txt", "utf8");
await fs.writeFile("./output/result.txt", content);
return content;
});
普通字符串仍然接受:allowedFiles: ["./output"] 默认为读写。
--mount)--mount 标志(CLI)或 mounts 参数(SDK)将主机目录挂载到沙箱中,并使用别名。挂载会传播到子任务,并添加对新路径的访问,但不会更改 allowed_files 中已声明路径的访问模式。
格式: HOST_PATH[::GUEST_PATH][:ro|:rw]
| 部分 | 必需 | 描述 |
|---|---|---|
HOST_PATH | 是 | 主机上的路径(相对于 cwd,必须保持在项目根目录内) |
::GUEST_PATH | 否 | 任务在沙箱内看到的路径。默认为 HOST_PATH |
:ro / :rw | 否 | 访问模式。默认为读写 |
CLI
# 挂载一个会话工作区,并在任务内将其暴露为 "workspace"
capsule run main.py --mount sessions/abc123_workspace::workspace
# 多个目录
capsule run main.py \
--mount sessions/abc123_workspace::workspace \
--mount sessions/bce456_workspace::workspace:ro
Python SDK
from capsule import run
result = await run(
file="main.py",
mounts=[".capsule/sessions/abc123_workspace::workspace"],
)