Aller au contenu

TypeBox

Dernière mise à jour : 2026-01-10

TypeBox est une bibliothèque de schémas centrée sur TypeScript. Nous l’utilisons pour définir le protocole WebSocket Gateway (poignée de main, demande/réponse, événements serveur). Ces schémas pilotent la validation à l’exécution, l’exportation JSON Schema et la génération de code Swift pour l’application macOS. Une source de vérité ; tout le reste est généré.

Si vous souhaitez obtenir le contexte de protocole de plus haut niveau, commencez par Architecture de la passerelle.

Chaque message WS Gateway est l’un des trois types de trames :

  • Demande : { type: "req", id, method, params }
  • Réponse : { type: "res", id, ok, payload | error }
  • Événement : { type: "event", event, payload, seq?, stateVersion? }

La première trame doit être une demande connect. Après cela, les clients peuvent appeler des méthodes (ex. health, send, chat.send) et s’abonner à des événements (ex. presence, tick, agent).

Flux de connexion (minimal) :

Client Gateway
|---- req:connect -------->|
|<---- res:hello-ok --------|
|<---- event:tick ----------|
|---- req:health ---------->|
|<---- res:health ----------|

Méthodes courantes + événements :

CatégorieExemplesNotes
Cœurconnect, health, statusconnect doit être en premier
Messageriesend, poll, agent, agent.waitles effets secondaires nécessitent idempotencyKey
Chatchat.history, chat.send, chat.abort, chat.injectWebChat les utilise
Sessionssessions.list, sessions.patch, sessions.deleteadministrateur de session
Nœudsnode.list, node.invoke, node.pair.*Gateway WS + node actions
Événementstick, presence, agent, chat, health, shutdownpush serveur

La liste faisant autorité se trouve dans src/gateway/server.ts (METHODS, EVENTS).

  • Source : src/gateway/protocol/schema.ts
  • Validateurs d’exécution (AJV) : src/gateway/protocol/index.ts
  • Handshake serveur + répartition des méthodes : src/gateway/server.ts
  • Client Node : src/gateway/client.ts
  • Schéma JSON généré : dist/protocol.schema.json
  • Modèles Swift générés : apps/macos/Sources/OpenClawProtocol/GatewayModels.swift
  • pnpm protocol:gen
    • écrit le JSON Schema (draft‑07) dans dist/protocol.schema.json
  • pnpm protocol:gen:swift
    • génère les modèles de passerelle Swift
  • pnpm protocol:check
    • exécute les deux générateurs et vérifie que la sortie est validée

Comment les schémas sont utilisés à l’exécution

Section intitulée « Comment les schémas sont utilisés à l’exécution »
  • Côté serveur : chaque trame entrante est validée avec AJV. Le handshake n’accepte qu’une requête connect dont les paramètres correspondent à ConnectParams.
  • Côté client : le client JS valide les trames d’événement et de réponse avant de les utiliser.
  • Surface de méthodes : le Gateway annonce les methods et events pris en charge dans hello-ok.

Connexion (premier message) :

{
"type": "req",
"id": "c1",
"method": "connect",
"params": {
"minProtocol": 2,
"maxProtocol": 2,
"client": {
"id": "openclaw-macos",
"displayName": "macos",
"version": "1.0.0",
"platform": "macos 15.1",
"mode": "ui",
"instanceId": "A1B2"
}
}
}

Réponse Hello-ok :

{
"type": "res",
"id": "c1",
"ok": true,
"payload": {
"type": "hello-ok",
"protocol": 2,
"server": { "version": "dev", "connId": "ws-1" },
"features": { "methods": ["health"], "events": ["tick"] },
"snapshot": {
"presence": [],
"health": {},
"stateVersion": { "presence": 0, "health": 0 },
"uptimeMs": 0
},
"policy": { "maxPayload": 1048576, "maxBufferedBytes": 1048576, "tickIntervalMs": 30000 }
}
}

Requête + réponse :

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

Événement :

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

Plus petit flux utile : connexion + santé.

import { WebSocket } from "ws";
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: 3,
maxProtocol: 3,
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();
}
});

Exemple pratique : ajouter une méthode de bout en bout

Section intitulée « Exemple pratique : ajouter une méthode de bout en bout »

Exemple : ajouter une nouvelle requête system.echo qui renvoie { ok: true, text }.

  1. Schéma (source de vérité)

Ajouter à src/gateway/protocol/schema.ts :

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

Ajouter les deux à ProtocolSchemas et exporter les types :

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

Dans src/gateway/protocol/index.ts, exporter un validateur AJV :

export const validateSystemEchoParams = ajv.compile<SystemEchoParams>(SystemEchoParamsSchema);
  1. Comportement du serveur

Ajoutez un gestionnaire dans src/gateway/server-methods/system.ts :

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

Inscrivez-le dans src/gateway/server-methods.ts (fusionne déjà systemHandlers), puis ajoutez "system.echo" à METHODS dans src/gateway/server.ts.

  1. Régénérer
Fenêtre de terminal
pnpm protocol:check
  1. Tests + documentation

Ajoutez un test serveur dans src/gateway/server.*.test.ts et notez la méthode dans la documentation.

Le générateur Swift émet :

  • énumération GatewayFrame avec les cas req, res, event et unknown
  • Structures/énumérations de charge utile fortement typées
  • valeurs ErrorCode et GATEWAY_PROTOCOL_VERSION

Les types de trames inconnus sont conservés sous forme de charges utiles brutes pour assurer la compatibilité ascendante.

  • PROTOCOL_VERSION réside dans src/gateway/protocol/schema.ts.
  • Les clients envoient minProtocol + maxProtocol ; le serveur rejette les incohérences.
  • Les modèles Swift conservent les types de trames inconnus pour éviter de casser les anciens clients.
  • La plupart des objets utilisent additionalProperties: false pour les charges utiles strictes.
  • NonEmptyString est la valeur par défaut pour les ID et les noms de méthodes/événements.
  • L’GatewayFrame de niveau supérieur utilise un discriminant sur type.
  • Les méthodes ayant des effets secondaires nécessitent généralement un idempotencyKey dans les paramètres (exemple : send, poll, agent, chat.send).
  • agent accepte un internalEvents optionnel pour le contexte d’orchestration généré à l’exécution (par exemple, transfert lors de l’achèvement d’une tâche de sous-agent/cron) ; traitez cela comme une surface de API interne.

Le JSON Schema généré se trouve dans le dépôt à dist/protocol.schema.json. Le fichier brut publié est généralement disponible à l’adresse :

  1. Mettez à jour les schémas TypeBox.
  2. Exécutez pnpm protocol:check.
  3. Validez le schéma régénéré + les modèles Swift.