Gateway-Kern
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
openclaw.mjs— Wurzel-Einstieg, nach Node-Versionsprüfung Weiterleitung andist/entry.js.entry.ts main:79-131—main()→runMainOrRootHelpverteilt.run-main Gateway-Hot-Path:159-225—gateway rundirekter dynamischer Import.run-command .action:64-71— Nach Optionsauflösung Aufruf vonrunGatewayCommand.server.ts startGatewayServer:31-40— Dünne Hülle, lazy-load von server.impl.startGatewayServer Implementierung:551-580— Tatsächlicher Start: alte Plugin-Generation aufräumen, Netzwerk-Runtime bootstrappen.coreGatewayHandlers:269— Kern-RPC-Handler-Registry.createRequestGatewayMethodRegistry:598-630— Pro Anfrage Core+Plugin+Extra-Handler zusammenführen.handleGatewayRequest:638-660— Autorisiert und verteilt eine JSON-RPC-Anfrage.createAgentEventHandler:299-320— Broadcastet Agent-Ereignisse an WebSocket-Clients.
Datenfluss
Kern-Startsequenz von startGatewayServer (server.impl.ts:551):
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:
/** 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:
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 einwarngeloggt, der Start nicht blockiert — der Dienst oben zu haben ist wichtiger als sauberes Aufräumen. - Erreichbarkeit heiß registrierter Handler:
handleGatewayRequestfä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_DIRkorrekt 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.