Skip to content

Gateway-Kern ​

源码版本v2026.6.11

Verantwortung ​

startGatewayServer ist der Einstieg des residenten Prozesses von OpenClaw: Port binden, Plugins laden, RPC-Methoden registrieren, Agent-Ereignisse broadcasten. Alle Kanalnachrichten, ACP-Anfragen und Web-Clients verbinden sich mit diesem Gateway, das die Anfragen an die Agent-Hauptschleife weiterreicht und die vom Agenten erzeugten Ereignisse an alle Clients broadcastet.

Das Gateway „denkt" selbst nicht — es macht nur empfangen, weiterleiten, broadcasten (broadcast): JSON-RPC-Anfragen empfangen, an den zuständigen Handler (viele landen letztlich beim Agenten) weiterleiten und Agent-Ereignisse an alle Verbindungen broadcasten, die diese Sitzung abonniert haben.

Designmotivation ​

Warum das Gateway als residenten Prozess auslagern? Weil OpenClaw gleichzeitig an 22 Kanälen hängt, von denen die meisten Langverbindungen (WebSocket/Polling) brauchen. Würde für jede Nachricht ein kurzlebiger Prozess gestartet, würden Handshake-Kosten und Zustandswiederherstellung das Design überlasten. Ein residentes Gateway teilt alle Kanalverbindungen, alle Agent-Sitzungen und allen Plugin-Zustand in einem Prozess; schichtübergreifende Koordination (z. B. Kanal A löst Agent-Aufruf aus, Werkzeugergebnis soll an Kanal B geliefert werden) ist dann nur ein prozessinterner Funktionsaufruf.

Schlüsseldateien ​

Datenfluss ​

Kern-Startsequenz von startGatewayServer (server.impl.ts:551):

typescript
export async function startGatewayServer(
  port = 18789,
  opts: GatewayServerOptions = {},
): Promise<GatewayServer> {
  normalizeStateDirEnv(process.env);
  // Aufräumen alter Plugin-Generationen aus vorherigem Restart, für sauberen Zustand zwischen Restarts
  const installRecords = loadInstalledPluginIndexInstallRecordsSync();
  const removedGenerations = await cleanupRetiredManagedNpmInstallGenerations({
    activeInstallPaths: Object.values(installRecords).flatMap((record) =>
      record.installPath ? [record.installPath] : [],
    ),
    onError: (error, projectRoot) =>
      log.warn(`failed to clean retained npm generation ${projectRoot}: ${String(error)}`),
  });
  const { bootstrapGatewayNetworkRuntime } = await import("./server-network-runtime.js");
  bootstrapGatewayNetworkRuntime();

Beachten Sie den Standardport 18789 und dass die erste Aktion beim Start das Aufräumen alter Plugin-NPM-Generationen ist — das ist für In-Process-Restarts ausgelegt: Beim Gateway-Restart werden zuerst die Plugin-Ressourcen der vorherigen Runde recycelt, um Lecks zu vermeiden.

Anfrageverteilung (handleGatewayRequest:638) über JSON-RPC:

typescript
/** Authorizes and dispatches one gateway JSON-RPC-style request. */
export async function handleGatewayRequest(
  opts: GatewayRequestOptions & { extraHandlers?: GatewayRequestHandlers },
): Promise<void> {
  const { req, respond, client, isWebchatConnect, context } = opts;
  // Bevorzugt die vom Aufrufer mitgegebene Registry (wenn sie die Methode hält),
  // sonst Neuaufbau aus der Live-Plugin-Registry, damit Plugin-RPC-Methoden,
  // die nach dem Start-Snapshot registriert wurden, erreichbar bleiben (#94127)

Die Handler-Registry wird pro Anfrage neu aufgebaut (createRequestGatewayMethodRegistry:598): Core-Handler, aktuell aktivierte Plugin-Handler und Extra-Handler des Aufrufers werden zusammengeführt. So können Plugins RPC-Methoden heiß registrieren, ohne das Gateway neu zu starten.

Agent-Ereignis-Broadcast (createAgentEventHandler:299) injiziert drei Primitive:

typescript
export function createAgentEventHandler({
  broadcast,              // An alle Verbindungen broadcasten, die diese Sitzung abonniert haben
  broadcastToConnIds,     // Gezielt an bestimmte Verbindungen broadcasten
  nodeSendToSession,      // Knotenübergreifend an eine Sitzung liefern
  agentRunSeq,
  chatRunState,
  resolveSessionKeyForRun,
  ...

broadcast und broadcastToConnIds werden von createGatewayNodeSessionRuntime in server.impl.ts:971 injiziert und durchziehen die gesamte Gateway-Lebensdauer.

Grenzen und Fehler ​

  • In-Process-Restart: Beim Gateway-Restart werden zuerst alte Plugin-NPM-Generationen aufgeräumt (src/gateway/server.impl.ts:560); schlägt das Aufräumen fehl, wird nur ein warn geloggt, der Start nicht blockiert — der Dienst oben zu haben ist wichtiger als sauberes Aufräumen.
  • Erreichbarkeit heiß registrierter Handler: handleGatewayRequest fällt auf den Live-Registry-Neuaufbau zurück, wenn der Aufrufer-Snapshot die Methode nicht hält; behebt #94127 — sonst wären heiß registrierte Plugin-RPCs nach dem Start „unsichtbar".
  • Zustandsverzeichnis: Beim Start zunächst normalizeStateDirEnv(process.env), damit $OPENCLAW_STATE_DIR korrekt aufgelöst wird; sonst würden Konfigurations- und Workspace-Pfade verrutschen.
  • Netzwerk-Runtime: bootstrapGatewayNetworkRuntime() wird vor dem Laden der Netzwerkschicht aufgerufen; falsche Reihenfolge führt zu nicht bereiten WebSocket-Kanälen.

Zusammenfassung ​

Das Gateway macht nur die drei Dinge empfangen, weiterleiten, broadcasten — aber jede einzelne ist für „resident + Multi-Kanal + heiß austauschbar" ausgelegt: Aufräumen beim Start, Handler-Neuaufbau pro Anfrage, injizierte Broadcast-Primitive. Was tatsächlich „denkt", ist die Agent-Hauptschleife; wie Anfragen autorisiert verteilt werden, siehe RPC-Methodentabelle; wie Ereignisse zu den Clients gelangen, siehe Chat-Broadcast.

Vergleich mit offiziellen Ressourcen: Gateway-Doku · README.