Concept internals
TypeBox
TypeBox یک کتابخانهٔ طرحواره با رویکرد TypeScript-first است. OpenClaw از آن برای تعریف پروتکل WebSocket در Gateway (دستدهی، درخواست/پاسخ و رویدادهای سرور) استفاده میکند. این طرحوارهها مبنای اعتبارسنجی زمان اجرا (AJV)، صدور JSON Schema و تولید کد Swift برای برنامهٔ macOS هستند. یک منبع حقیقت وجود دارد و هر چیز دیگری از روی آن تولید میشود.
برای آشنایی با زمینهٔ سطحبالاتر پروتکل، از معماری Gateway شروع کنید.
مدل ذهنی (۳۰ ثانیه)
هر پیام WS در Gateway یکی از سه قاب زیر است:
- درخواست:
{ type: "req", id, method, params } - پاسخ:
{ type: "res", id, ok, payload | error } - رویداد:
{ type: "event", event, payload, seq?, stateVersion? }
قاب نخست باید یک درخواست connect باشد. پس از آن، کلاینتها متدها را فراخوانی میکنند (برای مثال health، send و chat.send) و مشترک رویدادها میشوند (برای مثال presence، tick و agent).
جریان اتصال (حداقلی):
Client Gateway |---- req:connect -------->| |<---- res:hello-ok --------| |<---- event:tick ----------| |---- req:health ---------->| |<---- res:health ----------|متدها و رویدادهای رایج:
| دسته | نمونهها | توضیحات |
|---|---|---|
| هسته | connect، health، status |
connect باید نخستین مورد باشد |
| پیامرسانی | send، agent، agent.wait، system-event، logs.tail |
متدهای دارای اثر جانبی به idempotencyKey نیاز دارند |
| گفتوگو | chat.history، chat.send، chat.abort |
WebChat از این موارد استفاده میکند |
| نشستها | sessions.list، sessions.patch، sessions.delete |
مدیریت نشست |
| خودکارسازی | wake، cron.list، cron.run، cron.runs |
کنترل بیدارسازی و cron |
| Nodeها | node.list، node.invoke، node.pair.* |
WS در Gateway بههمراه کنشهای Node |
| رویدادها | tick، presence، agent، chat، health، shutdown |
ارسال از سوی سرور |
فهرست مرجع و اعلامشدهٔ کشف قابلیتها در src/gateway/server-methods-list.ts (listGatewayMethods، GATEWAY_EVENTS) قرار دارد.
محل طرحوارهها
- فایل تجمیعی منبع:
packages/gateway-protocol/src/schema.tsماژولهای دامنه را ازpackages/gateway-protocol/src/schema/*.tsبازصادر میکند (frames.tsبرای پوششهای سطحبالا و دستدهی و فایلهایagent.ts،sessions.ts،cron.tsو غیره برای هر حوزهٔ قابلیت). فایلprotocol-schemas.tsرجیستری مرکزیProtocolSchemasاست که نام طرحوارهها را به تعریفهای TypeBox آنها نگاشت میکند. - اعتبارسنجهای زمان اجرا (AJV):
packages/gateway-protocol/src/index.ts - رجیستری قابلیتها/کشف اعلامشده:
src/gateway/server-methods-list.ts - دستدهی سرور و هدایت متدها:
src/gateway/server.impl.ts - کلاینت Node:
src/gateway/client.ts - JSON Schema تولیدشده:
dist/protocol.schema.json(خروجی ساخت، ثبتنشده در مخزن) - مدلهای Swift تولیدشده:
apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift
خط لولهٔ فعلی
pnpm protocol:gen، JSON Schema (نسخهٔ draft-07) را درdist/protocol.schema.jsonمینویسد.pnpm protocol:gen:swiftمدلهای Swift مربوط به Gateway را تولید میکند.pnpm protocol:checkهر دو مولد را اجرا و بررسی میکند که خروجی Swift در مخزن ثبت شده باشد (خروجی JSON Schema یک محصول جانبی ساخت است که Git آن را نادیده میگیرد).
نحوهٔ استفاده از طرحوارهها در زمان اجرا
- سمت سرور: هر قاب ورودی با AJV اعتبارسنجی میشود. دستدهی فقط درخواست
connectای را میپذیرد که پارامترهای آن باConnectParamsمطابقت داشته باشند. - سمت کلاینت: کلاینت JS قابهای رویداد و پاسخ را پیش از استفاده اعتبارسنجی میکند.
- کشف قابلیتها: Gateway در
hello-okفهرستی محافظهکارانه ازfeatures.methodsوfeatures.eventsرا ازlistGatewayMethods()وGATEWAY_EVENTSارسال میکند. - این فهرست کشف، تخلیهای تولیدشده از تمام توابع کمکی قابل فراخوانی در
coreGatewayHandlersنیست؛ برخی RPCهای کمکی درsrc/gateway/server-methods/*.tsپیادهسازی شدهاند، بیآنکه در فهرست قابلیتهای اعلامشده برشمرده شوند.
نمونهٔ قابها
اتصال (نخستین پیام):
{ "type": "req", "id": "c1", "method": "connect", "params": { "minProtocol": 3, "maxProtocol": 4, "client": { "id": "openclaw-macos", "displayName": "macos", "version": "1.0.0", "platform": "macos 15.1", "mode": "ui", "instanceId": "A1B2" } }}پاسخ Hello-ok:
{ "type": "res", "id": "c1", "ok": true, "payload": { "type": "hello-ok", "protocol": 4, "server": { "version": "dev", "connId": "ws-1" }, "features": { "methods": ["health"], "events": ["tick"] }, "snapshot": { "presence": [], "health": {}, "stateVersion": { "presence": 0, "health": 0 }, "uptimeMs": 0 }, "auth": { "role": "operator", "scopes": ["operator.read"] }, "policy": { "maxPayload": 1048576, "maxBufferedBytes": 1048576, "tickIntervalMs": 30000 } }}درخواست و پاسخ:
{ "type": "req", "id": "r1", "method": "health" }{ "type": "res", "id": "r1", "ok": true, "payload": { "ok": true } }رویداد:
{ "type": "event", "event": "tick", "payload": { "ts": 1730000000 }, "seq": 12 }کلاینت حداقلی (Node.js)
کوچکترین جریان کاربردی: اتصال + بررسی سلامت.
const ws = new WebSocket("ws://127.0.0.1:18789"); ws.on("open", () => { ws.send( JSON.stringify({ type: "req", id: "c1", method: "connect", params: { minProtocol: 4, maxProtocol: 4, client: { id: "cli", displayName: "example", version: "dev", platform: "node", mode: "cli", }, }, }), );}); ws.on("message", (data) => { const msg = JSON.parse(String(data)); if (msg.type === "res" && msg.id === "c1" && msg.ok) { ws.send(JSON.stringify({ type: "req", id: "h1", method: "health" })); } if (msg.type === "res" && msg.id === "h1") { console.log("health:", msg.payload); ws.close(); }});مثال عملی: افزودن سرتاسری یک متد
مثال: افزودن درخواست جدید system.echo که { ok: true, text } را برمیگرداند.
- طرحواره (منبع حقیقت)
به packages/gateway-protocol/src/schema/system.ts (یا نزدیکترین ماژول قابلیت مرتبط) اضافه کنید:
export const SystemEchoParamsSchema = Type.Object( { text: NonEmptyString }, { additionalProperties: false },); export const SystemEchoResultSchema = Type.Object( { ok: Type.Boolean(), text: NonEmptyString }, { additionalProperties: false },);هر دو را در packages/gateway-protocol/src/schema/protocol-schemas.ts وارد کنید، آنها را به رجیستری ProtocolSchemas بیفزایید و نوعهای مشتقشده را صادر کنید:
SystemEchoParams: SystemEchoParamsSchema, SystemEchoResult: SystemEchoResultSchema,export type SystemEchoParams = Static<typeof SystemEchoParamsSchema>;export type SystemEchoResult = Static<typeof SystemEchoResultSchema>;- اعتبارسنجی
در packages/gateway-protocol/src/index.ts یک اعتبارسنج AJV صادر کنید:
export const validateSystemEchoParams = ajv.compile<SystemEchoParams>(SystemEchoParamsSchema);- رفتار سرور
یک کنترلگر در src/gateway/server-methods/system.ts اضافه کنید:
export const systemHandlers: GatewayRequestHandlers = { "system.echo": ({ params, respond }) => { const text = String(params.text ?? ""); respond(true, { ok: true, text }); },};آن را در src/gateway/server-methods.ts ثبت کنید (این فایل از قبل systemHandlers را ادغام میکند)، سپس "system.echo" را به ورودی listGatewayMethods در src/gateway/server-methods-list.ts اضافه کنید.
اگر این متد توسط کلاینتهای عملگر یا Node قابل فراخوانی است، آن را در src/gateway/method-scopes.ts نیز طبقهبندی کنید تا اعمال دامنهٔ دسترسی و اعلام قابلیتها در hello-ok همراستا بمانند.
- تولید مجدد
pnpm protocol:check- آزمونها و مستندات
یک آزمون سرور در src/gateway/server.*.test.ts اضافه کنید و متد را در مستندات ذکر کنید.
رفتار تولید کد Swift
مولد Swift موارد زیر را تولید میکند:
- یک enum به نام
GatewayFrameبا حالتهایreq،res،eventوunknown - ساختارها و enumهای payload با نوعدهی قوی
- مقادیر
ErrorCode،GATEWAY_PROTOCOL_VERSIONوGATEWAY_MIN_PROTOCOL_VERSION
نوعهای ناشناختهٔ قاب برای سازگاری روبهجلو بهصورت payload خام حفظ میشوند.
نسخهبندی و سازگاری
PROTOCOL_VERSIONدرpackages/gateway-protocol/src/version.tsقرار دارد (مقدار فعلی:4).- کلاینتها
minProtocolوmaxProtocolرا ارسال میکنند؛ سرور بازههایی را که پروتکل فعلیاش را در بر نگیرند رد میکند. - مدلهای Swift نوعهای ناشناختهٔ قاب را حفظ میکنند تا کلاینتهای قدیمیتر از کار نیفتند.
الگوها و قراردادهای طرحواره
- بیشتر اشیا برای payloadهای سختگیرانه از
additionalProperties: falseاستفاده میکنند. NonEmptyString(Type.String({ minLength: 1 })) گزینهٔ پیشفرض برای شناسهها و نام متدها/رویدادها است.GatewayFrameسطحبالا از یک تفکیکگر رویtypeاستفاده میکند.- متدهای دارای اثر جانبی معمولاً در پارامترهای خود به
idempotencyKeyنیاز دارند (مثال:send،poll،agent،chat.send). agentمقدار اختیاریinternalEventsرا برای زمینهٔ هماهنگسازی تولیدشده در زمان اجرا میپذیرد (برای مثال تحویل تکمیل وظیفهٔ زیرعامل/cron)؛ این مورد را یک سطح API داخلی در نظر بگیرید.
JSON زندهٔ طرحواره
JSON Schema تولیدشده یک محصول جانبی ساخت است و در مخزن ثبت نمیشود. فایل خام منتشرشده معمولاً در نشانی زیر در دسترس است:
هنگام تغییر طرحوارهها
- طرحوارههای TypeBox را در ماژول مالک
packages/gateway-protocol/src/schema/*.tsبهروزرسانی و آنها را درprotocol-schemas.tsثبت کنید. - متد/رویداد را در
src/gateway/server-methods-list.tsثبت کنید. - هنگامی که RPC جدید به طبقهبندی دامنهٔ دسترسی عملگر یا Node نیاز دارد،
src/gateway/method-scopes.tsرا بهروزرسانی کنید. - دستور
pnpm protocol:checkرا اجرا کنید. - مدلهای Swift بازتولیدشده را ثبت کنید.