
بيئة تشغيل آمنة لعزل مهام وكلاء الذكاء الاصطناعي في صندوق رمل. تشغيل الكود غير الموثوق في بيئات WebAssembly معزولة.
Capsule هو وقت تشغيل لتنفيذ الكود غير الموثوق في بيئات معزولة. كل مهمة تعمل داخل صندوق حماية WebAssembly الخاص بها، مما يوفر:
قم ببساطة بإضافة المُزيّن @task إلى دوال بايثون الخاصة بك:
from capsule import task
@task(name="analyze_data", compute="MEDIUM", ram="512MB", timeout="30s", max_retries=1)
def analyze_data(dataset: list) -> dict:
"""Process data in an isolated, resource-controlled environment."""
# Your code runs safely in a Wasm sandbox
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 => {
// Your code runs safely in a Wasm sandbox
return { processed: dataset.length, status: "complete" };
});
[!NOTE] يتطلب وقت التشغيل وجود مهمة باسم
"main"كنقطة دخول. ستنشئ بايثون مهمة تلقائيًا إذا لم يتم تعريف أي مهمة، ولكن يُوصى بتعيينها بشكل صريح.
عند تشغيل capsule run main.py (أو main.ts)، يتم تجميع كودك إلى وحدة WebAssembly وتنفيذها في صناديق حماية معزولة.
كل مهمة تعمل داخل صندوق الحماية الخاص بها مع حدود موارد قابلة للتكوين، مما يضمن احتواء حالات الفشل وعدم انتقالها إلى أجزاء أخرى من سير العمل الخاص بك. يتحكم نظام المضيف في كل جانب من جوانب التنفيذ، بدءًا من تخصيص وحدة المعالجة المركزية عبر قياس الوقود في Wasm إلى قيود الذاكرة وفرض المهلة.
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() تنفيذ المهام برمجيًا من الكود الخاص بك بدلاً من استخدام واجهة سطر الأوامر. يتم تمرير 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.
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] إذا كنت تبحث عن حل مهيأ مسبقًا وجاهز للاستخدام، فراجع محول بايثون أو محول TypeScript.
قم بتكوين مهامك باستخدام هذه المعاملات:
يتحكم Capsule في استخدام وحدة المعالجة المركزية من خلال آلية الوقود في WebAssembly، والتي تقيس تنفيذ التعليمات. يحدد مستوى الحوسبة مقدار الوقود الذي تتلقاه مهمتك.
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، string، null عند الفشل، إلخ)error — تفاصيل الخطأ إذا فشلت المهمة ({ error_type: string, message: string })execution — مقاييس الأداء:
task_name — اسم المهمة المنفذةduration_ms — وقت التنفيذ بالمللي ثانيةretries — عدد مرات إعادة المحاولة التي حدثتfuel_consumed — موارد وحدة المعالجة المركزية المستخدمة (راجع مستويات الحوسبة)ram_used — ذروة الذاكرة المستخدمة بالبايتhost_requests — قائمة بطلبات المضيف التي قامت بها المهمةيمكن للمهام إجراء طلبات HTTP إلى النطاقات المحددة في allowed_hosts. بشكل افتراضي، لا يُسمح بأي طلبات صادرة ([]). قدم قائمة مسموح بها من النطاقات لمنح الوصول، أو استخدم ["*"] للسماح بجميع النطاقات.
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")عمليات الملفات القياسية في بايثون تعمل بشكل طبيعي. استخدم 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]
CLI
# Mount a session workspace and expose it as "workspace" inside the task
capsule run main.py --mount sessions/abc123_workspace::workspace
# Multiple directories
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"],
)
TypeScript / JavaScript SDK
import { run } from "@capsule-run/sdk";
const result = await run({
file: "main.py",
mounts: [".capsule/sessions/abc123_workspace::workspace"],
});
داخل المهمة، يتم الوصول إلى الدليل عبر مسار الضيف:
# task sees it at "workspace/", not at the full session path
with open("workspace/output.txt", "w") as f:
f.write("done")
[!NOTE] يجب أن تكون مسارات
--mountنسبية ويجب ألا تخرج عن جذر المشروع. يتم رفض المسارات المطلقة.
يمكن للمهام الوصول إلى متغيرات البيئة لقراءة الإعدادات أو مفاتيح API أو أي إعدادات وقت تشغيل أخرى.
استخدم os.environ القياسي في بايثون للوصول إلى متغيرات البيئة:
from capsule import task
import os
@task(name="main", env_variables=["API_KEY"])
def main() -> dict:
api_key = os.environ.get("API_KEY")
return {"api_key": api_key}
استخدم process.env القياسي للوصول إلى متغيرات البيئة:
import { task } from "@capsule-run/sdk";
export const main = task({
name: "main",
envVariables: ["API_KEY"]
}, () => {
const apiKey = process.env.API_KEY;
return { apiKeySet: apiKey !== undefined };
});
يمكنك إنشاء ملف capsule.toml في جذر مشروعك لتعيين الخيارات الافتراضية لجميع المهام وتحديد بيانات سير العمل الوصفية:
# capsule.toml
[workflow]
name = "My Workflow"
version = "1.0.0"
entrypoint = "src/main.py" # Default file when running `capsule run`
[tasks]
default_compute = "MEDIUM"
default_ram = "256MB"
default_timeout = "30s"
default_max_retries = 2
مع تعريف نقطة دخول، يمكنك ببساطة تشغيل:
capsule run
تتجاوز الخيارات على مستوى المهمة دائمًا هذه الإعدادات الافتراضية عند تحديدها.
عند تشغيل الكود الخاص بك، ينشئ Capsule مجلد .capsule في جذر مشروعك. هذا هو ذاكرة التخزين المؤقت للبناء. يخزن القطع المجمعة بحيث تكون عمليات التشغيل اللاحقة سريعة (من ثوانٍ إلى بضع ملي ثانية).
[!TIP] يجب إضافة
.capsuleإلى.gitignore. التخزين المؤقت خاص ببيئتك الخاصة وسيتم إعادة إنشائه تلقائيًا.
.capsule/
├── wasm/
│ ├── main_a1b2c3d4.wasm # Compiled WebAssembly module
│ └── main_a1b2c3d4.cwasm # Native precompiled cache
├── wit/ # Interface definitions
└── trace.db # Execution logs
استخدم capsule build للتجميع المسبق مقدمًا وتخطي تكلفة التجميع في أول تشغيل:
capsule build main.ts # or `main.py`
تشغيل كود المصدر مباشرة (مثل .py أو .ts) يقوم بتقييم وتجميع ملفك في وقت التشغيل. على الرغم من أن هذا رائع للتطوير، إلا أن خطوة التجميع هذه تضيف بضع ثوانٍ من زمن الانتظار في أول استدعاء. لحالات الاستخدام التي يكون فيها زمن الاستجابة دون الثانية أمرًا بالغ الأهمية، يجب عليك بناء مهامك مسبقًا.
# Generates an optimized hello.wasm file
capsule build hello.py --export
# Execute the compiled artifact directly
capsule exec hello.wasm
[!NOTE] أو من الكود الحالي:
from capsule import run result = await run( file="./hello.wasm", # or `hello.py` args=[] ) print(f"Task completed: {result['result']}")
تنفيذ ملف .wasm يتجاوز المترجم تمامًا، مما يقلل وقت التهيئة إلى ملي ثانية مع استخدام تنسيق محسن أصلي (.cwasm) خلف الكواليس.
[!NOTE] TypeScript/JavaScript لديه توافق أوسع من بايثون لأنه لا يعتمد على الروابط الأصلية.
بايثون: معظم مكتبات بايثون القياسية تعمل بشكل مثالي. الحزم التي تستخدم ملحقات C تتطلب عجلة wasm32-wasi مجمعة. العديد من الحزم الشعبية مثل numpy و pandas لا تشحن واحدة بعد، لذلك لن تعمل داخل صندوق الحماية. ومع ذلك، فإن كود المضيف الخاص بك (باستخدام run()) لديه وصول إلى نظام بايثون البيئي الكامل، بما في ذلك أي حزمة pip وملحقات أصلية. راجع الاستخدام داخل الكود
TypeScript/JavaScript: حزم npm ووحدات ES تعمل. الوحدات المضمنة الشائعة في Node.js متاحة. إذا واجهت أي مشكلة مع وحدة مضمنة، فلا تتردد في فتح مشكلة.
المساهمات مرحب بها!
المتطلبات الأساسية: Rust (أحدث إصدار مستقر)، Python 3.13+، Node.js 22+
git clone https://github.com/capsulerun/capsule.git
cd capsule
# Build and install CLI
cargo install --path crates/capsule-cli
# Python SDK (editable install)
pip install -e crates/capsule-sdk/python
# TypeScript SDK (link for local dev)
cd crates/capsule-sdk/javascript
npm install && npm run build && npm link
# Then in your project: npm link @capsule-run/sdk
git checkout -b feature/amazing-featurecargo test (مطلوب فقط إذا قمت بتعديل crates/capsule-cli أو crates/capsule-core)هل تحتاج إلى مساعدة؟ افتح مشكلة
تم بناء Capsule على هذه المشاريع مفتوحة المصدر:
هذا المشروع مرخص بموجب رخصة Apache 2.0 - راجع ملف LICENSE للحصول على التفاصيل.
| المعامل | الوصف | النوع | الافتراضي | مثال |
|---|
name | معرف المهمة | str | اسم الدالة (بايثون) / مطلوب (تايب سكريبت) | "process_data" |
compute | مستوى تخصيص وحدة المعالجة المركزية: "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"] |
| الجزء | مطلوب | الوصف |
|---|
HOST_PATH | نعم | المسار على جهاز المضيف (نسبة إلى cwd، يجب أن يبقى داخل جذر المشروع) |
::GUEST_PATH | لا | المسار الذي تراه المهمة داخل صندوق الحماية. الافتراضي هو HOST_PATH |
:ro / :rw | لا | وضع الوصول. الافتراضي هو القراءة والكتابة |