Concept internals

TypeBox

TypeBox ist eine TypeScript-orientierte Schemabibliothek. OpenClaw verwendet sie zur Definition des Gateway-WebSocket-Protokolls (Handshake, Anfrage/Antwort, Serverereignisse). Diese Schemas steuern die Laufzeitvalidierung (AJV), den JSON-Schema-Export und die Swift-Codegenerierung für die macOS-App. Eine einzige maßgebliche Quelle; alles andere wird generiert.

Für den übergeordneten Protokollkontext beginnen Sie mit der Gateway-Architektur.

Mentales Modell (30 Sekunden)

Jede Gateway-WS-Nachricht ist einer von drei Frames:

  • Anfrage: { type: "req", id, method, params }
  • Antwort: { type: "res", id, ok, payload | error }
  • Ereignis: { type: "event", event, payload, seq?, stateVersion? }

Der erste Frame muss eine connect-Anfrage sein. Danach rufen Clients Methoden auf (z. B. health, send, chat.send) und abonnieren Ereignisse (z. B. presence, tick, agent).

Verbindungsablauf (minimal):

text
Client                    Gateway  |---- Anfr.:connect ------->|  |<---- Antw.:hello-ok -------|  |<---- Ereignis:tick --------|  |---- Anfr.:health --------->|  |<---- Antw.:health ---------|

Häufig verwendete Methoden und Ereignisse:

Kategorie Beispiele Hinweise
Kern connect, health, status connect muss zuerst gesendet werden
Messaging send, agent, agent.wait, system-event, logs.tail Methoden mit Nebenwirkungen benötigen idempotencyKey
Chat chat.history, chat.send, chat.abort WebChat verwendet diese
Sitzungen sessions.list, sessions.patch, sessions.delete Sitzungsverwaltung
Automatisierung wake, cron.list, cron.run, cron.runs Steuerung von Aktivierung und Cron
Nodes node.list, node.invoke, node.pair.* Gateway-WS sowie Node-Aktionen
Ereignisse tick, presence, agent, chat, health, shutdown Server-Push

Das maßgebliche veröffentlichte Discovery-Inventar befindet sich in src/gateway/server-methods-list.ts (listGatewayMethods, GATEWAY_EVENTS).

Speicherort der Schemas

  • Quell-Barrel: packages/gateway-protocol/src/schema.ts reexportiert Domänenmodule unter packages/gateway-protocol/src/schema/*.ts (frames.ts für die übergeordneten Umschläge und den Handshake, agent.ts, sessions.ts, cron.ts usw. je Funktionsbereich). protocol-schemas.ts ist die zentrale ProtocolSchemas-Registry, die Schemanamen ihren TypeBox-Definitionen zuordnet.
  • Laufzeitvalidatoren (AJV): packages/gateway-protocol/src/index.ts
  • Veröffentlichte Funktions-/Discovery-Registry: src/gateway/server-methods-list.ts
  • Server-Handshake und Methodendispatch: src/gateway/server.impl.ts
  • Node-Client: src/gateway/client.ts
  • Generiertes JSON-Schema: dist/protocol.schema.json (Build-Ausgabe, nicht eingecheckt)
  • Generierte Swift-Modelle: apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift

Aktuelle Pipeline

  • pnpm protocol:gen schreibt das JSON-Schema (Draft-07) nach dist/protocol.schema.json.
  • pnpm protocol:gen:swift generiert die Swift-Gateway-Modelle.
  • pnpm protocol:check führt beide Generatoren aus und überprüft, ob die Swift-Ausgabe eingecheckt ist (die JSON-Schema-Ausgabe ist ein durch Git ignoriertes Build-Artefakt).

Verwendung der Schemas zur Laufzeit

  • Serverseitig: Jeder eingehende Frame wird mit AJV validiert. Der Handshake akzeptiert nur eine connect-Anfrage, deren Parameter ConnectParams entsprechen.
  • Clientseitig: Der JS-Client validiert Ereignis- und Antwort-Frames, bevor er sie verwendet.
  • Funktions-Discovery: Der Gateway sendet in hello-ok eine konservative Liste von features.methods und features.events aus listGatewayMethods() und GATEWAY_EVENTS.
  • Diese Discovery-Liste ist keine generierte Auflistung aller aufrufbaren Hilfsfunktionen in coreGatewayHandlers; einige Hilfs-RPCs sind in src/gateway/server-methods/*.ts implementiert, ohne in der veröffentlichten Funktionsliste aufgeführt zu sein.

Beispiel-Frames

Verbindung herstellen (erste Nachricht):

json
{  "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-Antwort:

json
{  "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 }  }}

Anfrage und Antwort:

json
{ "type": "req", "id": "r1", "method": "health" }
json
{ "type": "res", "id": "r1", "ok": true, "payload": { "ok": true } }

Ereignis:

json
{ "type": "event", "event": "tick", "payload": { "ts": 1730000000 }, "seq": 12 }

Minimaler Client (Node.js)

Kleinster sinnvoller Ablauf: Verbindung herstellen + Integritätsprüfung.

ts
 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();  }});

Durchgängiges Praxisbeispiel: eine Methode hinzufügen

Beispiel: Fügen Sie eine neue system.echo-Anfrage hinzu, die { ok: true, text } zurückgibt.

  1. Schema (maßgebliche Quelle)

Fügen Sie Folgendes zu packages/gateway-protocol/src/schema/system.ts (oder dem am besten passenden Funktionsmodul) hinzu:

ts
export const SystemEchoParamsSchema = Type.Object(  { text: NonEmptyString },  { additionalProperties: false },); export const SystemEchoResultSchema = Type.Object(  { ok: Type.Boolean(), text: NonEmptyString },  { additionalProperties: false },);

Importieren Sie beide in packages/gateway-protocol/src/schema/protocol-schemas.ts, fügen Sie sie der ProtocolSchemas-Registry hinzu und exportieren Sie die abgeleiteten Typen:

ts
  SystemEchoParams: SystemEchoParamsSchema,  SystemEchoResult: SystemEchoResultSchema,
ts
export type SystemEchoParams = Static<typeof SystemEchoParamsSchema>;export type SystemEchoResult = Static<typeof SystemEchoResultSchema>;
  1. Validierung

Exportieren Sie in packages/gateway-protocol/src/index.ts einen AJV-Validator:

ts
export const validateSystemEchoParams = ajv.compile&lt;SystemEchoParams&gt;(SystemEchoParamsSchema);
  1. Serververhalten

Fügen Sie in src/gateway/server-methods/system.ts einen Handler hinzu:

ts
export const systemHandlers: GatewayRequestHandlers = {  "system.echo": ({ params, respond }) => {    const text = String(params.text ?? "");    respond(true, { ok: true, text });  },};

Registrieren Sie ihn in src/gateway/server-methods.ts (führt systemHandlers bereits zusammen) und fügen Sie anschließend "system.echo" zur listGatewayMethods-Eingabe in src/gateway/server-methods-list.ts hinzu.

Wenn die Methode von Operator- oder Node-Clients aufgerufen werden kann, klassifizieren Sie sie außerdem in src/gateway/method-scopes.ts, damit Bereichserzwingung und hello-ok-Funktionsankündigung übereinstimmen.

  1. Neu generieren
bash
pnpm protocol:check
  1. Tests und Dokumentation

Fügen Sie einen Servertest in src/gateway/server.*.test.ts hinzu und erwähnen Sie die Methode in der Dokumentation.

Verhalten der Swift-Codegenerierung

Der Swift-Generator erzeugt:

  • eine GatewayFrame-Enumeration mit den Fällen req, res, event und unknown
  • stark typisierte Payload-Strukturen/-Enumerationen
  • ErrorCode-Werte, GATEWAY_PROTOCOL_VERSION und GATEWAY_MIN_PROTOCOL_VERSION

Unbekannte Frame-Typen werden zur Vorwärtskompatibilität als rohe Payloads beibehalten.

Versionierung und Kompatibilität

  • PROTOCOL_VERSION befindet sich in packages/gateway-protocol/src/version.ts (aktueller Wert: 4).
  • Clients senden minProtocol und maxProtocol; der Server lehnt Bereiche ab, die sein aktuelles Protokoll nicht einschließen.
  • Die Swift-Modelle behalten unbekannte Frame-Typen bei, damit ältere Clients nicht beeinträchtigt werden.

Schemamuster und Konventionen

  • Die meisten Objekte verwenden additionalProperties: false für strikt definierte Payloads.
  • NonEmptyString (Type.String({ minLength: 1 })) ist die Standardeinstellung für IDs und Methoden-/Ereignisnamen.
  • Das übergeordnete GatewayFrame verwendet einen Diskriminator für type.
  • Methoden mit Nebenwirkungen erfordern in den Parametern normalerweise eine idempotencyKey (Beispiel: send, poll, agent, chat.send).
  • agent akzeptiert optional internalEvents für den zur Laufzeit generierten Orchestrierungskontext (zum Beispiel die Übergabe nach Abschluss einer Subagent-/Cron-Aufgabe); behandeln Sie dies als interne API-Oberfläche.

Live-Schema-JSON

Das generierte JSON-Schema ist ein Build-Artefakt und wird nicht in das Repository eingecheckt. Die veröffentlichte Rohdatei ist üblicherweise hier verfügbar:

Wenn Sie Schemas ändern

  1. Aktualisieren Sie die TypeBox-Schemas im zuständigen packages/gateway-protocol/src/schema/*.ts-Modul und registrieren Sie sie in protocol-schemas.ts.
  2. Registrieren Sie die Methode bzw. das Ereignis in src/gateway/server-methods-list.ts.
  3. Aktualisieren Sie src/gateway/method-scopes.ts, wenn der neue RPC eine Bereichsklassifizierung für Operator oder Node benötigt.
  4. Führen Sie pnpm protocol:check aus.
  5. Checken Sie die neu generierten Swift-Modelle ein.

Verwandte Themen

Was this useful?
On this page

On this page