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.