Diffs
使用 optional Diffs plugin 将 before and after text 或 unified patches 渲染为 gateway-hosted diff view、file(PNG 或 PDF)或两者。
Diffs
diffs 是一个 optional plugin tool,将 change content 转换为 read-only diff artifact 供 agents 使用。
它接受:
before和aftertext- unified
patch
它可以返回:
- canvas presentation 的 gateway viewer URL
- message delivery 的 rendered file path(PNG 或 PDF)
- 一次调用中的 both outputs
Quick start
- Enable the plugin。
- 调用
diffswithmode: "view"用于 canvas-first flows。 - 调用
diffswithmode: "file"用于 chat file delivery flows。 - 调用
diffswithmode: "both"当你需要 both artifacts。
Enable the plugin
{
plugins: {
entries: {
diffs: {
enabled: true,
},
},
},
}
Typical agent workflow
- Agent 调用
diffs。 - Agent 读取
detailsfields。 - Agent 要么:
- 用
canvas present打开details.viewerUrl - 用
message发送details.filePath使用path或filePath - 两者都做
- 用
Input examples
Before and 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 input reference
所有 fields 是 optional 除非注明:
before(string):original text。当patchomitted 时与after一起 required。after(string):updated text。当patchomitted 时与before一起 required。patch(string):unified diff text。与before和after互斥。path(string):before and after mode 的 display filename。lang(string):before and after mode 的 language override hint。title(string):viewer title override。mode("view" | "file" | "both"):output mode。默认为 plugin defaultdefaults.mode。theme("light" | "dark"):viewer theme。默认为 plugin defaultdefaults.theme。layout("unified" | "split"):diff layout。默认为 plugin defaultdefaults.layout。expandUnchanged(boolean):当 full context available 时 expand unchanged sections。仅 per-call option(不是 plugin default key)。fileFormat("png" | "pdf"):rendered file format。默认为 plugin defaultdefaults.fileFormat。fileQuality("standard" | "hq" | "print"):PNG 或 PDF rendering 的 quality preset。fileScale(number):device scale override(1-4)。fileMaxWidth(number):max render width in CSS pixels(640-2400)。ttlSeconds(number):viewer artifact TTL in seconds。默认 1800,max 21600。baseUrl(string):viewer URL origin override。必须是http或https,no query/hash。
Validation and limits:
before和after每个 max 512 KiB。patchmax 2 MiB。pathmax 2048 bytes。langmax 128 bytes。titlemax 1024 bytes。- Patch complexity cap:max 128 files 和 120000 total lines。
patch和before或aftertogether 被 rejected。- Rendered file safety limits(适用于 PNG 和 PDF):
fileQuality: "standard":max 8 MP(8,000,000 rendered pixels)。fileQuality: "hq":max 14 MP(14,000,000 rendered pixels)。fileQuality: "print":max 24 MP(24,000,000 rendered pixels)。- PDF also has a max of 50 pages。
Output details contract
Tool 在 details 下返回 structured metadata。
为创建 viewer 的 modes 共享 fields:
artifactIdviewerUrlviewerPathtitleexpiresAtinputKindfileCountmode
当 PNG 或 PDF rendered 时的 File fields:
filePathpath(与filePath相同值,用于 message tool compatibility)fileBytesfileFormatfileQualityfileScalefileMaxWidth
Mode behavior summary:
mode: "view":仅 viewer fields。mode: "file":仅 file fields,no viewer artifact。mode: "both":viewer fields plus file fields。如果 file rendering fails,viewer 仍然返回 withfileError。
Collapsed unchanged sections
- Viewer 可以显示 rows like
N unmodified lines。 - 那些 rows 上的 Expand controls 是 conditional 且不 guaranteed for every input kind。
- 当 rendered diff has expandable context data 时 Expand controls appear,这在 before and after input 中是 typical。
- 对于许多 unified patch inputs,omitted context bodies 在 parsed patch hunks 中不可用,所以 row 可以 appear without expand controls。这是 expected behavior。
expandUnchanged仅当 expandable context exists 时适用。
Plugin defaults
在 ~/.openclaw/openclaw.json 中设置 plugin-wide defaults:
{
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",
},
},
},
},
},
}
Supported defaults:
fontFamilyfontSizelineSpacinglayoutshowLineNumbersdiffIndicatorswordWrapbackgroundthemefileFormatfileQualityfileScalefileMaxWidthmode
Explicit tool parameters override these defaults。
Security config
security.allowRemoteViewer(boolean,默认false)false:non-loopback requests to viewer routes are denied。true:remote viewers are allowed if tokenized path is valid。
示例:
{
plugins: {
entries: {
diffs: {
enabled: true,
config: {
security: {
allowRemoteViewer: false,
},
},
},
},
},
}
Artifact lifecycle and storage
- Artifacts stored under the temp subfolder:
$TMPDIR/openclaw-diffs。 - Viewer artifact metadata contains:
- random artifact ID(20 hex chars)
- random token(48 hex chars)
createdAt和expiresAt- stored
viewer.htmlpath
- Default viewer TTL is 30 minutes when not specified。
- Maximum accepted viewer TTL is 6 hours。
- Cleanup runs opportunistically after artifact creation。
- Expired artifacts are deleted。
- Fallback cleanup removes stale folders older than 24 hours when metadata is missing。
Viewer URL and network behavior
Viewer route:
/plugins/diffs/view/{artifactId}/{token}
Viewer assets:
/plugins/diffs/assets/viewer.js/plugins/diffs/assets/viewer-runtime.js
URL construction behavior:
- 如果提供
baseUrl,它在 strict validation 后使用。 - 没有
baseUrl,viewer URL defaults to loopback127.0.0.1。 - 如果 gateway bind mode 是
custom且gateway.customBindHostis set,that host is used。
baseUrl rules:
- Must be
http://orhttps://。 - Query and hash are rejected。
- Origin plus optional base path is allowed。
Security model
Viewer hardening:
- Loopback-only by default。
- Tokenized viewer paths with strict ID and token validation。
- Viewer response CSP:
default-src 'none'- scripts and assets only from self
- no outbound
connect-src
- Remote miss throttling when remote access is enabled:
- 40 failures per 60 seconds
- 60 second lockout(
429 Too Many Requests)
File rendering hardening:
- Screenshot browser request routing is deny-by-default。
- Only local viewer assets from
http://127.0.0.1/plugins/diffs/assets/*are allowed。 - External network requests are blocked。
File mode 的 Browser requirements
mode: "file" 和 mode: "both" 需要 Chromium-compatible browser。
Resolution order:
- OpenClaw config 中的
browser.executablePath。 - Environment variables:
OPENCLAW_BROWSER_EXECUTABLE_PATHBROWSER_EXECUTABLE_PATHPLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH
- Platform command/path discovery fallback。
Common failure text:
Diff PNG/PDF rendering requires a Chromium-compatible browser...
通过安装 Chrome、Chromium、Edge 或 Brave 修复,或设置上述 executable path options 之一。
Troubleshooting
Input validation errors:
Provide patch or both before and after text.- Include both
beforeandafter,或 providepatch。
- Include both
Provide either patch or before/after input, not both.- Do not mix input modes。
Invalid baseUrl: ...- Use
http(s)origin with optional path,no query/hash。
- Use
{field} exceeds maximum size (...)- Reduce payload size。
- Large patch rejection
- Reduce patch file count or total lines。
Viewer accessibility issues:
- Viewer URL resolves to
127.0.0.1by default。 - For remote access scenarios,要么:
- pass
baseUrlper tool call,或 - use
gateway.bind=customandgateway.customBindHost
- pass
- Enable
security.allowRemoteVieweronly when you intend external viewer access。
Unmodified-lines row has no expand button:
- This can happen for patch input when the patch does not carry expandable context。
- This is expected and does not indicate a viewer failure。
Artifact not found:
- Artifact expired due TTL。
- Token or path changed。
- Cleanup removed stale data。
Operational guidance
- Prefer
mode: "view"for local interactive reviews in canvas。 - Prefer
mode: "file"for outbound chat channels that need an attachment。 - Keep
allowRemoteViewerdisabled unless your deployment requires remote viewer URLs。 - Set explicit short
ttlSecondsfor sensitive diffs。 - Avoid sending secrets in diff input when not required。
- If your channel compresses images aggressively(例如 Telegram 或 WhatsApp),prefer PDF output(
fileFormat: "pdf")。
Diff rendering engine:
- Powered by Diffs。