diff --git a/docs/de/concepts/active-memory.md b/docs/de/concepts/active-memory.md
index 9f7d130fe..05c084a62 100644
--- a/docs/de/concepts/active-memory.md
+++ b/docs/de/concepts/active-memory.md
@@ -1,36 +1,36 @@
---
read_when:
- - Sie möchten verstehen, wofür Active Memory gedacht ist
- - Sie möchten Active Memory für einen Konversationsagenten aktivieren
- - Sie möchten das Verhalten von Active Memory anpassen, ohne es überall zu aktivieren
+ - Sie möchten verstehen, wofür Active Memory gedacht ist.
+ - Sie möchten Active Memory für einen Konversationsagenten aktivieren.
+ - Sie möchten das Verhalten von Active Memory anpassen, ohne es überall zu aktivieren.
summary: Ein Plugin-eigener blockierender Speicher-Sub-Agent, der relevante Erinnerungen in interaktive Chat-Sitzungen einspeist
title: Active Memory
x-i18n:
- generated_at: "2026-04-14T02:08:44Z"
+ generated_at: "2026-04-16T06:22:27Z"
model: gpt-5.4
provider: openai
- source_hash: b151e9eded7fc5c37e00da72d95b24c1dc94be22e855c8875f850538392b0637
+ source_hash: ab36c5fea1578348cc2258ea3b344cc7bdc814f337d659cdb790512b3ea45473
source_path: concepts/active-memory.md
workflow: 15
---
# Active Memory
-Active Memory ist ein optionaler Plugin-eigener blockierender Speicher-Sub-Agent, der
+Active Memory ist ein optionaler, Plugin-eigener blockierender Speicher-Sub-Agent, der
vor der Hauptantwort für geeignete Konversationssitzungen ausgeführt wird.
Er existiert, weil die meisten Speichersysteme leistungsfähig, aber reaktiv sind. Sie verlassen sich darauf,
-dass der Haupt-Agent entscheidet, wann der Speicher durchsucht werden soll, oder darauf, dass der Benutzer Dinge sagt
-wie „merke dir das“ oder „durchsuche den Speicher“. Bis dahin ist der Moment, in dem der Speicher
-die Antwort natürlich hätte wirken lassen, bereits verstrichen.
+dass der Hauptagent entscheidet, wann der Speicher durchsucht werden soll, oder darauf, dass der Benutzer Dinge sagt
+wie „Merke dir das“ oder „Durchsuche den Speicher“. Zu diesem Zeitpunkt ist der Moment, in dem der Speicher
+die Antwort natürlich hätte wirken lassen, bereits vorbei.
Active Memory gibt dem System eine begrenzte Gelegenheit, relevanten Speicherinhalt anzuzeigen,
bevor die Hauptantwort generiert wird.
## Fügen Sie dies in Ihren Agenten ein
-Fügen Sie dies in Ihren Agenten ein, wenn Sie Active Memory mit einer
-eigenständigen, standardmäßig sicheren Konfiguration aktivieren möchten:
+Fügen Sie dies in Ihren Agenten ein, wenn Sie möchten, dass er Active Memory mit einer
+eigenständigen Konfiguration mit sicheren Standardwerten aktiviert:
```json5
{
@@ -56,9 +56,9 @@ eigenständigen, standardmäßig sicheren Konfiguration aktivieren möchten:
}
```
-Dadurch wird das Plugin für den Agenten `main` aktiviert, standardmäßig auf Sitzungen im Stil von Direktnachrichten
-beschränkt, lässt es zuerst das aktuelle Sitzungsmodell erben und verwendet
-das konfigurierte Fallback-Modell nur dann, wenn kein explizites oder geerbtes Modell verfügbar ist.
+Dadurch wird das Plugin für den Agenten `main` aktiviert, standardmäßig auf Sitzungen
+im Stil von Direktnachrichten beschränkt, es kann zunächst das aktuelle Sitzungsmodell übernehmen und
+verwendet das konfigurierte Fallback-Modell nur, wenn kein explizites oder übernommenes Modell verfügbar ist.
Starten Sie danach das Gateway neu:
@@ -66,7 +66,7 @@ Starten Sie danach das Gateway neu:
openclaw gateway
```
-So prüfen Sie es live in einer Konversation:
+Um es live in einer Unterhaltung zu prüfen:
```text
/verbose on
@@ -78,8 +78,8 @@ So prüfen Sie es live in einer Konversation:
Die sicherste Einrichtung ist:
1. das Plugin aktivieren
-2. einen Konversationsagenten festlegen
-3. die Protokollierung nur während der Feinabstimmung aktiviert lassen
+2. einen Konversationsagenten als Ziel festlegen
+3. Logging nur während der Anpassung aktiviert lassen
Beginnen Sie mit Folgendem in `openclaw.json`:
@@ -116,17 +116,102 @@ Das bedeutet:
- `plugins.entries.active-memory.enabled: true` aktiviert das Plugin
- `config.agents: ["main"]` aktiviert Active Memory nur für den Agenten `main`
-- `config.allowedChatTypes: ["direct"]` sorgt standardmäßig dafür, dass Active Memory nur für Sitzungen im Stil von Direktnachrichten aktiv ist
-- wenn `config.model` nicht gesetzt ist, erbt Active Memory zuerst das aktuelle Sitzungsmodell
-- `config.modelFallback` stellt optional Ihren eigenen Fallback-Anbieter bzw. Ihr eigenes Fallback-Modell für die Erinnerung bereit
+- `config.allowedChatTypes: ["direct"]` hält Active Memory standardmäßig nur für Sitzungen im Stil von Direktnachrichten aktiv
+- wenn `config.model` nicht gesetzt ist, übernimmt Active Memory zunächst das aktuelle Sitzungsmodell
+- `config.modelFallback` stellt optional Ihr eigenes Fallback-Anbieter-/Modell für den Abruf bereit
- `config.promptStyle: "balanced"` verwendet den allgemeinen Standard-Prompt-Stil für den Modus `recent`
-- Active Memory wird weiterhin nur für geeignete interaktive persistente Chat-Sitzungen ausgeführt
+- Active Memory wird weiterhin nur in geeigneten interaktiven persistenten Chat-Sitzungen ausgeführt
-## So sehen Sie es
+## Empfehlungen zur Geschwindigkeit
-Active Memory injiziert ein verborgenes, nicht vertrauenswürdiges Prompt-Präfix für das Modell. Es
+Die einfachste Einrichtung besteht darin, `config.model` nicht zu setzen und Active Memory
+dasselbe Modell verwenden zu lassen, das Sie bereits für normale Antworten verwenden. Das ist der sicherste Standard,
+weil dabei Ihre vorhandenen Anbieter-, Authentifizierungs- und Modellpräferenzen übernommen werden.
+
+Wenn Sie möchten, dass sich Active Memory schneller anfühlt, verwenden Sie ein dediziertes Inferenzmodell,
+anstatt das Haupt-Chat-Modell zu übernehmen.
+
+Beispiel für eine Einrichtung mit schnellem Anbieter:
+
+```json5
+models: {
+ providers: {
+ cerebras: {
+ baseUrl: "https://api.cerebras.ai/v1",
+ apiKey: "${CEREBRAS_API_KEY}",
+ api: "openai-completions",
+ models: [{ id: "gpt-oss-120b", name: "GPT OSS 120B (Cerebras)" }],
+ },
+ },
+},
+plugins: {
+ entries: {
+ "active-memory": {
+ enabled: true,
+ config: {
+ model: "cerebras/gpt-oss-120b",
+ },
+ },
+ },
+}
+```
+
+Schnelle Modelloptionen, die in Betracht gezogen werden sollten:
+
+- `cerebras/gpt-oss-120b` für ein schnelles dediziertes Abrufmodell mit einer schmalen Tool-Oberfläche
+- Ihr normales Sitzungsmodell, indem Sie `config.model` nicht setzen
+- ein Fallback-Modell mit geringer Latenz wie `google/gemini-3-flash`, wenn Sie ein separates Abrufmodell möchten, ohne Ihr primäres Chat-Modell zu ändern
+
+Warum Cerebras eine starke geschwindigkeitsorientierte Option für Active Memory ist:
+
+- die Tool-Oberfläche von Active Memory ist schmal: Es ruft nur `memory_search` und `memory_get` auf
+- die Qualität des Abrufs ist wichtig, aber die Latenz ist wichtiger als beim Hauptantwortpfad
+- ein dedizierter schneller Anbieter vermeidet es, die Latenz des Speicherabrufs an Ihren primären Chat-Anbieter zu koppeln
+
+Wenn Sie kein separates geschwindigkeitsoptimiertes Modell möchten, lassen Sie `config.model` ungesetzt
+und lassen Sie Active Memory das aktuelle Sitzungsmodell übernehmen.
+
+### Cerebras-Einrichtung
+
+Fügen Sie einen Anbietereintrag wie diesen hinzu:
+
+```json5
+models: {
+ providers: {
+ cerebras: {
+ baseUrl: "https://api.cerebras.ai/v1",
+ apiKey: "${CEREBRAS_API_KEY}",
+ api: "openai-completions",
+ models: [{ id: "gpt-oss-120b", name: "GPT OSS 120B (Cerebras)" }],
+ },
+ },
+}
+```
+
+Richten Sie Active Memory dann darauf aus:
+
+```json5
+plugins: {
+ entries: {
+ "active-memory": {
+ enabled: true,
+ config: {
+ model: "cerebras/gpt-oss-120b",
+ },
+ },
+ },
+}
+```
+
+Hinweis:
+
+- stellen Sie sicher, dass der Cerebras-API-Schlüssel tatsächlich Modellzugriff für das von Ihnen gewählte Modell hat, da die Sichtbarkeit von `/v1/models` allein keinen Zugriff auf `chat/completions` garantiert
+
+## Wie man es sieht
+
+Active Memory fügt für das Modell ein verborgenes nicht vertrauenswürdiges Prompt-Präfix ein. Es
zeigt keine rohen `...`-Tags in der
-normalen, für den Client sichtbaren Antwort an.
+normalen für den Client sichtbaren Antwort an.
## Sitzungsumschaltung
@@ -139,8 +224,8 @@ aktuelle Chat-Sitzung pausieren oder fortsetzen möchten, ohne die Konfiguration
/active-memory on
```
-Dies gilt nur für die Sitzung. Es ändert nicht
-`plugins.entries.active-memory.enabled`, die Agentenauswahl oder andere globale
+Dies gilt für die Sitzung. Es ändert nicht
+`plugins.entries.active-memory.enabled`, die Agentenzuordnung oder andere globale
Konfigurationen.
Wenn der Befehl in die Konfiguration schreiben und Active Memory für
@@ -153,11 +238,11 @@ alle Sitzungen pausieren oder fortsetzen soll, verwenden Sie die explizite globa
```
Die globale Form schreibt `plugins.entries.active-memory.config.enabled`. Dabei bleibt
-`plugins.entries.active-memory.enabled` aktiviert, damit der Befehl verfügbar bleibt, um
-Active Memory später wieder zu aktivieren.
+`plugins.entries.active-memory.enabled` aktiviert, sodass der Befehl verfügbar bleibt, um
+Active Memory später wieder einzuschalten.
Wenn Sie sehen möchten, was Active Memory in einer Live-Sitzung macht, aktivieren Sie die
-Sitzungsumschaltungen, die der gewünschten Ausgabe entsprechen:
+Sitzungsumschalter, die zu der gewünschten Ausgabe passen:
```text
/verbose on
@@ -170,12 +255,12 @@ Wenn diese aktiviert sind, kann OpenClaw Folgendes anzeigen:
- eine lesbare Debug-Zusammenfassung wie `Active Memory Debug: Lemon pepper wings with blue cheese.`, wenn `/trace on`
Diese Zeilen stammen aus demselben Active-Memory-Durchlauf, der das verborgene
-Prompt-Präfix speist, sind aber für Menschen formatiert, anstatt rohe Prompt-Markup-Strukturen offenzulegen.
-Sie werden als diagnostische Folgenachricht nach der normalen
-Assistentenantwort gesendet, sodass Kanal-Clients wie Telegram keine separate
-Diagnoseblase vor der Antwort anzeigen.
+Prompt-Präfix speist, sind aber für Menschen formatiert, anstatt rohe Prompt-
+Auszeichnung anzuzeigen. Sie werden als Diagnose-Folgenachricht nach der normalen
+Assistentenantwort gesendet, damit Kanal-Clients wie Telegram keine separate
+Diagnose-Sprechblase vor der Antwort aufblinken lassen.
-Wenn Sie zusätzlich `/trace raw` aktivieren, zeigt der nachverfolgte Block `Model Input (User Role)`
+Wenn Sie zusätzlich `/trace raw` aktivieren, zeigt der verfolgte Block `Model Input (User Role)`
das verborgene Active-Memory-Präfix wie folgt an:
```text
@@ -207,16 +292,16 @@ Erwartete sichtbare Antwortform:
## Wann es ausgeführt wird
-Active Memory verwendet zwei Schranken:
+Active Memory verwendet zwei Gate-Prüfungen:
1. **Konfigurations-Opt-in**
Das Plugin muss aktiviert sein, und die aktuelle Agenten-ID muss in
`plugins.entries.active-memory.config.agents` enthalten sein.
-2. **Strenge Laufzeit-Eignung**
- Selbst wenn es aktiviert und als Ziel festgelegt ist, wird Active Memory nur für geeignete
+2. **Strikte Laufzeitberechtigung**
+ Auch wenn es aktiviert ist und als Ziel festgelegt wurde, wird Active Memory nur für geeignete
interaktive persistente Chat-Sitzungen ausgeführt.
-Die tatsächliche Regel ist:
+Die tatsächliche Regel lautet:
```text
plugin enabled
@@ -234,8 +319,8 @@ Wenn eine dieser Bedingungen fehlschlägt, wird Active Memory nicht ausgeführt.
## Sitzungstypen
-`config.allowedChatTypes` steuert, welche Arten von Konversationen Active
-Memory überhaupt ausführen dürfen.
+`config.allowedChatTypes` steuert, in welchen Arten von Unterhaltungen Active
+Memory überhaupt ausgeführt werden darf.
Der Standardwert ist:
@@ -243,8 +328,8 @@ Der Standardwert ist:
allowedChatTypes: ["direct"]
```
-Das bedeutet, dass Active Memory standardmäßig in Sitzungen im Stil von Direktnachrichten ausgeführt wird,
-aber nicht in Gruppen- oder Kanalsitzungen, sofern Sie diese nicht ausdrücklich aktivieren.
+Das bedeutet, dass Active Memory standardmäßig in Sitzungen im Stil von Direktnachrichten ausgeführt wird, aber
+nicht in Gruppen- oder Kanalsitzungen, es sei denn, Sie aktivieren diese ausdrücklich.
Beispiele:
@@ -262,23 +347,23 @@ allowedChatTypes: ["direct", "group", "channel"]
## Wo es ausgeführt wird
-Active Memory ist eine Funktion zur Anreicherung von Konversationen, keine
-plattformweite Inferenzfunktion.
+Active Memory ist eine Funktion zur Anreicherung von Konversationen, keine plattformweite
+Inferenzfunktion.
-| Oberfläche | Führt Active Memory aus? |
-| ------------------------------------------------------------------- | ------------------------------------------------------- |
-| Control UI / persistente Web-Chat-Sitzungen | Ja, wenn das Plugin aktiviert ist und der Agent ausgewählt ist |
-| Andere interaktive Kanal-Sitzungen auf demselben persistenten Chat-Pfad | Ja, wenn das Plugin aktiviert ist und der Agent ausgewählt ist |
-| Headless-Einmalläufe | Nein |
-| Heartbeat-/Hintergrundläufe | Nein |
-| Generische interne `agent-command`-Pfade | Nein |
-| Sub-Agent-/interne Hilfsausführung | Nein |
+| Surface | Active Memory wird ausgeführt? |
+| ------------------------------------------------------------------- | -------------------------------------------------------- |
+| Persistente Sitzungen in der Control UI / im Web-Chat | Ja, wenn das Plugin aktiviert ist und der Agent als Ziel festgelegt ist |
+| Andere interaktive Kanalsitzungen auf demselben persistenten Chat-Pfad | Ja, wenn das Plugin aktiviert ist und der Agent als Ziel festgelegt ist |
+| Headless-Einmalläufe | Nein |
+| Heartbeat-/Hintergrundläufe | Nein |
+| Generische interne `agent-command`-Pfade | Nein |
+| Ausführung von Sub-Agenten/internen Hilfen | Nein |
-## Warum Sie es verwenden sollten
+## Warum es verwenden
Verwenden Sie Active Memory, wenn:
-- die Sitzung persistent und benutzerseitig ist
+- die Sitzung persistent und benutzergerichtet ist
- der Agent über sinnvollen Langzeitspeicher verfügt, der durchsucht werden kann
- Kontinuität und Personalisierung wichtiger sind als reine Prompt-Deterministik
@@ -286,16 +371,16 @@ Es funktioniert besonders gut für:
- stabile Präferenzen
- wiederkehrende Gewohnheiten
-- langfristigen Benutzerkontext, der natürlich auftauchen sollte
+- langfristigen Benutzerkontext, der natürlich angezeigt werden soll
Es ist ungeeignet für:
- Automatisierung
- interne Worker
- einmalige API-Aufgaben
-- Orte, an denen verborgene Personalisierung überraschend wäre
+- Stellen, an denen verborgene Personalisierung überraschend wäre
-## Funktionsweise
+## Wie es funktioniert
Die Laufzeitform ist:
@@ -317,7 +402,7 @@ Wenn die Verbindung schwach ist, sollte er `NONE` zurückgeben.
## Abfragemodi
-`config.queryMode` steuert, wie viel der Konversation der blockierende Speicher-Sub-Agent sieht.
+`config.queryMode` steuert, wie viel Unterhaltung der blockierende Speicher-Sub-Agent sieht.
## Prompt-Stile
@@ -327,9 +412,9 @@ wenn er entscheidet, ob Speicherinhalt zurückgegeben werden soll.
Verfügbare Stile:
- `balanced`: allgemeiner Standard für den Modus `recent`
-- `strict`: am wenigsten bereitwillig; am besten geeignet, wenn Sie sehr wenig Übertragung aus nahem Kontext möchten
-- `contextual`: am freundlichsten für Kontinuität; am besten geeignet, wenn der Konversationsverlauf wichtiger sein soll
-- `recall-heavy`: eher bereit, Speicher auch bei schwächeren, aber noch plausiblen Übereinstimmungen anzuzeigen
+- `strict`: am wenigsten bereitwillig; am besten, wenn Sie sehr wenig Übergreifen aus nahem Kontext möchten
+- `contextual`: am stärksten auf Kontinuität ausgerichtet; am besten, wenn der Unterhaltungsverlauf stärker ins Gewicht fallen soll
+- `recall-heavy`: eher bereit, Speicherinhalt auch bei schwächeren, aber dennoch plausiblen Übereinstimmungen anzuzeigen
- `precision-heavy`: bevorzugt aggressiv `NONE`, sofern die Übereinstimmung nicht offensichtlich ist
- `preference-only`: optimiert für Favoriten, Gewohnheiten, Routinen, Geschmack und wiederkehrende persönliche Fakten
@@ -349,7 +434,7 @@ Beispiel:
promptStyle: "preference-only"
```
-## Richtlinie für Modell-Fallbacks
+## Modell-Fallback-Richtlinie
Wenn `config.model` nicht gesetzt ist, versucht Active Memory, ein Modell in dieser Reihenfolge aufzulösen:
@@ -368,52 +453,52 @@ Optionales benutzerdefiniertes Fallback:
modelFallback: "google/gemini-3-flash"
```
-Wenn kein explizites, geerbtes oder konfiguriertes Fallback-Modell aufgelöst werden kann, überspringt Active Memory
-die Erinnerung für diesen Zug.
+Wenn kein explizites, übernommenes oder konfiguriertes Fallback-Modell aufgelöst werden kann, überspringt Active Memory
+den Abruf für diesen Zug.
`config.modelFallbackPolicy` wird nur noch als veraltetes Kompatibilitätsfeld
-für ältere Konfigurationen beibehalten. Es ändert das Laufzeitverhalten nicht mehr.
+für ältere Konfigurationen beibehalten. Es verändert das Laufzeitverhalten nicht mehr.
-## Erweiterte Ausweichmöglichkeiten
+## Erweiterte Escape-Hatches
Diese Optionen sind absichtlich nicht Teil der empfohlenen Einrichtung.
-`config.thinking` kann die Thinking-Stufe des blockierenden Speicher-Sub-Agenten überschreiben:
+`config.thinking` kann die Denkstufe des blockierenden Speicher-Sub-Agenten überschreiben:
```json5
thinking: "medium"
```
-Standardwert:
+Standard:
```json5
thinking: "off"
```
Aktivieren Sie dies nicht standardmäßig. Active Memory läuft im Antwortpfad, daher erhöht zusätzliche
-Thinking-Zeit direkt die für Benutzer sichtbare Latenz.
+Denkzeit direkt die für Benutzer sichtbare Latenz.
-`config.promptAppend` fügt zusätzliche Operator-Anweisungen nach dem standardmäßigen Active-
-Memory-Prompt und vor dem Konversationskontext hinzu:
+`config.promptAppend` fügt nach dem Standard-Prompt von Active Memory und vor dem Unterhaltungskontext
+zusätzliche Operator-Anweisungen hinzu:
```json5
-promptAppend: "Prefer stable long-term preferences over one-off events."
+promptAppend: "Bevorzuge stabile langfristige Präferenzen gegenüber einmaligen Ereignissen."
```
-`config.promptOverride` ersetzt den standardmäßigen Active-Memory-Prompt. OpenClaw
-hängt danach weiterhin den Konversationskontext an:
+`config.promptOverride` ersetzt den Standard-Prompt von Active Memory. OpenClaw
+hängt den Unterhaltungskontext danach weiterhin an:
```json5
promptOverride: "You are a memory search agent. Return NONE or one compact user fact."
```
-Eine Prompt-Anpassung wird nicht empfohlen, es sei denn, Sie testen bewusst einen
-anderen Erinnerungsvertrag. Der Standard-Prompt ist darauf abgestimmt, entweder `NONE`
-oder kompakten Benutzerfakt-Kontext für das Hauptmodell zurückzugeben.
+Eine Anpassung des Prompts wird nicht empfohlen, es sei denn, Sie testen bewusst einen
+anderen Abrufvertrag. Der Standard-Prompt ist darauf abgestimmt, entweder `NONE`
+oder kompakten Benutzerfakten-Kontext für das Hauptmodell zurückzugeben.
### `message`
-Es wird nur die neueste Benutzernachricht gesendet.
+Es wird nur die letzte Benutzernachricht gesendet.
```text
Latest user message only
@@ -422,16 +507,16 @@ Latest user message only
Verwenden Sie dies, wenn:
- Sie das schnellste Verhalten möchten
-- Sie die stärkste Ausrichtung auf die Erinnerung stabiler Präferenzen möchten
-- Folgezüge keinen Konversationskontext benötigen
+- Sie die stärkste Ausrichtung auf den Abruf stabiler Präferenzen möchten
+- Folgezüge keinen Unterhaltungskontext benötigen
-Empfohlener Timeout:
+Empfohlenes Timeout:
- beginnen Sie bei etwa `3000` bis `5000` ms
### `recent`
-Die neueste Benutzernachricht plus ein kleiner aktueller Konversationsverlauf werden gesendet.
+Die letzte Benutzernachricht plus ein kleiner aktueller Unterhaltungsausschnitt wird gesendet.
```text
Recent conversation tail:
@@ -445,16 +530,16 @@ Latest user message:
Verwenden Sie dies, wenn:
-- Sie ein besseres Gleichgewicht zwischen Geschwindigkeit und konversationeller Verankerung möchten
-- Rückfragen häufig von den letzten wenigen Zügen abhängen
+- Sie ein besseres Gleichgewicht zwischen Geschwindigkeit und Gesprächsverankerung möchten
+- Folgefragen oft von den letzten wenigen Zügen abhängen
-Empfohlener Timeout:
+Empfohlenes Timeout:
- beginnen Sie bei etwa `15000` ms
### `full`
-Die vollständige Konversation wird an den blockierenden Speicher-Sub-Agenten gesendet.
+Die vollständige Unterhaltung wird an den blockierenden Speicher-Sub-Agenten gesendet.
```text
Full conversation context:
@@ -466,15 +551,15 @@ user: ...
Verwenden Sie dies, wenn:
-- die bestmögliche Erinnerungsqualität wichtiger ist als Latenz
-- die Konversation wichtige Einrichtungsschritte weit oben im Verlauf enthält
+- die bestmögliche Abrufqualität wichtiger ist als die Latenz
+- die Unterhaltung wichtige Vorbereitung weit oben im Thread enthält
-Empfohlener Timeout:
+Empfohlenes Timeout:
-- erhöhen Sie ihn im Vergleich zu `message` oder `recent` deutlich
-- beginnen Sie bei etwa `15000` ms oder höher, je nach Größe des Threads
+- erhöhen Sie es deutlich im Vergleich zu `message` oder `recent`
+- beginnen Sie bei etwa `15000` ms oder höher, abhängig von der Thread-Größe
-Im Allgemeinen sollte der Timeout mit der Kontextgröße steigen:
+Im Allgemeinen sollte das Timeout mit der Kontextgröße zunehmen:
```text
message < recent < full
@@ -482,9 +567,8 @@ message < recent < full
## Transkriptpersistenz
-Läufe des blockierenden Speicher-Sub-Agenten von Active Memory erzeugen während des
-Aufrufs des blockierenden Speicher-Sub-Agenten ein echtes `session.jsonl`-
-Transkript.
+Durchläufe des blockierenden Speicher-Sub-Agenten von Active Memory erzeugen während des Aufrufs des blockierenden Speicher-Sub-Agenten
+ein echtes `session.jsonl`-Transkript.
Standardmäßig ist dieses Transkript temporär:
@@ -492,8 +576,8 @@ Standardmäßig ist dieses Transkript temporär:
- es wird nur für den Lauf des blockierenden Speicher-Sub-Agenten verwendet
- es wird sofort gelöscht, nachdem der Lauf abgeschlossen ist
-Wenn Sie diese Transkripte des blockierenden Speicher-Sub-Agenten zur Fehlerdiagnose oder
-Inspektion auf dem Datenträger behalten möchten, aktivieren Sie die Persistenz ausdrücklich:
+Wenn Sie diese Transkripte des blockierenden Speicher-Sub-Agenten zur Fehlersuche oder
+Prüfung auf der Festplatte behalten möchten, aktivieren Sie die Persistenz ausdrücklich:
```json5
{
@@ -513,9 +597,9 @@ Inspektion auf dem Datenträger behalten möchten, aktivieren Sie die Persistenz
```
Wenn aktiviert, speichert Active Memory Transkripte in einem separaten Verzeichnis unter dem
-Sitzungsordner des Ziel-Agenten, nicht im Haupttranskriptpfad der Benutzerkonversation.
+Sitzungsordner des Zielagenten, nicht im Haupttranskriptpfad der Benutzerunterhaltung.
-Das Standardlayout sieht konzeptionell so aus:
+Das Standardlayout ist konzeptionell:
```text
agents//sessions/active-memory/.jsonl
@@ -523,10 +607,10 @@ agents//sessions/active-memory/.jso
Sie können das relative Unterverzeichnis mit `config.transcriptDir` ändern.
-Verwenden Sie dies mit Bedacht:
+Verwenden Sie dies mit Vorsicht:
-- Transkripte des blockierenden Speicher-Sub-Agenten können sich in ausgelasteten Sitzungen schnell ansammeln
-- der Abfragemodus `full` kann viel Konversationskontext duplizieren
+- Transkripte des blockierenden Speicher-Sub-Agenten können sich bei ausgelasteten Sitzungen schnell ansammeln
+- der Abfragemodus `full` kann viel Unterhaltungskontext duplizieren
- diese Transkripte enthalten verborgenen Prompt-Kontext und abgerufene Erinnerungen
## Konfiguration
@@ -539,32 +623,32 @@ plugins.entries.active-memory
Die wichtigsten Felder sind:
-| Schlüssel | Typ | Bedeutung |
-| --------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
-| `enabled` | `boolean` | Aktiviert das Plugin selbst |
-| `config.agents` | `string[]` | Agenten-IDs, die Active Memory verwenden dürfen |
-| `config.model` | `string` | Optionale Modellreferenz für den blockierenden Speicher-Sub-Agenten; wenn nicht gesetzt, verwendet Active Memory das aktuelle Sitzungsmodell |
-| `config.queryMode` | `"message" \| "recent" \| "full"` | Steuert, wie viel der Konversation der blockierende Speicher-Sub-Agent sieht |
-| `config.promptStyle` | `"balanced" \| "strict" \| "contextual" \| "recall-heavy" \| "precision-heavy" \| "preference-only"` | Steuert, wie bereitwillig oder streng der blockierende Speicher-Sub-Agent ist, wenn er entscheidet, ob Speicher zurückgegeben werden soll |
+| Key | Type | Bedeutung |
+| --------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
+| `enabled` | `boolean` | Aktiviert das Plugin selbst |
+| `config.agents` | `string[]` | Agent-IDs, die Active Memory verwenden dürfen |
+| `config.model` | `string` | Optionaler Modellverweis für den blockierenden Speicher-Sub-Agenten; wenn nicht gesetzt, verwendet Active Memory das aktuelle Sitzungsmodell |
+| `config.queryMode` | `"message" \| "recent" \| "full"` | Steuert, wie viel Unterhaltung der blockierende Speicher-Sub-Agent sieht |
+| `config.promptStyle` | `"balanced" \| "strict" \| "contextual" \| "recall-heavy" \| "precision-heavy" \| "preference-only"` | Steuert, wie bereitwillig oder streng der blockierende Speicher-Sub-Agent bei der Entscheidung über die Rückgabe von Speicherinhalt ist |
| `config.thinking` | `"off" \| "minimal" \| "low" \| "medium" \| "high" \| "xhigh" \| "adaptive"` | Erweiterte Thinking-Überschreibung für den blockierenden Speicher-Sub-Agenten; Standard `off` für Geschwindigkeit |
-| `config.promptOverride` | `string` | Erweiterter vollständiger Prompt-Ersatz; für die normale Nutzung nicht empfohlen |
-| `config.promptAppend` | `string` | Erweiterte zusätzliche Anweisungen, die an den Standard- oder überschriebenen Prompt angehängt werden |
-| `config.timeoutMs` | `number` | Harter Timeout für den blockierenden Speicher-Sub-Agenten |
-| `config.maxSummaryChars` | `number` | Maximal zulässige Gesamtanzahl von Zeichen in der Active-Memory-Zusammenfassung |
-| `config.logging` | `boolean` | Gibt während der Feinabstimmung Active-Memory-Protokolle aus |
-| `config.persistTranscripts` | `boolean` | Behält Transkripte des blockierenden Speicher-Sub-Agenten auf dem Datenträger, statt temporäre Dateien zu löschen |
-| `config.transcriptDir` | `string` | Relatives Transkriptverzeichnis des blockierenden Speicher-Sub-Agenten unter dem Sitzungsordner des Agenten |
+| `config.promptOverride` | `string` | Erweiterter vollständiger Prompt-Ersatz; für normale Verwendung nicht empfohlen |
+| `config.promptAppend` | `string` | Erweiterte zusätzliche Anweisungen, die an den Standard- oder überschriebenen Prompt angehängt werden |
+| `config.timeoutMs` | `number` | Hartes Timeout für den blockierenden Speicher-Sub-Agenten |
+| `config.maxSummaryChars` | `number` | Maximal zulässige Gesamtzahl von Zeichen in der Active-Memory-Zusammenfassung |
+| `config.logging` | `boolean` | Gibt Active-Memory-Logs während der Anpassung aus |
+| `config.persistTranscripts` | `boolean` | Behält Transkripte des blockierenden Speicher-Sub-Agenten auf der Festplatte, anstatt temporäre Dateien zu löschen |
+| `config.transcriptDir` | `string` | Relatives Transkriptverzeichnis des blockierenden Speicher-Sub-Agenten unter dem Sitzungsordner des Agenten |
-Nützliche Felder zur Feinabstimmung:
+Nützliche Felder zur Anpassung:
-| Schlüssel | Typ | Bedeutung |
-| ----------------------------- | -------- | ------------------------------------------------------------------- |
-| `config.maxSummaryChars` | `number` | Maximal zulässige Gesamtanzahl von Zeichen in der Active-Memory-Zusammenfassung |
-| `config.recentUserTurns` | `number` | Frühere Benutzerzüge, die einbezogen werden, wenn `queryMode` `recent` ist |
-| `config.recentAssistantTurns` | `number` | Frühere Assistentenzüge, die einbezogen werden, wenn `queryMode` `recent` ist |
-| `config.recentUserChars` | `number` | Maximale Zeichen pro aktuellem Benutzerzug |
-| `config.recentAssistantChars` | `number` | Maximale Zeichen pro aktuellem Assistentenzug |
-| `config.cacheTtlMs` | `number` | Cache-Wiederverwendung für wiederholte identische Abfragen |
+| Key | Type | Bedeutung |
+| ----------------------------- | -------- | ------------------------------------------------------------ |
+| `config.maxSummaryChars` | `number` | Maximal zulässige Gesamtzahl von Zeichen in der Active-Memory-Zusammenfassung |
+| `config.recentUserTurns` | `number` | Vorherige Benutzerzüge, die einbezogen werden, wenn `queryMode` `recent` ist |
+| `config.recentAssistantTurns` | `number` | Vorherige Assistentenzüge, die einbezogen werden, wenn `queryMode` `recent` ist |
+| `config.recentUserChars` | `number` | Maximale Zeichenanzahl pro aktuellem Benutzerzug |
+| `config.recentAssistantChars` | `number` | Maximale Zeichenanzahl pro aktuellem Assistentenzug |
+| `config.cacheTtlMs` | `number` | Cache-Wiederverwendung für wiederholte identische Abfragen |
## Empfohlene Einrichtung
@@ -590,8 +674,8 @@ Beginnen Sie mit `recent`.
}
```
-Wenn Sie das Live-Verhalten während der Feinabstimmung prüfen möchten, verwenden Sie `/verbose on` für die
-normale Statuszeile und `/trace on` für die Active-Memory-Debug-Zusammenfassung statt
+Wenn Sie das Live-Verhalten während der Anpassung prüfen möchten, verwenden Sie `/verbose on` für die
+normale Statuszeile und `/trace on` für die Active-Memory-Debug-Zusammenfassung, anstatt
nach einem separaten Active-Memory-Debug-Befehl zu suchen. In Chat-Kanälen werden diese
Diagnosezeilen nach der Hauptantwort des Assistenten gesendet und nicht davor.
@@ -607,76 +691,74 @@ Wenn Active Memory nicht dort angezeigt wird, wo Sie es erwarten:
1. Bestätigen Sie, dass das Plugin unter `plugins.entries.active-memory.enabled` aktiviert ist.
2. Bestätigen Sie, dass die aktuelle Agenten-ID in `config.agents` aufgeführt ist.
3. Bestätigen Sie, dass Sie über eine interaktive persistente Chat-Sitzung testen.
-4. Aktivieren Sie `config.logging: true` und beobachten Sie die Gateway-Protokolle.
-5. Verifizieren Sie mit `openclaw memory status --deep`, dass die Speichersuche selbst funktioniert.
+4. Aktivieren Sie `config.logging: true` und beobachten Sie die Gateway-Logs.
+5. Überprüfen Sie mit `openclaw memory status --deep`, dass die Speichersuche selbst funktioniert.
-Wenn Speicher-Treffer zu verrauscht sind, verschärfen Sie:
+Wenn Speicher-Treffer zu ungenau sind, verschärfen Sie:
- `maxSummaryChars`
Wenn Active Memory zu langsam ist:
-- `queryMode` reduzieren
-- `timeoutMs` reduzieren
-- die Anzahl aktueller Züge reduzieren
-- die Zeichenobergrenzen pro Zug reduzieren
+- verringern Sie `queryMode`
+- verringern Sie `timeoutMs`
+- reduzieren Sie die Anzahl aktueller Züge
+- reduzieren Sie die Zeichenobergrenzen pro Zug
## Häufige Probleme
-### Embedding-Anbieter wurde unerwartet geändert
+### Embedding-Anbieter hat sich unerwartet geändert
Active Memory verwendet die normale `memory_search`-Pipeline unter
`agents.defaults.memorySearch`. Das bedeutet, dass die Einrichtung des Embedding-Anbieters nur dann
-erforderlich ist, wenn Ihre `memorySearch`-Einrichtung Embeddings für das gewünschte Verhalten
-benötigt.
+erforderlich ist, wenn Ihre `memorySearch`-Einrichtung Embeddings für das gewünschte Verhalten benötigt.
In der Praxis gilt:
-- eine explizite Anbieter-Einrichtung ist **erforderlich**, wenn Sie einen Anbieter möchten, der nicht
- automatisch erkannt wird, etwa `ollama`
-- eine explizite Anbieter-Einrichtung ist **erforderlich**, wenn die automatische Erkennung
- keinen verwendbaren Embedding-Anbieter für Ihre Umgebung auflösen kann
-- eine explizite Anbieter-Einrichtung ist **dringend empfohlen**, wenn Sie eine deterministische
- Anbieterauswahl statt „der erste verfügbare gewinnt“ möchten
-- eine explizite Anbieter-Einrichtung ist in der Regel **nicht erforderlich**, wenn die automatische Erkennung bereits
- den gewünschten Anbieter auflöst und dieser in Ihrer Bereitstellung stabil ist
+- eine explizite Anbietereinrichtung ist **erforderlich**, wenn Sie einen Anbieter möchten, der nicht
+ automatisch erkannt wird, z. B. `ollama`
+- eine explizite Anbietereinrichtung ist **erforderlich**, wenn die automatische Erkennung
+ keinen verwendbaren Embedding-Anbieter für Ihre Umgebung auflöst
+- eine explizite Anbietereinrichtung ist **dringend empfohlen**, wenn Sie eine deterministische
+ Anbieterauswahl statt „erstes verfügbares gewinnt“ möchten
+- eine explizite Anbietereinrichtung ist normalerweise **nicht erforderlich**, wenn die automatische Erkennung bereits
+ den gewünschten Anbieter auflöst und dieser Anbieter in Ihrer Bereitstellung stabil ist
Wenn `memorySearch.provider` nicht gesetzt ist, erkennt OpenClaw automatisch den ersten verfügbaren
Embedding-Anbieter.
Das kann in realen Bereitstellungen verwirrend sein:
-- ein neu verfügbarer API-Schlüssel kann ändern, welcher Anbieter für die Speichersuche verwendet wird
+- ein neu verfügbarer API-Schlüssel kann ändern, welchen Anbieter die Speichersuche verwendet
- ein Befehl oder eine Diagnoseoberfläche kann den ausgewählten Anbieter anders erscheinen lassen
als den Pfad, den Sie tatsächlich bei der Live-Speichersynchronisierung oder beim
- Bootstrap der Suche verwenden
-- gehostete Anbieter können mit Kontingent- oder Rate-Limit-Fehlern scheitern, die erst sichtbar werden,
- wenn Active Memory vor jeder Antwort Erinnerungsabfragen ausführt
+ Such-Bootstrap verwenden
+- gehostete Anbieter können mit Kontingent- oder Ratenbegrenzungsfehlern scheitern, die erst sichtbar werden,
+ sobald Active Memory vor jeder Antwort Abrufsuchen ausführt
-Active Memory kann auch ohne Embeddings ausgeführt werden, wenn `memory_search` im
-degradierten rein lexikalischen Modus arbeiten kann, was typischerweise geschieht, wenn kein Embedding-
-Anbieter aufgelöst werden kann.
+Active Memory kann auch ohne Embeddings laufen, wenn `memory_search` im degradierten rein lexikalischen Modus
+arbeiten kann, was typischerweise geschieht, wenn kein Embedding-Anbieter aufgelöst werden kann.
-Gehen Sie nicht davon aus, dass derselbe Fallback bei Laufzeitfehlern des Anbieters gilt, etwa bei ausgeschöpftem Kontingent,
-Rate-Limits, Netzwerk-/Anbieterfehlern oder fehlenden lokalen/Remote-Modellen, nachdem bereits
-ein Anbieter ausgewählt wurde.
+Gehen Sie nicht davon aus, dass derselbe Fallback auch bei Laufzeitfehlern des Anbieters funktioniert, etwa bei
+Kontingenterschöpfung, Ratenbegrenzungen, Netzwerk-/Anbieterfehlern oder fehlenden lokalen/entfernten
+Modellen, nachdem bereits ein Anbieter ausgewählt wurde.
-In der Praxis gilt:
+In der Praxis:
-- wenn kein Embedding-Anbieter aufgelöst werden kann, kann `memory_search` auf
- rein lexikalen Abruf degradieren
+- wenn kein Embedding-Anbieter aufgelöst werden kann, kann `memory_search` zu
+ rein lexikalischem Abruf degradieren
- wenn ein Embedding-Anbieter aufgelöst wird und dann zur Laufzeit fehlschlägt, garantiert OpenClaw
- derzeit keinen lexikalen Fallback für diese Anfrage
-- wenn Sie eine deterministische Anbieterauswahl benötigen, setzen Sie
- `agents.defaults.memorySearch.provider` fest
+ derzeit keinen lexikalischen Fallback für diese Anfrage
+- wenn Sie eine deterministische Anbieterauswahl benötigen, pinnen Sie
+ `agents.defaults.memorySearch.provider`
- wenn Sie Anbieter-Failover bei Laufzeitfehlern benötigen, konfigurieren Sie
`agents.defaults.memorySearch.fallback` explizit
-Wenn Sie auf embedding-gestützten Abruf, multimodale Indizierung oder einen bestimmten
-lokalen/Remote-Anbieter angewiesen sind, setzen Sie den Anbieter explizit fest, statt sich auf
-die automatische Erkennung zu verlassen.
+Wenn Sie auf embeddinggestützten Abruf, multimodale Indizierung oder einen bestimmten
+lokalen/entfernten Anbieter angewiesen sind, pinnen Sie den Anbieter explizit, anstatt sich auf
+automatische Erkennung zu verlassen.
-Häufige Beispiele für das Festlegen:
+Häufige Beispiele für das Pinning:
OpenAI:
@@ -723,8 +805,8 @@ Ollama:
}
```
-Wenn Sie Anbieter-Failover bei Laufzeitfehlern wie ausgeschöpftem Kontingent erwarten,
-reicht das Festlegen eines Anbieters allein nicht aus. Konfigurieren Sie zusätzlich einen expliziten Fallback:
+Wenn Sie Anbieter-Failover bei Laufzeitfehlern wie Kontingenterschöpfung erwarten,
+ist das Pinning eines Anbieters allein nicht ausreichend. Konfigurieren Sie zusätzlich einen expliziten Fallback:
```json5
{
@@ -741,30 +823,30 @@ reicht das Festlegen eines Anbieters allein nicht aus. Konfigurieren Sie zusätz
### Fehlerbehebung bei Anbieterproblemen
-Wenn Active Memory langsam ist, leer bleibt oder Anbieter unerwartet zu wechseln scheint:
+Wenn Active Memory langsam ist, leer bleibt oder scheinbar unerwartet den Anbieter wechselt:
-- beobachten Sie die Gateway-Protokolle, während Sie das Problem reproduzieren; suchen Sie nach Zeilen wie
+- beobachten Sie die Gateway-Logs, während Sie das Problem reproduzieren; achten Sie auf Zeilen wie
`active-memory: ... start|done`, `memory sync failed (search-bootstrap)` oder
- anbieterbezogenen Embedding-Fehlern
+ anbieterspezifische Embedding-Fehler
- aktivieren Sie `/trace on`, um die Plugin-eigene Active-Memory-Debug-Zusammenfassung in
der Sitzung anzuzeigen
-- aktivieren Sie `/verbose on`, wenn Sie zusätzlich die normale `🧩 Active Memory: ...`
- Statuszeile nach jeder Antwort möchten
-- führen Sie `openclaw memory status --deep` aus, um das aktuelle Backend der Speichersuche
- und den Zustand des Index zu prüfen
-- prüfen Sie `agents.defaults.memorySearch.provider` und die zugehörige Authentifizierung/Konfiguration, um sicherzustellen,
- dass der Anbieter, den Sie erwarten, tatsächlich zur Laufzeit aufgelöst werden kann
-- wenn Sie `ollama` verwenden, verifizieren Sie, dass das konfigurierte Embedding-Modell installiert ist, zum
+- aktivieren Sie `/verbose on`, wenn Sie zusätzlich die normale Statuszeile
+ `🧩 Active Memory: ...` nach jeder Antwort sehen möchten
+- führen Sie `openclaw memory status --deep` aus, um das aktuelle Memory-Search-
+ Backend und den Zustand des Index zu prüfen
+- prüfen Sie `agents.defaults.memorySearch.provider` und die zugehörige Authentifizierung/Konfiguration, um
+ sicherzustellen, dass der Anbieter, den Sie erwarten, tatsächlich derjenige ist, der zur Laufzeit aufgelöst werden kann
+- wenn Sie `ollama` verwenden, prüfen Sie, ob das konfigurierte Embedding-Modell installiert ist, zum
Beispiel mit `ollama list`
-Beispiel für eine Debugging-Schleife:
+Beispiel für einen Debugging-Ablauf:
```text
-1. Starten Sie das Gateway und beobachten Sie seine Protokolle
-2. Führen Sie in der Chat-Sitzung /trace on aus
-3. Senden Sie eine Nachricht, die Active Memory auslösen sollte
-4. Vergleichen Sie die im Chat sichtbare Debug-Zeile mit den Gateway-Protokollzeilen
-5. Wenn die Anbieterwahl unklar ist, setzen Sie agents.defaults.memorySearch.provider explizit fest
+1. Gateway starten und seine Logs beobachten
+2. In der Chat-Sitzung /trace on ausführen
+3. Eine Nachricht senden, die Active Memory auslösen sollte
+4. Die im Chat sichtbare Debug-Zeile mit den Gateway-Logzeilen vergleichen
+5. Wenn die Anbieterauswahl uneindeutig ist, agents.defaults.memorySearch.provider explizit pinnen
```
Beispiel:
@@ -796,8 +878,8 @@ Oder, wenn Sie Gemini-Embeddings möchten:
}
```
-Nach dem Ändern des Anbieters starten Sie das Gateway neu und führen einen frischen Test mit
-`/trace on` aus, damit die Active-Memory-Debug-Zeile den neuen Embedding-Pfad widerspiegelt.
+Nachdem Sie den Anbieter geändert haben, starten Sie das Gateway neu und führen Sie mit
+`/trace on` einen neuen Test aus, damit die Active-Memory-Debug-Zeile den neuen Embedding-Pfad widerspiegelt.
## Verwandte Seiten
diff --git a/docs/de/gateway/protocol.md b/docs/de/gateway/protocol.md
index c35f75724..19e314d11 100644
--- a/docs/de/gateway/protocol.md
+++ b/docs/de/gateway/protocol.md
@@ -1,32 +1,32 @@
---
read_when:
- - Implementieren oder Aktualisieren von Gateway-WS-Clients
- - Debuggen von Protokollabweichungen oder Verbindungsfehlern
+ - Implementierung oder Aktualisierung von Gateway-WS-Clients
+ - Fehlersuche bei Protokollabweichungen oder Verbindungsfehlern
- Erneutes Generieren von Protokollschema/-modellen
summary: 'Gateway-WebSocket-Protokoll: Handshake, Frames, Versionierung'
title: Gateway-Protokoll
x-i18n:
- generated_at: "2026-04-11T02:44:51Z"
+ generated_at: "2026-04-16T06:22:25Z"
model: gpt-5.4
provider: openai
- source_hash: 83c820c46d4803d571c770468fd6782619eaa1dca253e156e8087dec735c127f
+ source_hash: 683e61ebe993a2d739bc34860060b0e3eda36b5c57267a2bcc03d177ec612fb3
source_path: gateway/protocol.md
workflow: 15
---
# Gateway-Protokoll (WebSocket)
-Das Gateway-WS-Protokoll ist die **einzige Steuerungsebene + der Knotentransport** für
-OpenClaw. Alle Clients (CLI, Web-UI, macOS-App, iOS-/Android-Knoten, headless
-Knoten) verbinden sich über WebSocket und deklarieren ihre **Rolle** + ihren **Scope** zum
-Zeitpunkt des Handshakes.
+Das Gateway-WS-Protokoll ist die **einzige Control Plane + der einzige Node-Transport** für
+OpenClaw. Alle Clients (CLI, Web-UI, macOS-App, iOS-/Android-Nodes, Headless-
+Nodes) verbinden sich über WebSocket und deklarieren ihre **Rolle** + ihren **Scope** beim
+Handshake.
## Transport
- WebSocket, Text-Frames mit JSON-Payloads.
- Der erste Frame **muss** eine `connect`-Anfrage sein.
-## Handshake (connect)
+## Handshake (`connect`)
Gateway → Client (Pre-Connect-Challenge):
@@ -80,11 +80,25 @@ Gateway → Client:
"type": "res",
"id": "…",
"ok": true,
- "payload": { "type": "hello-ok", "protocol": 3, "policy": { "tickIntervalMs": 15000 } }
+ "payload": {
+ "type": "hello-ok",
+ "protocol": 3,
+ "server": { "version": "…", "connId": "…" },
+ "features": { "methods": ["…"], "events": ["…"] },
+ "snapshot": { "…": "…" },
+ "policy": {
+ "maxPayload": 26214400,
+ "maxBufferedBytes": 52428800,
+ "tickIntervalMs": 15000
+ }
+ }
}
```
-Wenn ein Gerätetoken ausgestellt wird, enthält `hello-ok` außerdem:
+`server`, `features`, `snapshot` und `policy` sind laut Schema alle erforderlich
+(`src/gateway/protocol/schema/frames.ts`). `auth` und `canvasHostUrl` sind optional.
+
+Wenn ein Device-Token ausgestellt wird, enthält `hello-ok` außerdem:
```json
{
@@ -116,14 +130,14 @@ gebundene Rolleneinträge in `deviceTokens` enthalten:
}
```
-Für den integrierten Bootstrap-Flow für Knoten/Operatoren bleibt das primäre Knotentoken bei
-`scopes: []`, und jedes übergebene Operatortoken bleibt auf die Bootstrap-
-Allowlist für Operatoren beschränkt (`operator.approvals`, `operator.read`,
-`operator.talk.secrets`, `operator.write`). Prüfungen des Bootstrap-Scopes bleiben
-rollenpräfixbasiert: Operatoreinträge erfüllen nur Operatoranfragen, und Nicht-Operator-
+Für den integrierten Bootstrap-Ablauf für Node/Operator bleibt das primäre Node-Token bei
+`scopes: []`, und jedes übergebene Operator-Token bleibt auf die Bootstrap-
+Operator-Allowlist beschränkt (`operator.approvals`, `operator.read`,
+`operator.talk.secrets`, `operator.write`). Bootstrap-Scope-Prüfungen bleiben
+rollenpräfixiert: Operator-Einträge erfüllen nur Operator-Anfragen, und Nicht-Operator-
Rollen benötigen weiterhin Scopes unter ihrem eigenen Rollenpräfix.
-### Knotenbeispiel
+### Node-Beispiel
```json
{
@@ -160,20 +174,20 @@ Rollen benötigen weiterhin Scopes unter ihrem eigenen Rollenpräfix.
## Framing
-- **Anfrage**: `{type:"req", id, method, params}`
-- **Antwort**: `{type:"res", id, ok, payload|error}`
-- **Ereignis**: `{type:"event", event, payload, seq?, stateVersion?}`
+- **Request**: `{type:"req", id, method, params}`
+- **Response**: `{type:"res", id, ok, payload|error}`
+- **Event**: `{type:"event", event, payload, seq?, stateVersion?}`
-Methoden mit Nebeneffekten erfordern **Idempotenzschlüssel** (siehe Schema).
+Methoden mit Nebenwirkungen erfordern **Idempotenzschlüssel** (siehe Schema).
## Rollen + Scopes
### Rollen
-- `operator` = Client der Steuerungsebene (CLI/UI/Automatisierung).
-- `node` = Fähigkeits-Host (camera/screen/canvas/system.run).
+- `operator` = Control-Plane-Client (CLI/UI/Automatisierung).
+- `node` = Capability-Host (camera/screen/canvas/system.run).
-### Scopes (operator)
+### Scopes (`operator`)
Häufige Scopes:
@@ -187,283 +201,286 @@ Häufige Scopes:
`talk.config` mit `includeSecrets: true` erfordert `operator.talk.secrets`
(oder `operator.admin`).
-Von Plugins registrierte Gateway-RPC-Methoden können ihren eigenen Operator-Scope anfordern, aber
+Plugin-registrierte Gateway-RPC-Methoden können ihren eigenen Operator-Scope anfordern, aber
reservierte Core-Admin-Präfixe (`config.*`, `exec.approvals.*`, `wizard.*`,
`update.*`) werden immer zu `operator.admin` aufgelöst.
Der Methodenscope ist nur die erste Hürde. Einige Slash-Befehle, die über
-`chat.send` erreicht werden, wenden zusätzlich strengere Prüfungen auf Befehlsebene an. Zum Beispiel erfordern persistente
-Schreibvorgänge mit `/config set` und `/config unset` `operator.admin`.
+`chat.send` erreicht werden, wenden zusätzlich strengere Prüfungen auf
+Befehlsebene an. Zum Beispiel erfordern persistente Schreibvorgänge mit
+`/config set` und `/config unset` `operator.admin`.
-`node.pair.approve` hat zusätzlich zur
-grundlegenden Methodenscope-Prüfung eine weitere Scope-Prüfung zum Zeitpunkt der Genehmigung:
+`node.pair.approve` hat zusätzlich zur Basis-Methodenscope außerdem eine weitere
+Scope-Prüfung zum Zeitpunkt der Freigabe:
-- anfragelose Requests: `operator.pairing`
-- Requests mit Nicht-Exec-Knotenbefehlen: `operator.pairing` + `operator.write`
-- Requests, die `system.run`, `system.run.prepare` oder `system.which` enthalten:
+- Anfragen ohne Befehle: `operator.pairing`
+- Anfragen mit Nicht-Exec-Node-Befehlen: `operator.pairing` + `operator.write`
+- Anfragen, die `system.run`, `system.run.prepare` oder `system.which` enthalten:
`operator.pairing` + `operator.admin`
-### Caps/commands/permissions (node)
+### Caps/commands/permissions (`node`)
-Knoten deklarieren ihre Fähigkeitsansprüche zum Zeitpunkt von `connect`:
+Nodes deklarieren ihre Capability-Claims beim Verbinden:
-- `caps`: übergeordnete Fähigkeitskategorien.
-- `commands`: Allowlist von Befehlen für `invoke`.
-- `permissions`: granulare Umschalter (z. B. `screen.record`, `camera.capture`).
+- `caps`: allgemeine Capability-Kategorien.
+- `commands`: Befehls-Allowlist für `invoke`.
+- `permissions`: granulare Schalter (z. B. `screen.record`, `camera.capture`).
-Das Gateway behandelt diese als **Ansprüche** und erzwingt serverseitige Allowlists.
+Das Gateway behandelt diese als **Claims** und erzwingt serverseitige Allowlists.
-## Präsenz
+## Presence
-- `system-presence` gibt Einträge zurück, die nach Geräteidentität gruppiert sind.
-- Präsenzeinträge enthalten `deviceId`, `roles` und `scopes`, damit UIs eine einzelne Zeile pro Gerät anzeigen können,
+- `system-presence` gibt Einträge zurück, die nach Geräteidentität indiziert sind.
+- Presence-Einträge enthalten `deviceId`, `roles` und `scopes`, damit UIs eine einzelne Zeile pro Gerät anzeigen können,
selbst wenn es sowohl als **operator** als auch als **node** verbunden ist.
## Häufige RPC-Methodenfamilien
-Diese Seite ist kein vollständig generierter Dump, aber die öffentliche WS-Oberfläche ist breiter
-als die oben gezeigten Handshake-/Auth-Beispiele. Dies sind die wichtigsten Methodenfamilien, die das
-Gateway heute bereitstellt.
+Diese Seite ist kein generierter vollständiger Dump, aber die öffentliche WS-Oberfläche ist umfassender
+als die Handshake-/Auth-Beispiele oben. Dies sind die wichtigsten Methodenfamilien, die das
+Gateway derzeit bereitstellt.
`hello-ok.features.methods` ist eine konservative Discovery-Liste, die aus
-`src/gateway/server-methods-list.ts` plus geladenen Plugin-/Kanal-Methodenexporten erstellt wird.
-Behandeln Sie sie als Feature-Erkennung, nicht als generierten Dump jeder aufrufbaren Hilfsfunktion,
-die in `src/gateway/server-methods/*.ts` implementiert ist.
+`src/gateway/server-methods-list.ts` sowie geladenen Plugin-/Channel-Methodenexports aufgebaut wird.
+Behandle sie als Feature Discovery, nicht als generierten Dump aller aufrufbaren Helfer,
+die in `src/gateway/server-methods/*.ts` implementiert sind.
### System und Identität
- `health` gibt den gecachten oder frisch geprüften Gateway-Health-Snapshot zurück.
-- `status` gibt die Gateway-Zusammenfassung im Stil von `/status` zurück; sensible Felder sind
- nur für Operator-Clients mit Admin-Scope enthalten.
+- `status` gibt die Gateway-Zusammenfassung im Stil von `/status` zurück; sensible Felder werden
+ nur für Operator-Clients mit Admin-Scope einbezogen.
- `gateway.identity.get` gibt die Gateway-Geräteidentität zurück, die von Relay- und
- Pairing-Flows verwendet wird.
-- `system-presence` gibt den aktuellen Präsenz-Snapshot für verbundene
- Operator-/Knotengeräte zurück.
-- `system-event` hängt ein Systemereignis an und kann den Präsenzkontext
- aktualisieren/übertragen.
+ Pairing-Abläufen verwendet wird.
+- `system-presence` gibt den aktuellen Presence-Snapshot für verbundene
+ Operator-/Node-Geräte zurück.
+- `system-event` hängt ein Systemereignis an und kann den Presence-
+ Kontext aktualisieren/übertragen.
- `last-heartbeat` gibt das zuletzt persistierte Heartbeat-Ereignis zurück.
- `set-heartbeats` schaltet die Heartbeat-Verarbeitung auf dem Gateway um.
### Modelle und Nutzung
- `models.list` gibt den zur Laufzeit erlaubten Modellkatalog zurück.
-- `usage.status` gibt Zusammenfassungen von Provider-Nutzungsfenstern/verbleibender Quote zurück.
-- `usage.cost` gibt aggregierte Kosten-Nutzungszusammenfassungen für einen Datumsbereich zurück.
-- `doctor.memory.status` gibt die Bereitschaft von Vektorspeicher/Embeddings für den
+- `usage.status` gibt Provider-Nutzungsfenster/Zusammenfassungen des verbleibenden Kontingents zurück.
+- `usage.cost` gibt aggregierte Zusammenfassungen der Kostennutzung für einen Datumsbereich zurück.
+- `doctor.memory.status` gibt den Bereitschaftsstatus für Vector Memory / Embeddings für den
aktiven Standard-Agent-Workspace zurück.
- `sessions.usage` gibt Nutzungszusammenfassungen pro Sitzung zurück.
-- `sessions.usage.timeseries` gibt Zeitreihen-Nutzungsdaten für eine Sitzung zurück.
-- `sessions.usage.logs` gibt Nutzungseinträge für eine Sitzung zurück.
+- `sessions.usage.timeseries` gibt Zeitreihennutzung für eine Sitzung zurück.
+- `sessions.usage.logs` gibt Nutzungslogeinträge für eine Sitzung zurück.
-### Kanäle und Login-Helfer
+### Channels und Login-Helfer
-- `channels.status` gibt Statuszusammenfassungen für integrierte und gebündelte Kanäle/Plugins zurück.
-- `channels.logout` meldet einen bestimmten Kanal/ein bestimmtes Konto ab, wenn der Kanal
+- `channels.status` gibt Statuszusammenfassungen für integrierte und gebündelte Channels/Plugins zurück.
+- `channels.logout` meldet einen bestimmten Channel/Account ab, sofern der Channel
Logout unterstützt.
-- `web.login.start` startet einen QR-/Web-Login-Flow für den aktuellen QR-fähigen Web-
- Kanal-Provider.
-- `web.login.wait` wartet auf den Abschluss dieses QR-/Web-Login-Flows und startet bei Erfolg den
- Kanal.
-- `push.test` sendet einen Test-APNs-Push an einen registrierten iOS-Knoten.
+- `web.login.start` startet einen QR-/Web-Login-Ablauf für den aktuell QR-fähigen Web-
+ Channel-Provider.
+- `web.login.wait` wartet darauf, dass dieser QR-/Web-Login-Ablauf abgeschlossen wird, und startet bei Erfolg den
+ Channel.
+- `push.test` sendet einen Test-APNs-Push an einen registrierten iOS-Node.
- `voicewake.get` gibt die gespeicherten Wake-Word-Trigger zurück.
- `voicewake.set` aktualisiert Wake-Word-Trigger und überträgt die Änderung.
### Messaging und Logs
-- `send` ist die direkte RPC für ausgehende Zustellung für auf Kanal/Konto/Thread ausgerichtete
- Sendungen außerhalb des Chat-Runners.
-- `logs.tail` gibt den konfigurierten Gateway-Dateilog-Tail mit Cursor-/Limit- und
+- `send` ist die direkte RPC für ausgehende Zustellung an Channel/Account/Thread-Ziele
+ außerhalb des Chat-Runners.
+- `logs.tail` gibt den konfigurierten Gateway-Dateilog-Tail mit Cursor/Limit und
Max-Byte-Steuerung zurück.
### Talk und TTS
- `talk.config` gibt die effektive Talk-Konfigurations-Payload zurück; `includeSecrets`
erfordert `operator.talk.secrets` (oder `operator.admin`).
-- `talk.mode` setzt/überträgt den aktuellen Zustand des Talk-Modus für WebChat-/Control-UI-
+- `talk.mode` setzt/überträgt den aktuellen Talk-Modusstatus für WebChat-/Control-UI-
Clients.
-- `talk.speak` synthetisiert Sprache über den aktiven Talk-Sprachprovider.
+- `talk.speak` synthetisiert Sprache über den aktiven Talk-Speech-Provider.
- `tts.status` gibt den aktivierten TTS-Status, den aktiven Provider, Fallback-Provider
- und den Zustand der Provider-Konfiguration zurück.
-- `tts.providers` gibt das sichtbare Inventar der TTS-Provider zurück.
-- `tts.enable` und `tts.disable` schalten den TTS-Präferenzstatus um.
+ und den Provider-Konfigurationsstatus zurück.
+- `tts.providers` gibt das sichtbare TTS-Provider-Inventar zurück.
+- `tts.enable` und `tts.disable` schalten den TTS-Status der Voreinstellungen um.
- `tts.setProvider` aktualisiert den bevorzugten TTS-Provider.
- `tts.convert` führt eine einmalige Text-zu-Sprache-Konvertierung aus.
### Secrets, Konfiguration, Update und Wizard
-- `secrets.reload` löst aktive SecretRefs erneut auf und tauscht den Laufzeit-Secret-Status
+- `secrets.reload` löst aktive SecretRefs erneut auf und tauscht den Laufzeitstatus für Secrets
nur bei vollständigem Erfolg aus.
-- `secrets.resolve` löst zielgerichtete Secret-Zuweisungen für einen bestimmten
- Befehl/Zielsatz auf.
+- `secrets.resolve` löst Secret-Zuweisungen für ein bestimmtes
+ Befehls-/Ziel-Set auf.
- `config.get` gibt den aktuellen Konfigurations-Snapshot und Hash zurück.
- `config.set` schreibt eine validierte Konfigurations-Payload.
-- `config.patch` führt eine teilweise Konfigurationsaktualisierung zusammen.
+- `config.patch` führt eine partielle Konfigurationsaktualisierung zusammen.
- `config.apply` validiert und ersetzt die vollständige Konfigurations-Payload.
- `config.schema` gibt die Live-Konfigurationsschema-Payload zurück, die von Control UI und
CLI-Tooling verwendet wird: Schema, `uiHints`, Version und Generierungsmetadaten, einschließlich
- Plugin- und Kanalschema-Metadaten, wenn die Laufzeit sie laden kann. Das Schema
- enthält die Feldmetadaten `title` / `description`, die aus denselben Labels
- und Hilfetexten abgeleitet sind, die von der UI verwendet werden, einschließlich verschachtelter Objekt-,
- Wildcard-, Array-Item- und `anyOf` / `oneOf` / `allOf`-Kompositionszweige, wenn passende Felddokumentation vorhanden ist.
+ Plugin- und Channel-Schema-Metadaten, wenn die Laufzeit sie laden kann. Das Schema
+ enthält Feldmetadaten `title` / `description`, die aus denselben Labels
+ und Hilfetexten abgeleitet werden, die von der UI verwendet werden, einschließlich verschachtelter Objekte,
+ Wildcards, Array-Items und `anyOf`- / `oneOf`- / `allOf`-Kompositionszweigen, wenn passende
+ Felddokumentation existiert.
- `config.schema.lookup` gibt eine pfadbezogene Lookup-Payload für einen Konfigurationspfad zurück:
- normalisierter Pfad, ein flacher Schemaknoten, passender Hint + `hintPath` sowie
- Zusammenfassungen der unmittelbaren Kinder für UI-/CLI-Drill-down.
- - Lookup-Schemaknoten behalten die benutzerseitige Dokumentation und allgemeine Validierungsfelder:
+ normalisierter Pfad, ein flacher Schemaknoten, passender Hint + `hintPath` und
+ Zusammenfassungen der direkten Kindknoten für UI-/CLI-Drill-down.
+ - Lookup-Schemaknoten behalten die nutzerseitige Dokumentation und häufige Validierungsfelder:
`title`, `description`, `type`, `enum`, `const`, `format`, `pattern`,
- numerische/String-/Array-/Objekt-Grenzen sowie boolesche Flags wie
+ numerische/String-/Array-/Objekt-Grenzen und boolesche Flags wie
`additionalProperties`, `deprecated`, `readOnly`, `writeOnly`.
- - Kindzusammenfassungen stellen `key`, normalisierten `path`, `type`, `required`,
+ - Zusammenfassungen der Kindknoten stellen `key`, normalisierten `path`, `type`, `required`,
`hasChildren` sowie den passenden `hint` / `hintPath` bereit.
-- `update.run` führt den Gateway-Update-Flow aus und plant einen Neustart nur dann,
+- `update.run` führt den Gateway-Update-Ablauf aus und plant einen Neustart nur dann,
wenn das Update selbst erfolgreich war.
- `wizard.start`, `wizard.next`, `wizard.status` und `wizard.cancel` stellen den
Onboarding-Wizard über WS RPC bereit.
-### Bestehende große Familien
+### Vorhandene große Familien
-#### Agenten- und Workspace-Helfer
+#### Agent- und Workspace-Helfer
-- `agents.list` gibt konfigurierte Agenteneinträge zurück.
-- `agents.create`, `agents.update` und `agents.delete` verwalten Agentendatensätze und
+- `agents.list` gibt konfigurierte Agent-Einträge zurück.
+- `agents.create`, `agents.update` und `agents.delete` verwalten Agent-Datensätze und
Workspace-Verdrahtung.
- `agents.files.list`, `agents.files.get` und `agents.files.set` verwalten die
exponierten Bootstrap-Workspace-Dateien eines Agenten.
- `agent.identity.get` gibt die effektive Assistentenidentität für einen Agenten oder
eine Sitzung zurück.
-- `agent.wait` wartet darauf, dass ein Lauf abgeschlossen wird, und gibt den terminalen Snapshot zurück,
- wenn verfügbar.
+- `agent.wait` wartet darauf, dass ein Lauf abgeschlossen wird, und gibt den terminalen Snapshot zurück, wenn
+ verfügbar.
#### Sitzungssteuerung
- `sessions.list` gibt den aktuellen Sitzungsindex zurück.
- `sessions.subscribe` und `sessions.unsubscribe` schalten Abonnements für Sitzungsänderungsereignisse
- für den aktuellen WS-Client ein bzw. aus.
+ für den aktuellen WS-Client um.
- `sessions.messages.subscribe` und `sessions.messages.unsubscribe` schalten
- Protokoll-/Nachrichtenereignis-Abonnements für eine Sitzung ein bzw. aus.
-- `sessions.preview` gibt begrenzte Protokollvorschauen für bestimmte Sitzungsschlüssel
- zurück.
+ Abonnements für Transkript-/Nachrichtenereignisse für eine Sitzung um.
+- `sessions.preview` gibt begrenzte Transkriptvorschauen für bestimmte Sitzungs-
+ Schlüssel zurück.
- `sessions.resolve` löst ein Sitzungsziel auf oder kanonisiert es.
- `sessions.create` erstellt einen neuen Sitzungseintrag.
- `sessions.send` sendet eine Nachricht in eine bestehende Sitzung.
-- `sessions.steer` ist die Interrupt-und-Steer-Variante für eine aktive Sitzung.
+- `sessions.steer` ist die Variante zum Unterbrechen und Neu-Steuern für eine aktive Sitzung.
- `sessions.abort` bricht aktive Arbeit für eine Sitzung ab.
-- `sessions.patch` aktualisiert Sitzungsmetadaten/-Überschreibungen.
+- `sessions.patch` aktualisiert Sitzungsmetadaten/-Overrides.
- `sessions.reset`, `sessions.delete` und `sessions.compact` führen Sitzungs-
- Wartungsaufgaben aus.
+ Wartung durch.
- `sessions.get` gibt die vollständige gespeicherte Sitzungszeile zurück.
- Die Chat-Ausführung verwendet weiterhin `chat.history`, `chat.send`, `chat.abort` und
`chat.inject`.
-- `chat.history` ist für UI-Clients anzeige-normalisiert: Inline-Direktiv-Tags werden
+- `chat.history` ist für UI-Clients anzeige-normalisiert: Inline-Direktiventags werden
aus sichtbarem Text entfernt, XML-Payloads von Tool-Aufrufen im Klartext (einschließlich
`...`, `...`,
`...`, `...` und
abgeschnittener Tool-Call-Blöcke) sowie durchgesickerte ASCII-/Full-Width-
- Modellsteuerungstoken werden entfernt, reine stille-Token-Assistentenzeilen wie exakt `NO_REPLY` /
- `no_reply` werden ausgelassen, und übergroße Zeilen können durch Platzhalter ersetzt werden.
+ Modellsteuerungstoken werden entfernt, reine Assistant-Zeilen mit stillen Tokens wie exaktem `NO_REPLY` /
+ `no_reply` werden weggelassen, und übergroße Zeilen können durch Platzhalter ersetzt werden.
-#### Geräte-Pairing und Gerätetoken
+#### Geräte-Pairing und Device-Tokens
-- `device.pair.list` gibt ausstehende und genehmigte gepaarte Geräte zurück.
+- `device.pair.list` gibt ausstehende und genehmigte gekoppelte Geräte zurück.
- `device.pair.approve`, `device.pair.reject` und `device.pair.remove` verwalten
Geräte-Pairing-Einträge.
-- `device.token.rotate` rotiert ein gepaartes Gerätetoken innerhalb seiner genehmigten Rollen-
+- `device.token.rotate` rotiert ein Token für ein gekoppeltes Gerät innerhalb seiner genehmigten Rollen-
und Scope-Grenzen.
-- `device.token.revoke` widerruft ein gepaartes Gerätetoken.
+- `device.token.revoke` widerruft ein Token für ein gekoppeltes Gerät.
-#### Knoten-Pairing, Invoke und ausstehende Arbeit
+#### Node-Pairing, Invoke und ausstehende Arbeit
- `node.pair.request`, `node.pair.list`, `node.pair.approve`,
- `node.pair.reject` und `node.pair.verify` decken Knoten-Pairing und Bootstrap-
+ `node.pair.reject` und `node.pair.verify` decken Node-Pairing und Bootstrap-
Verifizierung ab.
-- `node.list` und `node.describe` geben den bekannten/verbundenen Knotenzustand zurück.
-- `node.rename` aktualisiert eine Bezeichnung eines gepaarten Knotens.
-- `node.invoke` leitet einen Befehl an einen verbundenen Knoten weiter.
+- `node.list` und `node.describe` geben bekannte/verbundene Node-Zustände zurück.
+- `node.rename` aktualisiert ein Label für einen gekoppelten Node.
+- `node.invoke` leitet einen Befehl an einen verbundenen Node weiter.
- `node.invoke.result` gibt das Ergebnis für eine Invoke-Anfrage zurück.
-- `node.event` überträgt von Knoten stammende Ereignisse zurück in das Gateway.
-- `node.canvas.capability.refresh` aktualisiert bereichsbezogene Canvas-Fähigkeitstoken.
-- `node.pending.pull` und `node.pending.ack` sind die Queue-APIs für verbundene Knoten.
+- `node.event` überträgt von Nodes stammende Ereignisse zurück ins Gateway.
+- `node.canvas.capability.refresh` aktualisiert bereichsbezogene Canvas-Capability-Tokens.
+- `node.pending.pull` und `node.pending.ack` sind die Queue-APIs für verbundene Nodes.
- `node.pending.enqueue` und `node.pending.drain` verwalten dauerhafte ausstehende Arbeit
- für offline/getrennte Knoten.
+ für offline/getrennte Nodes.
#### Genehmigungsfamilien
- `exec.approval.request`, `exec.approval.get`, `exec.approval.list` und
- `exec.approval.resolve` decken einmalige Exec-Genehmigungsanfragen plus Nachschlagen/Wiederholen
+ `exec.approval.resolve` decken einmalige Exec-Genehmigungsanfragen sowie Lookup/Replay
ausstehender Genehmigungen ab.
- `exec.approval.waitDecision` wartet auf eine ausstehende Exec-Genehmigung und gibt
- die endgültige Entscheidung zurück (oder `null` bei Zeitüberschreitung).
-- `exec.approvals.get` und `exec.approvals.set` verwalten Gateway-Exec-Genehmigungs-
- Richtlinien-Snapshots.
-- `exec.approvals.node.get` und `exec.approvals.node.set` verwalten knotenspezifische Exec-
- Genehmigungsrichtlinien über Knoten-Relay-Befehle.
+ die finale Entscheidung zurück (oder `null` bei Timeout).
+- `exec.approvals.get` und `exec.approvals.set` verwalten Snapshots der Gateway-Exec-
+ Genehmigungsrichtlinie.
+- `exec.approvals.node.get` und `exec.approvals.node.set` verwalten Node-lokale Exec-
+ Genehmigungsrichtlinien über Node-Relay-Befehle.
- `plugin.approval.request`, `plugin.approval.list`,
`plugin.approval.waitDecision` und `plugin.approval.resolve` decken
- plugin-definierte Genehmigungs-Flows ab.
+ Plugin-definierte Genehmigungsabläufe ab.
-#### Andere große Familien
+#### Weitere große Familien
- Automatisierung:
- - `wake` plant eine sofortige oder bei einem nächsten Heartbeat erfolgende Wake-Text-Injektion
+ - `wake` plant eine sofortige oder beim nächsten Heartbeat erfolgende Wake-Textinjektion
- `cron.list`, `cron.status`, `cron.add`, `cron.update`, `cron.remove`,
`cron.run`, `cron.runs`
- Skills/Tools: `commands.list`, `skills.*`, `tools.catalog`, `tools.effective`
### Häufige Ereignisfamilien
-- `chat`: UI-Chat-Updates wie `chat.inject` und andere reine Protokoll-Chat-
- Ereignisse.
-- `session.message` und `session.tool`: Protokoll-/Ereignisstream-Updates für eine
+- `chat`: UI-Chat-Updates wie `chat.inject` und andere Chat-
+ Ereignisse nur für das Transkript.
+- `session.message` und `session.tool`: Transkript-/Ereignisstream-Updates für eine
abonnierte Sitzung.
-- `sessions.changed`: Sitzungsindex oder Metadaten haben sich geändert.
-- `presence`: Snapshot-Aktualisierungen der Systempräsenz.
+- `sessions.changed`: Sitzungsindex oder -metadaten wurden geändert.
+- `presence`: Updates des System-Presence-Snapshots.
- `tick`: periodisches Keepalive-/Liveness-Ereignis.
-- `health`: Gateway-Health-Snapshot-Aktualisierung.
-- `heartbeat`: Aktualisierung des Heartbeat-Ereignisstreams.
-- `cron`: Änderungsereignis für Cron-Lauf/-Job.
-- `shutdown`: Gateway-Abschaltbenachrichtigung.
-- `node.pair.requested` / `node.pair.resolved`: Lebenszyklus des Knoten-Pairings.
-- `node.invoke.request`: Broadcast einer Knoten-Invoke-Anfrage.
-- `device.pair.requested` / `device.pair.resolved`: Lebenszyklus gepaarter Geräte.
-- `voicewake.changed`: Konfiguration von Wake-Word-Triggern wurde geändert.
+- `health`: Update des Gateway-Health-Snapshots.
+- `heartbeat`: Update des Heartbeat-Ereignisstreams.
+- `cron`: Ereignis für Änderung von Cron-Lauf/Job.
+- `shutdown`: Benachrichtigung über das Herunterfahren des Gateways.
+- `node.pair.requested` / `node.pair.resolved`: Lebenszyklus des Node-Pairings.
+- `node.invoke.request`: Broadcast einer Node-Invoke-Anfrage.
+- `device.pair.requested` / `device.pair.resolved`: Lebenszyklus gekoppelter Geräte.
+- `voicewake.changed`: Konfiguration des Wake-Word-Triggers wurde geändert.
- `exec.approval.requested` / `exec.approval.resolved`: Lebenszyklus der Exec-
Genehmigung.
-- `plugin.approval.requested` / `plugin.approval.resolved`: Lebenszyklus der Plugin-Genehmigung.
+- `plugin.approval.requested` / `plugin.approval.resolved`: Lebenszyklus der Plugin-
+ Genehmigung.
-### Hilfsmethoden für Knoten
+### Node-Helfermethoden
-- Knoten können `skills.bins` aufrufen, um die aktuelle Liste ausführbarer Skills
+- Nodes können `skills.bins` aufrufen, um die aktuelle Liste ausführbarer Skill-Dateien
für Auto-Allow-Prüfungen abzurufen.
-### Hilfsmethoden für Operatoren
+### Operator-Helfermethoden
- Operatoren können `commands.list` (`operator.read`) aufrufen, um das Laufzeit-
Befehlsinventar für einen Agenten abzurufen.
- - `agentId` ist optional; lassen Sie es weg, um den Standard-Agent-Workspace zu lesen.
- - `scope` steuert, welche Oberfläche vom primären `name` angesprochen wird:
+ - `agentId` ist optional; lasse es weg, um den Standard-Agent-Workspace zu lesen.
+ - `scope` steuert, auf welche Oberfläche sich `name` primär bezieht:
- `text` gibt das primäre Textbefehlstoken ohne führendes `/` zurück
- `native` und der Standardpfad `both` geben providerbewusste native Namen
zurück, wenn verfügbar
- `textAliases` enthält exakte Slash-Aliasse wie `/model` und `/m`.
- - `nativeName` enthält den providerbewussten nativen Befehlsnamen, wenn einer existiert.
- - `provider` ist optional und beeinflusst nur native Benennung sowie die Verfügbarkeit
- nativer Plugin-Befehle.
+ - `nativeName` enthält den providerbewussten nativen Befehlsnamen, wenn ein solcher existiert.
+ - `provider` ist optional und beeinflusst nur die native Benennung sowie die Verfügbarkeit nativer Plugin-
+ Befehle.
- `includeArgs=false` lässt serialisierte Argumentmetadaten in der Antwort weg.
- Operatoren können `tools.catalog` (`operator.read`) aufrufen, um den Laufzeit-Toolkatalog für einen
Agenten abzurufen. Die Antwort enthält gruppierte Tools und Herkunftsmetadaten:
- `source`: `core` oder `plugin`
- `pluginId`: Plugin-Eigentümer, wenn `source="plugin"`
- `optional`: ob ein Plugin-Tool optional ist
-- Operatoren können `tools.effective` (`operator.read`) aufrufen, um das zur Laufzeit wirksame Tool-
+- Operatoren können `tools.effective` (`operator.read`) aufrufen, um das zur Laufzeit effektive Tool-
Inventar für eine Sitzung abzurufen.
- `sessionKey` ist erforderlich.
- - Das Gateway leitet vertrauenswürdigen Laufzeitkontext serverseitig aus der Sitzung ab, statt
- vom Aufrufer gelieferten Auth- oder Zustellungskontext zu akzeptieren.
- - Die Antwort ist sitzungsbezogen und spiegelt wider, was die aktive Unterhaltung derzeit nutzen kann,
- einschließlich Core-, Plugin- und Kanal-Tools.
+ - Das Gateway leitet den vertrauenswürdigen Laufzeitkontext serverseitig aus der Sitzung ab, statt
+ vom Aufrufer bereitgestellten Auth- oder Zustellungskontext zu akzeptieren.
+ - Die Antwort ist sitzungsbezogen und spiegelt wider, was die aktive Unterhaltung derzeit verwenden kann,
+ einschließlich Core-, Plugin- und Channel-Tools.
- Operatoren können `skills.status` (`operator.read`) aufrufen, um das sichtbare
- Skill-Inventar für einen Agenten abzurufen.
- - `agentId` ist optional; lassen Sie es weg, um den Standard-Agent-Workspace zu lesen.
- - Die Antwort enthält Eignung, fehlende Anforderungen, Konfigurationsprüfungen und
+ Skills-Inventar für einen Agenten abzurufen.
+ - `agentId` ist optional; lasse es weg, um den Standard-Agent-Workspace zu lesen.
+ - Die Antwort enthält Eignung, fehlende Voraussetzungen, Konfigurationsprüfungen und
bereinigte Installationsoptionen, ohne rohe Secret-Werte offenzulegen.
- Operatoren können `skills.search` und `skills.detail` (`operator.read`) für
ClawHub-Discovery-Metadaten aufrufen.
@@ -473,134 +490,166 @@ die in `src/gateway/server-methods/*.ts` implementiert ist.
- Gateway-Installer-Modus: `{ name, installId, dangerouslyForceUnsafeInstall?, timeoutMs? }`
führt eine deklarierte `metadata.openclaw.install`-Aktion auf dem Gateway-Host aus.
- Operatoren können `skills.update` (`operator.admin`) in zwei Modi aufrufen:
- - Der ClawHub-Modus aktualisiert einen verfolgten Slug oder alle verfolgten ClawHub-Installationen im
- Standard-Agent-Workspace.
- - Der Konfigurationsmodus patcht `skills.entries.`-Werte wie `enabled`,
- `apiKey` und `env`.
+ - Im ClawHub-Modus wird ein verfolgter Slug oder werden alle verfolgten ClawHub-Installationen im
+ Standard-Agent-Workspace aktualisiert.
+ - Im Konfigurationsmodus werden Werte in `skills.entries.` wie `enabled`,
+ `apiKey` und `env` gepatcht.
## Exec-Genehmigungen
-- Wenn eine Exec-Anfrage eine Genehmigung benötigt, überträgt das Gateway `exec.approval.requested`.
-- Operator-Clients lösen dies durch Aufruf von `exec.approval.resolve` auf (erfordert Scope `operator.approvals`).
-- Für `host=node` muss `exec.approval.request` `systemRunPlan` enthalten (kanonische `argv`/`cwd`/`rawCommand`/Sitzungsmetadaten). Anfragen ohne `systemRunPlan` werden abgelehnt.
-- Nach der Genehmigung verwenden weitergeleitete `node.invoke system.run`-Aufrufe dieses kanonische
- `systemRunPlan` als maßgeblichen Befehls-/cwd-/Sitzungskontext.
+- Wenn eine Exec-Anfrage eine Genehmigung benötigt, sendet das Gateway `exec.approval.requested`.
+- Operator-Clients lösen dies durch Aufruf von `exec.approval.resolve` auf (erfordert den Scope `operator.approvals`).
+- Für `host=node` muss `exec.approval.request` `systemRunPlan` enthalten (kanonische `argv`-/`cwd`-/`rawCommand`-/Sitzungsmetadaten). Anfragen ohne `systemRunPlan` werden abgelehnt.
+- Nach der Genehmigung verwenden weitergeleitete `node.invoke system.run`-Aufrufe denselben kanonischen
+ `systemRunPlan` als maßgeblichen Befehls-/`cwd`-/Sitzungskontext.
- Wenn ein Aufrufer `command`, `rawCommand`, `cwd`, `agentId` oder
- `sessionKey` zwischen der Vorbereitung und der endgültigen genehmigten Weiterleitung von `system.run` verändert, lehnt das
- Gateway den Lauf ab, statt der veränderten Payload zu vertrauen.
+ `sessionKey` zwischen `prepare` und dem finalen weitergeleiteten genehmigten `system.run` ändert, lehnt das
+ Gateway den Lauf ab, statt der geänderten Payload zu vertrauen.
-## Agenten-Zustellungs-Fallback
+## Agent-Zustellungs-Fallback
- `agent`-Anfragen können `deliver=true` enthalten, um ausgehende Zustellung anzufordern.
-- `bestEffortDeliver=false` behält striktes Verhalten bei: nicht auflösbare oder nur intern verfügbare Zustellungsziele geben `INVALID_REQUEST` zurück.
-- `bestEffortDeliver=true` erlaubt Fallback auf reine Sitzungsausführung, wenn keine extern zustellbare Route aufgelöst werden kann (zum Beispiel interne/WebChat-Sitzungen oder mehrdeutige Multi-Kanal-Konfigurationen).
+- `bestEffortDeliver=false` behält striktes Verhalten bei: Nicht auflösbare oder nur intern verfügbare Zustellungsziele geben `INVALID_REQUEST` zurück.
+- `bestEffortDeliver=true` erlaubt Fallback auf reine Sitzungsausführung, wenn keine extern zustellbare Route aufgelöst werden kann (zum Beispiel bei internen/WebChat-Sitzungen oder mehrdeutigen Multi-Channel-Konfigurationen).
## Versionierung
-- `PROTOCOL_VERSION` befindet sich in `src/gateway/protocol/schema.ts`.
+- `PROTOCOL_VERSION` befindet sich in `src/gateway/protocol/schema/protocol-schemas.ts`.
- Clients senden `minProtocol` + `maxProtocol`; der Server lehnt Abweichungen ab.
- Schemas + Modelle werden aus TypeBox-Definitionen generiert:
- `pnpm protocol:gen`
- `pnpm protocol:gen:swift`
- `pnpm protocol:check`
+### Client-Konstanten
+
+Der Referenzclient in `src/gateway/client.ts` verwendet diese Standardwerte. Die Werte sind
+über Protokoll v3 hinweg stabil und bilden die erwartete Basis für Drittanbieter-Clients.
+
+| Konstante | Standardwert | Quelle |
+| ----------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------- |
+| `PROTOCOL_VERSION` | `3` | `src/gateway/protocol/schema/protocol-schemas.ts` |
+| Request-Timeout (pro RPC) | `30_000` ms | `src/gateway/client.ts` (`requestTimeoutMs`) |
+| Preauth- / Connect-Challenge-Timeout | `10_000` ms | `src/gateway/handshake-timeouts.ts` (Clamp `250`–`10_000`) |
+| Initialer Reconnect-Backoff | `1_000` ms | `src/gateway/client.ts` (`backoffMs`) |
+| Maximaler Reconnect-Backoff | `30_000` ms | `src/gateway/client.ts` (`scheduleReconnect`) |
+| Fast-Retry-Clamp nach Device-Token-Close | `250` ms | `src/gateway/client.ts` |
+| Force-Stop-Schonfrist vor `terminate()` | `250` ms | `FORCE_STOP_TERMINATE_GRACE_MS` |
+| Standard-Timeout von `stopAndWait()` | `1_000` ms | `STOP_AND_WAIT_TIMEOUT_MS` |
+| Standard-Tick-Intervall (vor `hello-ok`) | `30_000` ms | `src/gateway/client.ts` |
+| Tick-Timeout-Close | Code `4000`, wenn Stille `tickIntervalMs * 2` überschreitet | `src/gateway/client.ts` |
+| `MAX_PAYLOAD_BYTES` | `25 * 1024 * 1024` (25 MB) | `src/gateway/server-constants.ts` |
+
+Der Server kündigt das effektive `policy.tickIntervalMs`, `policy.maxPayload`
+und `policy.maxBufferedBytes` in `hello-ok` an; Clients sollten diese Werte
+statt der Standardwerte vor dem Handshake beachten.
+
## Auth
-- Gateway-Auth mit gemeinsamem Secret verwendet `connect.params.auth.token` oder
+- Authentifizierung des Gateways per Shared Secret verwendet `connect.params.auth.token` oder
`connect.params.auth.password`, abhängig vom konfigurierten Auth-Modus.
- Identitätstragende Modi wie Tailscale Serve
- (`gateway.auth.allowTailscale: true`) oder Nicht-Loopback-
+ (`gateway.auth.allowTailscale: true`) oder nicht über Loopback laufendes
`gateway.auth.mode: "trusted-proxy"` erfüllen die Connect-Auth-Prüfung über
Request-Header statt über `connect.params.auth.*`.
-- `gateway.auth.mode: "none"` für private Ingress überspringt die Connect-Auth mit gemeinsamem Secret
- vollständig; setzen Sie diesen Modus nicht an öffentlichem/nicht vertrauenswürdigem Ingress ein.
-- Nach dem Pairing stellt das Gateway ein **Gerätetoken** aus, das auf die Verbindungs-
- Rolle + Scopes begrenzt ist. Es wird in `hello-ok.auth.deviceToken` zurückgegeben und sollte
+- `gateway.auth.mode: "none"` für privaten Ingress überspringt die Connect-Auth per Shared Secret
+ vollständig; diesen Modus nicht auf öffentlichem/nicht vertrauenswürdigem Ingress bereitstellen.
+- Nach dem Pairing stellt das Gateway ein **Device-Token** aus, das auf die Rollen + Scopes
+ der Verbindung begrenzt ist. Es wird in `hello-ok.auth.deviceToken` zurückgegeben und sollte
vom Client für zukünftige Verbindungen persistiert werden.
- Clients sollten das primäre `hello-ok.auth.deviceToken` nach jeder
erfolgreichen Verbindung persistieren.
-- Eine erneute Verbindung mit diesem **gespeicherten** Gerätetoken sollte außerdem den gespeicherten
- genehmigten Scope-Satz für dieses Token wiederverwenden. Dadurch bleibt bereits gewährter
- Lese-/Probe-/Status-Zugriff erhalten und es wird vermieden, dass Reconnects stillschweigend auf einen
- engeren impliziten Admin-Only-Scope zurückfallen.
-- Die normale Priorität bei Connect-Auth ist zuerst explizites gemeinsames Token/Passwort, dann
- explizites `deviceToken`, dann gespeichertes gerätespezifisches Token, dann Bootstrap-Token.
-- Zusätzliche Einträge in `hello-ok.auth.deviceTokens` sind Bootstrap-Übergabetoken.
- Persistieren Sie diese nur, wenn die Verbindung Bootstrap-Auth auf einem vertrauenswürdigen Transport
- wie `wss://` oder Loopback/lokal verwendet hat.
+- Beim erneuten Verbinden mit diesem **gespeicherten** Device-Token sollte auch der gespeicherte
+ genehmigte Scope-Satz für dieses Token wiederverwendet werden. Dadurch bleibt bereits gewährter
+ Zugriff für Lesen/Probe/Status erhalten und es wird vermieden, dass Reconnects stillschweigend auf einen
+ engeren impliziten Admin-only-Scope zusammenfallen.
+- Clientseitiger Aufbau der Connect-Auth (`selectConnectAuth` in
+ `src/gateway/client.ts`):
+ - `auth.password` ist orthogonal und wird immer weitergeleitet, wenn gesetzt.
+ - `auth.token` wird in dieser Prioritätsreihenfolge befüllt: zuerst explizites Shared Token,
+ dann ein explizites `deviceToken`, dann ein gespeichertes gerätespezifisches Token (indiziert nach
+ `deviceId` + `role`).
+ - `auth.bootstrapToken` wird nur gesendet, wenn keines der oben genannten ein
+ `auth.token` aufgelöst hat. Ein Shared Token oder ein aufgelöstes Device-Token unterdrückt es.
+ - Automatische Promotion eines gespeicherten Device-Tokens beim einmaligen
+ Retry bei `AUTH_TOKEN_MISMATCH` ist **nur für vertrauenswürdige Endpunkte** aktiviert —
+ Loopback oder `wss://` mit angeheftetem `tlsFingerprint`. Öffentliches `wss://`
+ ohne Pinning qualifiziert sich nicht.
+- Zusätzliche Einträge in `hello-ok.auth.deviceTokens` sind Bootstrap-Handoff-Tokens.
+ Persistiere sie nur, wenn die Verbindung Bootstrap-Auth über einen vertrauenswürdigen Transport
+ wie `wss://` oder Loopback/lokales Pairing verwendet hat.
- Wenn ein Client ein **explizites** `deviceToken` oder explizite `scopes` angibt, bleibt dieser
- vom Aufrufer angeforderte Scope-Satz maßgeblich; gecachte Scopes werden nur
- wiederverwendet, wenn der Client das gespeicherte gerätespezifische Token wiederverwendet.
-- Gerätetoken können über `device.token.rotate` und
- `device.token.revoke` rotiert/widerrufen werden (erfordert Scope `operator.pairing`).
-- Die Ausgabe/Rotation von Token bleibt auf den genehmigten Rollensatz begrenzt, der im
- Pairing-Eintrag dieses Geräts gespeichert ist; durch das Rotieren eines Tokens kann das Gerät nicht auf eine
- Rolle erweitert werden, die durch die Pairing-Genehmigung nie erteilt wurde.
-- Für Sitzungen mit gepaarten Gerätetokens ist die Geräteverwaltung auf das eigene Gerät beschränkt, sofern der
+ vom Aufrufer angeforderte Scope-Satz maßgeblich; gecachte Scopes werden nur wiederverwendet, wenn
+ der Client das gespeicherte gerätespezifische Token wiederverwendet.
+- Device-Tokens können über `device.token.rotate` und
+ `device.token.revoke` rotiert/widerrufen werden (erfordert den Scope `operator.pairing`).
+- Ausstellung/Rotation von Tokens bleibt auf den genehmigten Rollensatz beschränkt, der im
+ Pairing-Eintrag dieses Geräts aufgezeichnet ist; durch die Rotation eines Tokens kann ein Gerät nicht
+ auf eine Rolle erweitert werden, die durch die Pairing-Genehmigung nie gewährt wurde.
+- Für Sitzungen mit Tokens gekoppelter Geräte ist die Geräteverwaltung selbstbegrenzt, sofern der
Aufrufer nicht zusätzlich `operator.admin` hat: Nicht-Admin-Aufrufer können nur ihren **eigenen**
Geräteeintrag entfernen/widerrufen/rotieren.
- `device.token.rotate` prüft außerdem den angeforderten Operator-Scope-Satz gegen die
aktuellen Sitzungsscopes des Aufrufers. Nicht-Admin-Aufrufer können ein Token nicht in einen
- breiteren Operator-Scope-Satz rotieren, als sie bereits besitzen.
-- Auth-Fehler enthalten `error.details.code` plus Wiederherstellungshinweise:
- - `error.details.canRetryWithDeviceToken` (boolean)
+ umfassenderen Operator-Scope-Satz rotieren, als sie bereits besitzen.
+- Auth-Fehler enthalten `error.details.code` sowie Wiederherstellungshinweise:
+ - `error.details.canRetryWithDeviceToken` (boolesch)
- `error.details.recommendedNextStep` (`retry_with_device_token`, `update_auth_configuration`, `update_auth_credentials`, `wait_then_retry`, `review_auth_configuration`)
-- Client-Verhalten für `AUTH_TOKEN_MISMATCH`:
- - Vertrauenswürdige Clients können einen begrenzten Wiederholungsversuch mit einem gecachten gerätespezifischen Token unternehmen.
- - Wenn dieser Wiederholungsversuch fehlschlägt, sollten Clients automatische Reconnect-Schleifen beenden und Hinweise für erforderliche Operatoraktionen anzeigen.
+- Client-Verhalten bei `AUTH_TOKEN_MISMATCH`:
+ - Vertrauenswürdige Clients können einen begrenzten Retry mit einem gecachten gerätespezifischen Token versuchen.
+ - Wenn dieser Retry fehlschlägt, sollten Clients automatische Reconnect-Schleifen stoppen und Hinweise für Operator-Aktionen anzeigen.
## Geräteidentität + Pairing
-- Knoten sollten eine stabile Geräteidentität (`device.id`) angeben, die von einem
+- Nodes sollten eine stabile Geräteidentität (`device.id`) angeben, die aus einem
Schlüsselpaar-Fingerprint abgeleitet ist.
-- Gateways stellen Token pro Gerät + Rolle aus.
-- Pairing-Genehmigungen sind für neue Geräte-IDs erforderlich, sofern keine lokale automatische Genehmigung
- aktiviert ist.
-- Die automatische Pairing-Genehmigung konzentriert sich auf direkte lokale local loopback-Verbindungen.
-- OpenClaw hat außerdem einen engen backend-/containerlokalen Self-Connect-Pfad für
- vertrauenswürdige Helper-Flows mit gemeinsamem Secret.
-- Same-Host-Tailnet- oder LAN-Verbindungen werden für das Pairing weiterhin als remote behandelt und
+- Gateways stellen Tokens pro Gerät + Rolle aus.
+- Pairing-Genehmigungen sind für neue Geräte-IDs erforderlich, sofern lokale automatische Genehmigung
+ nicht aktiviert ist.
+- Die automatische Pairing-Genehmigung ist auf direkte lokale Loopback-Verbindungen ausgerichtet.
+- OpenClaw hat außerdem einen engen lokalen Self-Connect-Pfad für Backend-/Container-
+ Kontexte für vertrauenswürdige Shared-Secret-Helferabläufe.
+- Verbindungen über dasselbe Host-Tailnet oder LAN werden für Pairing weiterhin als remote behandelt und
erfordern eine Genehmigung.
-- Alle WS-Clients müssen während `connect` eine `device`-Identität angeben (operator + node).
+- Alle WS-Clients müssen während `connect` die Geräteidentität `device` angeben (`operator` + `node`).
Control UI kann sie nur in diesen Modi weglassen:
- - `gateway.controlUi.allowInsecureAuth=true` für localhost-only inkompatibilitätsbedingte unsichere HTTP-Unterstützung.
- - erfolgreiche `gateway.auth.mode: "trusted-proxy"`-Authentifizierung für operator Control UI.
- - `gateway.controlUi.dangerouslyDisableDeviceAuth=true` (Break-Glass, schwerwiegende Sicherheitsverschlechterung).
-- Alle Verbindungen müssen den vom Server bereitgestellten `connect.challenge`-Nonce signieren.
+ - `gateway.controlUi.allowInsecureAuth=true` für localhost-only-Kompatibilität mit unsicherem HTTP.
+ - erfolgreiche `gateway.auth.mode: "trusted-proxy"`-Authentifizierung der Operator-Control-UI.
+ - `gateway.controlUi.dangerouslyDisableDeviceAuth=true` (Break-Glass, erhebliche Sicherheitsabsenkung).
+- Alle Verbindungen müssen die vom Server bereitgestellte Nonce `connect.challenge` signieren.
-### Diagnostik für die Migration der Geräteauthentifizierung
+### Migrationsdiagnostik für Geräte-Auth
Für Legacy-Clients, die noch das Signaturverhalten vor der Challenge verwenden, gibt `connect` jetzt
-`DEVICE_AUTH_*`-Detailcodes unter `error.details.code` mit einem stabilen `error.details.reason` zurück.
+Detailcodes `DEVICE_AUTH_*` unter `error.details.code` mit einem stabilen `error.details.reason` zurück.
Häufige Migrationsfehler:
-| Nachricht | details.code | details.reason | Bedeutung |
-| ---------------------------- | -------------------------------- | ------------------------ | --------------------------------------------------- |
-| `device nonce required` | `DEVICE_AUTH_NONCE_REQUIRED` | `device-nonce-missing` | Client hat `device.nonce` weggelassen (oder leer gesendet). |
-| `device nonce mismatch` | `DEVICE_AUTH_NONCE_MISMATCH` | `device-nonce-mismatch` | Client hat mit einem veralteten/falschen Nonce signiert. |
-| `device signature invalid` | `DEVICE_AUTH_SIGNATURE_INVALID` | `device-signature` | Die Signatur-Payload stimmt nicht mit der v2-Payload überein. |
-| `device signature expired` | `DEVICE_AUTH_SIGNATURE_EXPIRED` | `device-signature-stale` | Der signierte Zeitstempel liegt außerhalb der zulässigen Abweichung. |
-| `device identity mismatch` | `DEVICE_AUTH_DEVICE_ID_MISMATCH` | `device-id-mismatch` | `device.id` stimmt nicht mit dem Public-Key-Fingerprint überein. |
-| `device public key invalid` | `DEVICE_AUTH_PUBLIC_KEY_INVALID` | `device-public-key` | Format/Kanonisierung des Public Key ist fehlgeschlagen. |
+| Meldung | details.code | details.reason | Bedeutung |
+| --------------------------- | -------------------------------- | ------------------------ | ----------------------------------------------------------- |
+| `device nonce required` | `DEVICE_AUTH_NONCE_REQUIRED` | `device-nonce-missing` | Client hat `device.nonce` weggelassen (oder leer gesendet). |
+| `device nonce mismatch` | `DEVICE_AUTH_NONCE_MISMATCH` | `device-nonce-mismatch` | Client hat mit einer veralteten/falschen Nonce signiert. |
+| `device signature invalid` | `DEVICE_AUTH_SIGNATURE_INVALID` | `device-signature` | Signatur-Payload entspricht nicht der v2-Payload. |
+| `device signature expired` | `DEVICE_AUTH_SIGNATURE_EXPIRED` | `device-signature-stale` | Signierter Zeitstempel liegt außerhalb des erlaubten Skews. |
+| `device identity mismatch` | `DEVICE_AUTH_DEVICE_ID_MISMATCH` | `device-id-mismatch` | `device.id` entspricht nicht dem Public-Key-Fingerprint. |
+| `device public key invalid` | `DEVICE_AUTH_PUBLIC_KEY_INVALID` | `device-public-key` | Public-Key-Format/Kanonisierung fehlgeschlagen. |
Migrationsziel:
-- Warten Sie immer auf `connect.challenge`.
-- Signieren Sie die v2-Payload, die den Server-Nonce enthält.
-- Senden Sie denselben Nonce in `connect.params.device.nonce`.
+- Immer auf `connect.challenge` warten.
+- Die v2-Payload signieren, die die Server-Nonce enthält.
+- Dieselbe Nonce in `connect.params.device.nonce` senden.
- Die bevorzugte Signatur-Payload ist `v3`, die zusätzlich zu den Feldern für device/client/role/scopes/token/nonce auch `platform` und `deviceFamily` bindet.
-- Legacy-`v2`-Signaturen bleiben aus Kompatibilitätsgründen akzeptiert, aber das Pinning der gepaarten Geräte-
- Metadaten steuert weiterhin die Befehlsrichtlinie beim Wiederverbinden.
+- Legacy-Signaturen vom Typ `v2` bleiben aus Kompatibilitätsgründen akzeptiert, aber das Anheften von Metadaten gekoppelter Geräte steuert weiterhin die Befehlsrichtlinie beim erneuten Verbinden.
## TLS + Pinning
- TLS wird für WS-Verbindungen unterstützt.
-- Clients können optional den Gateway-Zertifikat-Fingerprint pinnen (siehe `gateway.tls`-
- Konfiguration plus `gateway.remote.tlsFingerprint` oder CLI `--tls-fingerprint`).
+- Clients können optional den Fingerprint des Gateway-Zertifikats anheften (siehe Konfiguration `gateway.tls`
+ sowie `gateway.remote.tlsFingerprint` oder CLI `--tls-fingerprint`).
-## Scope
+## Umfang
-Dieses Protokoll stellt die **vollständige Gateway-API** bereit (status, channels, models, chat,
-agent, sessions, nodes, approvals usw.). Die genaue Oberfläche ist durch die
+Dieses Protokoll stellt die **vollständige Gateway-API** bereit (Status, Channels, Modelle, Chat,
+Agent, Sitzungen, Nodes, Genehmigungen usw.). Die genaue Oberfläche wird durch die
TypeBox-Schemas in `src/gateway/protocol/schema.ts` definiert.
diff --git a/docs/de/refactor/async-exec-duplicate-completion-investigation.md b/docs/de/refactor/async-exec-duplicate-completion-investigation.md
new file mode 100644
index 000000000..8835bfe60
--- /dev/null
+++ b/docs/de/refactor/async-exec-duplicate-completion-investigation.md
@@ -0,0 +1,132 @@
+---
+x-i18n:
+ generated_at: "2026-04-16T06:22:19Z"
+ model: gpt-5.4
+ provider: openai
+ source_hash: 95e56c5411204363676f002059c942201503e2359515d1a4b409882cc2e04920
+ source_path: refactor/async-exec-duplicate-completion-investigation.md
+ workflow: 15
+---
+
+# Untersuchung zu doppeltem Abschluss bei Async Exec
+
+## Umfang
+
+- Sitzung: `agent:main:telegram:group:-1003774691294:topic:1`
+- Symptom: Derselbe Async-Exec-Abschluss für Sitzung/Run `keen-nexus` wurde in LCM zweimal als Nutzer-Turn erfasst.
+- Ziel: Ermitteln, ob dies höchstwahrscheinlich eine doppelte Sitzungsinjektion oder ein einfacher Retry bei der ausgehenden Zustellung ist.
+
+## Schlussfolgerung
+
+Am wahrscheinlichsten ist dies eine **doppelte Sitzungsinjektion**, nicht ein reiner Retry bei der ausgehenden Zustellung.
+
+Die stärkste Lücke auf Gateway-Seite liegt im **Pfad für Node-Exec-Abschlüsse**:
+
+1. Ein Exec-Abschluss auf Node-Seite sendet `exec.finished` mit der vollständigen `runId`.
+2. Gateway `server-node-events` wandelt das in ein System-Event um und fordert einen Heartbeat an.
+3. Der Heartbeat-Run injiziert den geleerten System-Event-Block in den Agent-Prompt.
+4. Der eingebettete Runner persistiert diesen Prompt als neuen Nutzer-Turn im Sitzungs-Transkript.
+
+Wenn dasselbe `exec.finished` aus irgendeinem Grund (Replay, erneute Verbindung mit Duplikat, erneutes Senden Upstream, duplizierter Producer) zweimal mit derselben `runId` beim Gateway ankommt, hat OpenClaw auf diesem Pfad derzeit **keine Idempotenzprüfung, die nach `runId`/`contextKey` schlüsselt**. Die zweite Kopie wird zu einer zweiten Nutzernachricht mit identischem Inhalt.
+
+## Exakter Code-Pfad
+
+### 1. Producer: Event für Node-Exec-Abschluss
+
+- `src/node-host/invoke.ts:340-360`
+ - `sendExecFinishedEvent(...)` sendet `node.event` mit dem Event `exec.finished`.
+ - Die Payload enthält `sessionKey` und die vollständige `runId`.
+
+### 2. Gateway-Event-Ingestion
+
+- `src/gateway/server-node-events.ts:574-640`
+ - Verarbeitet `exec.finished`.
+ - Baut Text auf:
+ - `Exec finished (node=..., id=, code ...)`
+ - Stellt ihn in die Queue über:
+ - `enqueueSystemEvent(text, { sessionKey, contextKey: runId ? \`exec:${runId}\` : "exec", trusted: false })`
+ - Fordert sofort ein Wake an:
+ - `requestHeartbeatNow(scopedHeartbeatWakeOptions(sessionKey, { reason: "exec-event" }))`
+
+### 3. Schwäche bei der Deduplizierung von System-Events
+
+- `src/infra/system-events.ts:90-115`
+ - `enqueueSystemEvent(...)` unterdrückt nur **aufeinanderfolgende doppelte Texte**:
+ - `if (entry.lastText === cleaned) return false`
+ - Es speichert `contextKey`, verwendet `contextKey` jedoch **nicht** für Idempotenz.
+ - Nach dem Drain wird die Duplikatunterdrückung zurückgesetzt.
+
+Das bedeutet: Ein erneut gesendetes `exec.finished` mit derselben `runId` kann später erneut akzeptiert werden, obwohl der Code bereits einen stabilen Kandidaten für Idempotenz hatte (`exec:`).
+
+### 4. Wake-Handling ist nicht der primäre Verursacher von Duplikaten
+
+- `src/infra/heartbeat-wake.ts:79-117`
+ - Wakes werden nach `(agentId, sessionKey)` zusammengefasst.
+ - Doppelte Wake-Anfragen für dasselbe Ziel werden zu einem ausstehenden Wake-Eintrag zusammengeführt.
+
+Dadurch ist **doppeltes Wake-Handling allein** eine schwächere Erklärung als doppelte Event-Ingestion.
+
+### 5. Heartbeat verarbeitet das Event und macht daraus Prompt-Eingabe
+
+- `src/infra/heartbeat-runner.ts:535-574`
+ - Preflight prüft ausstehende System-Events vorab und klassifiziert Runs mit Exec-Events.
+- `src/auto-reply/reply/session-system-events.ts:86-90`
+ - `drainFormattedSystemEvents(...)` leert die Queue für die Sitzung.
+- `src/auto-reply/reply/get-reply-run.ts:400-427`
+ - Der geleerte System-Event-Block wird dem Agent-Prompt-Body vorangestellt.
+
+### 6. Injektionspunkt ins Transkript
+
+- `src/agents/pi-embedded-runner/run/attempt.ts:2000-2017`
+ - `activeSession.prompt(effectivePrompt)` übergibt den vollständigen Prompt an die eingebettete PI-Sitzung.
+ - Das ist der Punkt, an dem der vom Abschluss abgeleitete Prompt als persistierter Nutzer-Turn gespeichert wird.
+
+Sobald also dasselbe System-Event zweimal in den Prompt eingebaut wird, sind doppelte LCM-Nutzernachrichten zu erwarten.
+
+## Warum ein einfacher Retry bei der ausgehenden Zustellung weniger wahrscheinlich ist
+
+Es gibt einen realen Fehlerpfad für ausgehende Zustellung im Heartbeat-Runner:
+
+- `src/infra/heartbeat-runner.ts:1194-1242`
+ - Die Antwort wird zuerst generiert.
+ - Die ausgehende Zustellung erfolgt später über `deliverOutboundPayloads(...)`.
+ - Ein Fehler dort liefert `{ status: "failed" }` zurück.
+
+Für denselben System-Event-Queue-Eintrag reicht das allein jedoch **nicht aus**, um die doppelten Nutzer-Turns zu erklären:
+
+- `src/auto-reply/reply/session-system-events.ts:86-90`
+ - Die System-Event-Queue ist bereits geleert, bevor die ausgehende Zustellung erfolgt.
+
+Ein Retry beim Kanalversand allein würde das exakt gleiche Queue-Event also nicht erneut erzeugen. Das könnte fehlende/fehlgeschlagene externe Zustellung erklären, aber für sich genommen nicht eine zweite identische Nutzer-Nachricht in der Sitzung.
+
+## Sekundäre Möglichkeit mit geringerer Sicherheit
+
+Es gibt eine Retry-Schleife für vollständige Runs im Agent-Runner:
+
+- `src/auto-reply/reply/agent-runner-execution.ts:741-1473`
+ - Bestimmte transiente Fehler können den gesamten Run erneut versuchen und denselben `commandBody` erneut absenden.
+
+Das kann einen persistierten Nutzer-Prompt **innerhalb derselben Antwortausführung** duplizieren, wenn der Prompt bereits angehängt wurde, bevor die Retry-Bedingung ausgelöst hat.
+
+Ich stufe das niedriger ein als doppelte `exec.finished`-Ingestion, weil:
+
+- der beobachtete Abstand bei etwa 51 Sekunden lag, was eher wie ein zweiter Wake/Turn aussieht als wie ein In-Process-Retry;
+- im Bericht bereits wiederholte Fehler beim Nachrichtensenden erwähnt werden, was eher auf einen separaten späteren Turn hindeutet als auf einen unmittelbaren Modell-/Runtime-Retry.
+
+## Hypothese zur Grundursache
+
+Hypothese mit der höchsten Sicherheit:
+
+- Der Abschluss von `keen-nexus` kam über den **Node-Exec-Event-Pfad**.
+- Dasselbe `exec.finished` wurde zweimal an `server-node-events` zugestellt.
+- Das Gateway akzeptierte beide, weil `enqueueSystemEvent(...)` nicht nach `contextKey` / `runId` dedupliziert.
+- Jedes akzeptierte Event löste einen Heartbeat aus und wurde als Nutzer-Turn in das PI-Transkript injiziert.
+
+## Vorgeschlagener kleiner, gezielter Fix
+
+Falls ein Fix gewünscht ist, ist die kleinste Änderung mit hohem Nutzen:
+
+- dafür zu sorgen, dass die Idempotenz von Exec-/System-Events `contextKey` für einen kurzen Zeitraum berücksichtigt, zumindest für exakte Wiederholungen von `(sessionKey, contextKey, text)`;
+- oder eine dedizierte Deduplizierung in `server-node-events` für `exec.finished` hinzuzufügen, geschlüsselt nach `(sessionKey, runId, event kind)`.
+
+Das würde erneut gesendete `exec.finished`-Duplikate direkt blockieren, bevor sie zu Sitzungsturns werden.