Diffs

diffs 是一個選用的外掛工具,內建簡短的系統引導說明,並附帶一個輔助技能,可將變更內容轉換為代理的唯讀 diff 成品。

它接受:

  • beforeafter 文字
  • 統一格式的 patch

它可以回傳:

  • Gateway 檢視器 URL,供 canvas 呈現
  • 渲染後的檔案路徑(PNG 或 PDF),供訊息投遞
  • 單次呼叫同時產生兩種輸出

啟用後,外掛會將簡潔的使用引導注入系統提示空間,同時公開一個詳細的技能,供代理需要更完整指示時使用。

快速上手

  1. 啟用外掛。
  2. mode: "view" 呼叫 diffs,適用於以 canvas 為主的流程。
  3. mode: "file" 呼叫 diffs,適用於聊天檔案投遞流程。
  4. mode: "both" 呼叫 diffs,同時需要兩種成品時使用。

啟用外掛

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

停用內建系統引導

如果你想保留 diffs 工具但停用其內建的系統提示引導,將 plugins.entries.diffs.hooks.allowPromptInjection 設為 false

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

這會阻擋 diffs 外掛的 before_prompt_build 鉤子,同時保留外掛、工具和輔助技能可用。

如果你想同時停用引導和工具,請直接停用外掛。

典型的代理工作流程

  1. 代理呼叫 diffs
  2. 代理讀取 details 欄位。
  3. 代理選擇:
    • canvas present 開啟 details.viewerUrl
    • message 透過 pathfilePath 傳送 details.filePath
    • 兩者都做

輸入範例

Before 和 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"
}

工具輸入參考

除非另有說明,所有欄位皆為選填:

  • beforestring):原始文字。省略 patch 時需與 after 一起提供。
  • afterstring):更新後的文字。省略 patch 時需與 before 一起提供。
  • patchstring):統一格式的 diff 文字。與 beforeafter 互斥。
  • pathstring):before 和 after 模式的顯示檔名。
  • langstring):before 和 after 模式的語言覆寫提示。
  • titlestring):檢視器標題覆寫。
  • mode"view" | "file" | "both"):輸出模式。預設為外掛的 defaults.mode
  • theme"light" | "dark"):檢視器主題。預設為外掛的 defaults.theme
  • layout"unified" | "split"):diff 版面。預設為外掛的 defaults.layout
  • expandUnchangedboolean):在有完整上下文時展開未變更的區段。僅限單次呼叫選項(不是外掛預設 key)。
  • fileFormat"png" | "pdf"):渲染的檔案格式。預設為外掛的 defaults.fileFormat
  • fileQuality"standard" | "hq" | "print"):PNG 或 PDF 渲染的品質預設。
  • fileScalenumber):裝置縮放覆寫(1-4)。
  • fileMaxWidthnumber):最大渲染寬度,CSS 像素(640-2400)。
  • ttlSecondsnumber):檢視器成品的 TTL 秒數。預設 1800,最大 21600。
  • baseUrlstring):檢視器 URL 來源覆寫。必須是 httphttps,不可有查詢字串 / hash。

驗證和限制:

  • beforeafter 各自最大 512 KiB。
  • patch 最大 2 MiB。
  • path 最大 2048 bytes。
  • lang 最大 128 bytes。
  • title 最大 1024 bytes。
  • Patch 複雜度上限:最多 128 個檔案和 120000 總行數。
  • patchbeforeafter 同時提供會被拒絕。
  • 渲染檔案的安全限制(適用於 PNG 和 PDF):
    • fileQuality: "standard":最大 8 MP(8,000,000 渲染像素)。
    • fileQuality: "hq":最大 14 MP(14,000,000 渲染像素)。
    • fileQuality: "print":最大 24 MP(24,000,000 渲染像素)。
    • PDF 另有最多 50 頁的限制。

輸出 details 合約

工具在 details 底下回傳結構化的元資料。

建立檢視器的模式共用欄位:

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

渲染 PNG 或 PDF 時的檔案欄位:

  • filePath
  • path(與 filePath 相同,供 message 工具相容)
  • fileBytes
  • fileFormat
  • fileQuality
  • fileScale
  • fileMaxWidth

模式行為摘要:

  • mode: "view":僅檢視器欄位。
  • mode: "file":僅檔案欄位,不建立檢視器成品。
  • mode: "both":檢視器欄位加檔案欄位。如果檔案渲染失敗,檢視器仍會回傳並附帶 fileError

折疊的未變更區段

  • 檢視器可能顯示 N unmodified lines 之類的行。
  • 這些行上的展開控制項是有條件的,不保證每種輸入都有。
  • 當渲染的 diff 有可展開的上下文資料時才會出現展開控制項,通常在 before 和 after 輸入時出現。
  • 對於許多統一 patch 輸入,省略的上下文主體在解析的 patch hunk 中不可用,因此該行可能沒有展開控制項。這是預期行為。
  • expandUnchanged 僅在有可展開的上下文時生效。

外掛預設值

~/.openclaw/openclaw.json 中設定外掛全域預設值:

{
  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",
          },
        },
      },
    },
  },
}

支援的預設值:

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

明確的工具參數會覆寫這些預設值。

安全性設定

  • security.allowRemoteViewerboolean,預設 false
    • false:拒絕非回環的檢視器路由請求。
    • true:如果 token 化路徑有效則允許遠端檢視器。

範例:

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

成品生命週期和儲存

  • 成品儲存在暫存子資料夾:$TMPDIR/openclaw-diffs
  • 檢視器成品的元資料包含:
    • 隨機成品 ID(20 個十六進位字元)
    • 隨機 token(48 個十六進位字元)
    • createdAtexpiresAt
    • 儲存的 viewer.html 路徑
  • 未指定時,檢視器預設 TTL 為 30 分鐘。
  • 最大可接受的檢視器 TTL 為 6 小時。
  • 清理在成品建立後伺機執行。
  • 過期的成品會被刪除。
  • 元資料遺失時,超過 24 小時的過期資料夾會被後備清理機制移除。

檢視器 URL 和網路行為

檢視器路由:

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

檢視器資源:

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

URL 建構行為:

  • 如果提供了 baseUrl,經過嚴格驗證後使用。
  • 未提供 baseUrl 時,檢視器 URL 預設為回環 127.0.0.1
  • 如果 Gateway 繫結模式為 custom 且設定了 gateway.customBindHost,則使用該主機。

baseUrl 規則:

  • 必須是 http://https://
  • 查詢字串和 hash 會被拒絕。
  • 允許 origin 加上選用的基底路徑。

安全模型

檢視器加固:

  • 預設僅限回環。
  • token 化的檢視器路徑,嚴格驗證 ID 和 token。
  • 檢視器回應 CSP:
    • default-src 'none'
    • scripts 和 assets 僅從 self
    • 無對外 connect-src
  • 啟用遠端存取時的失敗限流:
    • 每 60 秒 40 次失敗
    • 60 秒鎖定(429 Too Many Requests

檔案渲染加固:

  • 截圖瀏覽器的請求路由預設為拒絕。
  • 僅允許來自 http://127.0.0.1/plugins/diffs/assets/* 的本地檢視器資源。
  • 外部網路請求被阻擋。

檔案模式的瀏覽器需求

mode: "file"mode: "both" 需要 Chromium 相容的瀏覽器。

解析順序:

  1. OpenClaw 設定中的 browser.executablePath
  2. 環境變數:
    • OPENCLAW_BROWSER_EXECUTABLE_PATH
    • BROWSER_EXECUTABLE_PATH
    • PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH
  3. 平台指令 / 路徑探索後備。

常見的失敗訊息:

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

安裝 Chrome、Chromium、Edge 或 Brave,或設定上述其中一個執行路徑選項即可修復。

疑難排解

輸入驗證錯誤:

  • Provide patch or both before and after text.
    • 同時提供 beforeafter,或提供 patch
  • Provide either patch or before/after input, not both.
    • 不要混用輸入模式。
  • Invalid baseUrl: ...
    • 使用帶有選用路徑的 http(s) origin,不可有查詢字串 / hash。
  • {field} exceeds maximum size (...)
    • 減少 payload 大小。
  • 大型 patch 被拒絕
    • 減少 patch 的檔案數或總行數。

檢視器可達性問題:

  • 檢視器 URL 預設解析為 127.0.0.1
  • 遠端存取情境:
    • 每次工具呼叫傳入 baseUrl,或
    • 使用 gateway.bind=customgateway.customBindHost
  • 僅在需要外部檢視器存取時才啟用 security.allowRemoteViewer

未變更行沒有展開按鈕:

  • patch 輸入不帶可展開上下文時可能發生。
  • 這是預期行為,不表示檢視器故障。

成品找不到:

  • 成品因 TTL 過期。
  • Token 或路徑已變更。
  • 清理機制移除了過期資料。

操作建議

  • 本地互動式審閱建議使用 mode: "view",在 canvas 中檢視。
  • 需要附件的外部聊天頻道建議使用 mode: "file"
  • 除非部署環境需要遠端檢視器 URL,否則保持 allowRemoteViewer 停用。
  • 敏感的 diff 設定較短的明確 ttlSeconds
  • 非必要時避免在 diff 輸入中傳送機密資料。
  • 如果你的頻道會積極壓縮圖片(例如 Telegram 或 WhatsApp),建議使用 PDF 輸出(fileFormat: "pdf")。

Diff 渲染引擎:

相關文件