Diffs

diffs ist ein optionales Plugin-Tool mit kurzer eingebauter Systemanleitung und einem begleitenden Skill, der geänderte Inhalte in ein schreibgeschütztes Diff-Artefakt für Agenten umwandelt.

Es akzeptiert entweder:

  • before- und after-Text
  • einen Unified-patch

Es kann zurückgeben:

  • eine Gateway-Viewer-URL für Canvas-Präsentation
  • einen gerenderten Dateipfad (PNG oder PDF) für Nachrichtenzustellung
  • beide Ausgaben in einem Aufruf

Wenn aktiviert, fügt das Plugin knappe Nutzungsanleitung in den System-Prompt-Bereich ein und stellt auch einen detaillierten Skill für Fälle bereit, in denen der Agent ausführlichere Anweisungen benötigt.

Schnellstart

  1. Plugin aktivieren.
  2. diffs mit mode: "view" für Canvas-First-Flows aufrufen.
  3. diffs mit mode: "file" für Chat-Dateizustellungs-Flows aufrufen.
  4. diffs mit mode: "both" aufrufen, wenn du beide Artefakte brauchst.

Plugin aktivieren

{
  plugins: {
    entries: {
      diffs: {
        enabled: true,
      },
    },
  },
}

Eingebaute Systemanleitung deaktivieren

Wenn du das diffs-Tool aktiviert lassen, aber seine eingebaute System-Prompt-Anleitung deaktivieren möchtest, setze plugins.entries.diffs.hooks.allowPromptInjection auf false:

{
  plugins: {
    entries: {
      diffs: {
        enabled: true,
        hooks: {
          allowPromptInjection: false,
        },
      },
    },
  },
}

Das blockiert den before_prompt_build-Hook des Diffs-Plugins, während Plugin, Tool und begleitender Skill verfügbar bleiben.

Wenn du sowohl die Anleitung als auch das Tool deaktivieren möchtest, deaktiviere stattdessen das Plugin.

Typischer Agent-Workflow

  1. Agent ruft diffs auf.
  2. Agent liest die details-Felder.
  3. Agent entweder:
    • öffnet details.viewerUrl mit canvas present
    • sendet details.filePath mit message unter Verwendung von path oder filePath
    • tut beides

Eingabebeispiele

Before und After:

{
  "before": "# Hello\n\nOne",
  "after": "# Hello\n\nTwo",
  "path": "docs/example.md",
  "mode": "view"
}

Patch:

{
  "patch": "diff --git a/src/example.ts b/src/example.ts\n--- a/src/example.ts\n+++ b/src/example.ts\n@@ -1 +1 @@\n-const x = 1;\n+const x = 2;\n",
  "mode": "both"
}

Tool-Eingabereferenz

Alle Felder sind optional, sofern nicht anders angegeben:

  • before (string): Originaltext. Erforderlich zusammen mit after, wenn patch weggelassen wird.
  • after (string): Aktualisierter Text. Erforderlich zusammen mit before, wenn patch weggelassen wird.
  • patch (string): Unified-Diff-Text. Gegenseitig exklusiv mit before und after.
  • path (string): Anzeige-Dateiname für Before-und-After-Modus.
  • lang (string): Sprachüberschreibungshinweis für Before-und-After-Modus.
  • title (string): Viewer-Titelüberschreibung.
  • mode ("view" | "file" | "both"): Ausgabemodus. Standardwert ist der Plugin-Standard defaults.mode.
  • theme ("light" | "dark"): Viewer-Theme. Standardwert ist der Plugin-Standard defaults.theme.
  • layout ("unified" | "split"): Diff-Layout. Standardwert ist der Plugin-Standard defaults.layout.
  • expandUnchanged (boolean): Unveränderte Abschnitte erweitern, wenn vollständiger Kontext verfügbar ist. Nur als Einzelaufruf-Option (kein Plugin-Standard-Schlüssel).
  • fileFormat ("png" | "pdf"): Gerendertes Dateiformat. Standardwert ist der Plugin-Standard defaults.fileFormat.
  • fileQuality ("standard" | "hq" | "print"): Qualitäts-Preset für PNG- oder PDF-Rendering.
  • fileScale (number): Device-Scale-Überschreibung (1-4).
  • fileMaxWidth (number): Maximale Renderbreite in CSS-Pixeln (640-2400).
  • ttlSeconds (number): Viewer-Artefakt-TTL in Sekunden. Standard 1800, Maximum 21600.
  • baseUrl (string): Viewer-URL-Origin-Überschreibung. Muss http oder https sein, kein Query/Hash.

Validierung und Limits:

  • before und after jeweils maximal 512 KiB.
  • patch maximal 2 MiB.
  • path maximal 2048 Bytes.
  • lang maximal 128 Bytes.
  • title maximal 1024 Bytes.
  • Patch-Komplexitätsobergrenze: maximal 128 Dateien und 120000 Gesamtzeilen.
  • patch und before oder after zusammen werden abgelehnt.
  • Sicherheitslimits für gerenderte Dateien (gelten für PNG und PDF):
    • fileQuality: "standard": maximal 8 MP (8.000.000 gerenderte Pixel).
    • fileQuality: "hq": maximal 14 MP (14.000.000 gerenderte Pixel).
    • fileQuality: "print": maximal 24 MP (24.000.000 gerenderte Pixel).
    • PDF hat zusätzlich ein Maximum von 50 Seiten.

Ausgabe-Details-Vertrag

Das Tool gibt strukturierte Metadaten unter details zurück.

Gemeinsame Felder für Modi, die einen Viewer erstellen:

  • artifactId
  • viewerUrl
  • viewerPath
  • title
  • expiresAt
  • inputKind
  • fileCount
  • mode

Dateifelder, wenn PNG oder PDF gerendert wird:

  • filePath
  • path (gleicher Wert wie filePath, für Kompatibilität mit dem Message-Tool)
  • fileBytes
  • fileFormat
  • fileQuality
  • fileScale
  • fileMaxWidth

Modusverhalten-Zusammenfassung:

  • mode: "view": nur Viewer-Felder.
  • mode: "file": nur Dateifelder, kein Viewer-Artefakt.
  • mode: "both": Viewer-Felder plus Dateifelder. Wenn das Datei-Rendering fehlschlägt, wird der Viewer trotzdem mit fileError zurückgegeben.

Eingeklappte unveränderte Abschnitte

  • Der Viewer kann Zeilen wie N unmodified lines anzeigen.
  • Erweitern-Steuerungen auf diesen Zeilen sind bedingt und nicht für jeden Eingabetyp garantiert.
  • Erweitern-Steuerungen erscheinen, wenn der gerenderte Diff erweiterbare Kontextdaten hat, was typisch für Before-und-After-Eingabe ist.
  • Für viele Unified-Patch-Eingaben sind ausgelassene Kontextkörper in den geparseten Patch-Hunks nicht verfügbar, sodass die Zeile ohne Erweitern-Steuerungen erscheinen kann. Das ist erwartetes Verhalten.
  • expandUnchanged gilt nur, wenn erweiterbarer Kontext vorhanden ist.

Plugin-Standardwerte

Plugin-weite Standardwerte in ~/.openclaw/openclaw.json setzen:

{
  plugins: {
    entries: {
      diffs: {
        enabled: true,
        config: {
          defaults: {
            fontFamily: "Fira Code",
            fontSize: 15,
            lineSpacing: 1.6,
            layout: "unified",
            showLineNumbers: true,
            diffIndicators: "bars",
            wordWrap: true,
            background: true,
            theme: "dark",
            fileFormat: "png",
            fileQuality: "standard",
            fileScale: 2,
            fileMaxWidth: 960,
            mode: "both",
          },
        },
      },
    },
  },
}

Unterstützte Standardwerte:

  • fontFamily
  • fontSize
  • lineSpacing
  • layout
  • showLineNumbers
  • diffIndicators
  • wordWrap
  • background
  • theme
  • fileFormat
  • fileQuality
  • fileScale
  • fileMaxWidth
  • mode

Explizite Tool-Parameter überschreiben diese Standardwerte.

Sicherheitskonfiguration

  • security.allowRemoteViewer (boolean, Standard false)
    • false: Nicht-Loopback-Anfragen an Viewer-Routen werden abgelehnt.
    • true: Remote-Viewer sind erlaubt, wenn der tokenisierte Pfad gültig ist.

Beispiel:

{
  plugins: {
    entries: {
      diffs: {
        enabled: true,
        config: {
          security: {
            allowRemoteViewer: false,
          },
        },
      },
    },
  },
}

Artefakt-Lebenszyklus und Speicher

  • Artefakte werden im Temp-Unterordner gespeichert: $TMPDIR/openclaw-diffs.
  • Viewer-Artefakt-Metadaten enthalten:
    • Zufällige Artefakt-ID (20 Hex-Zeichen)
    • Zufälliges Token (48 Hex-Zeichen)
    • createdAt und expiresAt
    • Gespeicherter viewer.html-Pfad
  • Standard-Viewer-TTL ist 30 Minuten, wenn nicht angegeben.
  • Maximal akzeptierte Viewer-TTL ist 6 Stunden.
  • Bereinigung läuft opportunistisch nach Artefakt-Erstellung.
  • Abgelaufene Artefakte werden gelöscht.
  • Fallback-Bereinigung entfernt veraltete Ordner, die älter als 24 Stunden sind, wenn Metadaten fehlen.

Viewer-URL und Netzwerkverhalten

Viewer-Route:

  • /plugins/diffs/view/{artifactId}/{token}

Viewer-Assets:

  • /plugins/diffs/assets/viewer.js
  • /plugins/diffs/assets/viewer-runtime.js

URL-Konstruktionsverhalten:

  • Wenn baseUrl angegeben wird, wird es nach strikter Validierung verwendet.
  • Ohne baseUrl verwendet die Viewer-URL standardmäßig Loopback 127.0.0.1.
  • Wenn der Gateway-Bind-Modus custom ist und gateway.customBindHost gesetzt ist, wird dieser Host verwendet.

baseUrl-Regeln:

  • Muss http:// oder https:// sein.
  • Query und Hash werden abgelehnt.
  • Origin plus optionaler Basispfad ist erlaubt.

Sicherheitsmodell

Viewer-Absicherung:

  • Standardmäßig nur Loopback.
  • Tokenisierte Viewer-Pfade mit strikter ID- und Token-Validierung.
  • Viewer-Antwort-CSP:
    • default-src 'none'
    • Scripts und Assets nur von self
    • Kein ausgehendes connect-src
  • Remote-Miss-Drosselung, wenn Remote-Zugriff aktiviert ist:
    • 40 Fehlversuche pro 60 Sekunden
    • 60 Sekunden Sperre (429 Too Many Requests)

Datei-Rendering-Absicherung:

  • Screenshot-Browser-Request-Routing ist standardmäßig deny.
  • Nur lokale Viewer-Assets von http://127.0.0.1/plugins/diffs/assets/* sind erlaubt.
  • Externe Netzwerkanfragen werden blockiert.

Browser-Anforderungen für den Dateimodus

mode: "file" und mode: "both" benötigen einen Chromium-kompatiblen Browser.

Auflösungsreihenfolge:

  1. browser.executablePath in der OpenClaw-Konfiguration.
  2. Umgebungsvariablen:
    • OPENCLAW_BROWSER_EXECUTABLE_PATH
    • BROWSER_EXECUTABLE_PATH
    • PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH
  3. Plattform-Befehl/Pfad-Discovery-Fallback.

Häufige Fehlermeldung:

  • Diff PNG/PDF rendering requires a Chromium-compatible browser...

Behebe es durch Installation von Chrome, Chromium, Edge oder Brave, oder durch Setzen einer der oben genannten Executable-Path-Optionen.

Fehlerbehebung

Eingabevalidierungsfehler:

  • Provide patch or both before and after text.
    • Gib sowohl before als auch after an, oder stelle patch bereit.
  • Provide either patch or before/after input, not both.
    • Mische keine Eingabemodi.
  • Invalid baseUrl: ...
    • Verwende http(s)-Origin mit optionalem Pfad, kein Query/Hash.
  • {field} exceeds maximum size (...)
    • Payload-Größe reduzieren.
  • Ablehnung großer Patches
    • Patch-Dateizahl oder Gesamtzeilenzahl reduzieren.

Viewer-Erreichbarkeitsprobleme:

  • Viewer-URL löst standardmäßig auf 127.0.0.1 auf.
  • Für Remote-Zugriffs-Szenarien entweder:
    • baseUrl pro Tool-Aufruf übergeben, oder
    • gateway.bind=custom und gateway.customBindHost verwenden
  • security.allowRemoteViewer nur aktivieren, wenn du externen Viewer-Zugriff beabsichtigst.

Zeile für unveränderte Zeilen hat keinen Erweitern-Button:

  • Das kann bei Patch-Eingabe passieren, wenn der Patch keinen erweiterbaren Kontext enthält.
  • Das ist erwartetes Verhalten und deutet nicht auf einen Viewer-Fehler hin.

Artefakt nicht gefunden:

  • Artefakt durch TTL abgelaufen.
  • Token oder Pfad geändert.
  • Bereinigung hat veraltete Daten entfernt.

Betriebsanleitung

  • Bevorzuge mode: "view" für lokale interaktive Reviews im Canvas.
  • Bevorzuge mode: "file" für ausgehende Chat-Kanäle, die einen Anhang benötigen.
  • Halte allowRemoteViewer deaktiviert, es sei denn, dein Deployment erfordert Remote-Viewer-URLs.
  • Setze explizit kurze ttlSeconds für sensible Diffs.
  • Vermeide das Senden von Geheimnissen in Diff-Eingaben, wenn nicht erforderlich.
  • Wenn dein Kanal Bilder aggressiv komprimiert (zum Beispiel Telegram oder WhatsApp), bevorzuge PDF-Ausgabe (fileFormat: "pdf").

Diff-Rendering-Engine:

Verwandte Dokumentation