Concept internals
TypeBox
TypeBox là một thư viện lược đồ ưu tiên TypeScript. OpenClaw sử dụng thư viện này để định nghĩa giao thức WebSocket của Gateway (bắt tay, yêu cầu/phản hồi, sự kiện máy chủ). Các lược đồ đó phục vụ xác thực khi chạy (AJV), xuất JSON Schema và sinh mã Swift cho ứng dụng macOS. Chỉ có một nguồn dữ liệu chuẩn; mọi thứ khác đều được tạo tự động.
Để tìm hiểu bối cảnh giao thức ở cấp cao hơn, hãy bắt đầu với kiến trúc Gateway.
Mô hình tư duy (30 giây)
Mỗi thông điệp WS của Gateway thuộc một trong ba khung:
- Yêu cầu:
{ type: "req", id, method, params } - Phản hồi:
{ type: "res", id, ok, payload | error } - Sự kiện:
{ type: "event", event, payload, seq?, stateVersion? }
Khung đầu tiên bắt buộc phải là một yêu cầu connect. Sau đó, máy khách gọi các phương thức (ví dụ: health, send, chat.send) và đăng ký nhận sự kiện (ví dụ: presence, tick, agent).
Luồng kết nối (tối thiểu):
Máy khách Gateway |---- req:connect -------->| |<---- res:hello-ok --------| |<---- event:tick ----------| |---- req:health ---------->| |<---- res:health ----------|Các phương thức và sự kiện thường dùng:
| Danh mục | Ví dụ | Ghi chú |
|---|---|---|
| Cốt lõi | connect, health, status |
connect phải được gửi đầu tiên |
| Nhắn tin | send, agent, agent.wait, system-event, logs.tail |
các phương thức gây tác dụng phụ cần idempotencyKey |
| Trò chuyện | chat.history, chat.send, chat.abort |
WebChat sử dụng các phương thức này |
| Phiên | sessions.list, sessions.patch, sessions.delete |
quản trị phiên |
| Tự động hóa | wake, cron.list, cron.run, cron.runs |
điều khiển đánh thức và Cron |
| Node | node.list, node.invoke, node.pair.* |
WS của Gateway cùng các thao tác Node |
| Sự kiện | tick, presence, agent, chat, health, shutdown |
máy chủ chủ động đẩy |
Danh mục khám phá được công bố và có tính chuẩn nằm trong src/gateway/server-methods-list.ts (listGatewayMethods, GATEWAY_EVENTS).
Vị trí của các lược đồ
- Tệp xuất nguồn:
packages/gateway-protocol/src/schema.tstái xuất các mô-đun miền trongpackages/gateway-protocol/src/schema/*.ts(frames.tsdành cho các phong bì cấp cao nhất và quá trình bắt tay, cònagent.ts,sessions.ts,cron.ts, v.v. dành cho từng khu vực tính năng).protocol-schemas.tslà sổ đăng kýProtocolSchemastrung tâm, ánh xạ tên lược đồ tới định nghĩa TypeBox tương ứng. - Trình xác thực khi chạy (AJV):
packages/gateway-protocol/src/index.ts - Sổ đăng ký tính năng/khám phá được công bố:
src/gateway/server-methods-list.ts - Bắt tay máy chủ và điều phối phương thức:
src/gateway/server.impl.ts - Máy khách Node:
src/gateway/client.ts - JSON Schema được tạo:
dist/protocol.schema.json(đầu ra bản dựng, không được commit) - Mô hình Swift được tạo:
apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift
Quy trình hiện tại
pnpm protocol:genghi JSON Schema (draft-07) vàodist/protocol.schema.json.pnpm protocol:gen:swifttạo các mô hình Gateway bằng Swift.pnpm protocol:checkchạy cả hai trình sinh và xác minh rằng đầu ra Swift đã được commit (đầu ra JSON Schema là một tạo tác bản dựng bị git bỏ qua).
Cách sử dụng các lược đồ khi chạy
- Phía máy chủ: mọi khung đến đều được xác thực bằng AJV. Quá trình bắt tay chỉ chấp nhận yêu cầu
connectcó tham số khớp vớiConnectParams. - Phía máy khách: máy khách JS xác thực các khung sự kiện và phản hồi trước khi sử dụng.
- Khám phá tính năng: Gateway gửi danh sách
features.methodsvàfeatures.eventstheo hướng thận trọng tronghello-ok, lấy từlistGatewayMethods()vàGATEWAY_EVENTS. - Danh sách khám phá đó không phải là bản kết xuất được tạo tự động của mọi hàm trợ giúp có thể gọi trong
coreGatewayHandlers; một số RPC trợ giúp được triển khai trongsrc/gateway/server-methods/*.tsnhưng không được liệt kê trong danh sách tính năng được công bố.
Khung ví dụ
Kết nối (thông điệp đầu tiên):
{ "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" } }}Phản hồi 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 } }}Yêu cầu và phản hồi:
{ "type": "req", "id": "r1", "method": "health" }{ "type": "res", "id": "r1", "ok": true, "payload": { "ok": true } }Sự kiện:
{ "type": "event", "event": "tick", "payload": { "ts": 1730000000 }, "seq": 12 }Máy khách tối thiểu (Node.js)
Luồng hữu ích nhỏ nhất: kết nối + kiểm tra tình trạng.
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(); }});Ví dụ hoàn chỉnh: thêm một phương thức từ đầu đến cuối
Ví dụ: thêm yêu cầu system.echo mới trả về { ok: true, text }.
- Lược đồ (nguồn dữ liệu chuẩn)
Thêm vào packages/gateway-protocol/src/schema/system.ts (hoặc mô-đun tính năng phù hợp nhất):
export const SystemEchoParamsSchema = Type.Object( { text: NonEmptyString }, { additionalProperties: false },); export const SystemEchoResultSchema = Type.Object( { ok: Type.Boolean(), text: NonEmptyString }, { additionalProperties: false },);Nhập cả hai vào packages/gateway-protocol/src/schema/protocol-schemas.ts, thêm chúng vào sổ đăng ký ProtocolSchemas và xuất các kiểu dẫn xuất:
SystemEchoParams: SystemEchoParamsSchema, SystemEchoResult: SystemEchoResultSchema,export type SystemEchoParams = Static<typeof SystemEchoParamsSchema>;export type SystemEchoResult = Static<typeof SystemEchoResultSchema>;- Xác thực
Trong packages/gateway-protocol/src/index.ts, xuất một trình xác thực AJV:
export const validateSystemEchoParams = ajv.compile<SystemEchoParams>(SystemEchoParamsSchema);- Hành vi máy chủ
Thêm một trình xử lý trong src/gateway/server-methods/system.ts:
export const systemHandlers: GatewayRequestHandlers = { "system.echo": ({ params, respond }) => { const text = String(params.text ?? ""); respond(true, { ok: true, text }); },};Đăng ký trình xử lý này trong src/gateway/server-methods.ts (tệp này đã hợp nhất systemHandlers), sau đó thêm "system.echo" vào đầu vào của listGatewayMethods trong src/gateway/server-methods-list.ts.
Nếu phương thức có thể được máy khách vận hành viên hoặc Node gọi, hãy phân loại phương thức đó trong src/gateway/method-scopes.ts để việc thực thi phạm vi và công bố tính năng trong hello-ok luôn đồng bộ.
- Tạo lại
pnpm protocol:check- Kiểm thử và tài liệu
Thêm một kiểm thử máy chủ trong src/gateway/server.*.test.ts và ghi chú phương thức này trong tài liệu.
Hành vi sinh mã Swift
Trình sinh Swift tạo ra:
- một enum
GatewayFramevới các trường hợpreq,res,eventvàunknown - các struct/enum tải trọng được định kiểu chặt chẽ
- các giá trị
ErrorCode,GATEWAY_PROTOCOL_VERSIONvàGATEWAY_MIN_PROTOCOL_VERSION
Các kiểu khung không xác định được giữ nguyên dưới dạng tải trọng thô để bảo đảm khả năng tương thích về sau.
Lập phiên bản và khả năng tương thích
PROTOCOL_VERSIONnằm trongpackages/gateway-protocol/src/version.ts(giá trị hiện tại:4).- Máy khách gửi
minProtocolvàmaxProtocol; máy chủ từ chối các phạm vi không bao gồm giao thức hiện tại của máy chủ. - Các mô hình Swift giữ lại kiểu khung không xác định để tránh làm hỏng các máy khách cũ hơn.
Mẫu và quy ước lược đồ
- Hầu hết đối tượng sử dụng
additionalProperties: falseđể có tải trọng nghiêm ngặt. NonEmptyString(Type.String({ minLength: 1 })) là giá trị mặc định cho ID cũng như tên phương thức/sự kiện.GatewayFramecấp cao nhất sử dụng một trường phân biệt trêntype.- Các phương thức có tác dụng phụ thường yêu cầu
idempotencyKeytrong tham số (ví dụ:send,poll,agent,chat.send). agentchấp nhậninternalEventstùy chọn cho ngữ cảnh điều phối do môi trường chạy tạo ra (ví dụ: chuyển giao khi tác vụ tác nhân con/Cron hoàn tất); hãy xem đây là bề mặt API nội bộ.
JSON lược đồ trực tiếp
JSON Schema được tạo là một tạo tác bản dựng, không được commit vào kho mã nguồn. Tệp thô đã phát hành thường có tại:
Khi bạn thay đổi lược đồ
- Cập nhật các lược đồ TypeBox trong mô-đun sở hữu
packages/gateway-protocol/src/schema/*.tsvà đăng ký chúng trongprotocol-schemas.ts. - Đăng ký phương thức/sự kiện trong
src/gateway/server-methods-list.ts. - Cập nhật
src/gateway/method-scopes.tskhi RPC mới cần phân loại phạm vi vận hành viên hoặc Node. - Chạy
pnpm protocol:check. - Commit các mô hình Swift đã được tạo lại.