Appearance
OpenClaw Diffs 插件为 agent 提供只读代码差异查看能力:接受 before/after 文本或 unified patch 输入,输出画布查看器 URL(mode: "view")或 PNG/PDF 文件(mode: "file"),也可同时返回两者。默认制品 TTL 30 分钟,最大 6 小时。文件模式需要 Chromium 兼容浏览器,查看器默认仅限本地环回地址,远程访问需额外配置 viewerBaseUrl 并启用 allowRemoteViewer。
OpenClaw Diffs 插件:代码差异可视化工具配置与故障排查
diffs 是可选插件工具,带有简短内置系统提示引导和配套技能,用于将变更内容转化为 agent 可呈现的只读差异制品。
接受以下输入之一:
before和after文本- unified
patch
可返回:
- 用于画布展示的网关查看器 URL
- 用于消息投递的渲染文件路径(PNG 或 PDF)
- 一次调用同时返回两者
快速开始
安装插件
```bash
openclaw plugins install diffs
```
启用插件
```json5
{
plugins: {
entries: {
diffs: {
enabled: true,
},
},
},
}
```
选择输出模式
view
画布优先流程:agent 调用 `diffs` 并设置 `mode: "view"`,然后用 `canvas present` 打开 `details.viewerUrl`。
file
聊天文件投递:agent 调用 `diffs` 并设置 `mode: "file"`,然后用 `message` 工具通过 `path` 或 `filePath` 发送 `details.filePath`。
both
组合模式:agent 调用 `diffs` 并设置 `mode: "both"`,一次调用同时获得查看器和文件。
怎么禁用内置系统提示引导
如果想保留 diffs 工具但去掉其自动注入的系统提示,设置 plugins.entries.diffs.hooks.allowPromptInjection 为 false:
json5
{
plugins: {
entries: {
diffs: {
enabled: true,
hooks: {
allowPromptInjection: false,
},
},
},
},
}这会屏蔽 diffs 插件的 before_prompt_build 钩子,同时保持插件、工具和配套技能可用。如果想完全禁用引导和工具,直接禁用插件本身。
典型 agent 工作流
调用 diffs
Agent 调用 `diffs` 工具并传入输入。
读取 details
Agent 从响应中读取 `details` 字段。
展示制品
Agent 选择:
- 用 `canvas present` 打开 `details.viewerUrl`
- 用 `message` 工具通过 `path` 或 `filePath` 发送 `details.filePath`
- 两者都做
输入示例
Before and after
```json
{
"before": "# Hello\n\nOne",
"after": "# Hello\n\nTwo",
"path": "docs/example.md",
"mode": "view"
}
```
Patch
```json
{
"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"
}
```
工具输入参数参考
所有字段均为可选,除非另有说明。
before string
原始文本。省略 patch 时,必须与 after 一起提供。
after string
更新后文本。省略 patch 时,必须与 before 一起提供。
patch string
Unified diff 文本。与 before/after 互斥。
path string
Before/after 模式下显示的文件名。
lang string
语言覆盖提示;未知值回退为纯文本。
title string
查看器标题覆盖。
mode
输出模式,默认值为插件配置中的 defaults.mode。已废弃别名 "image" 行为同 "file",仍向后兼容。
theme
查看器主题,默认值来自 defaults.theme。
layout
差异布局,默认值来自 defaults.layout。
expandUnchanged boolean
当存在可展开上下文时,展开未改动部分。仅作为每次调用的选项,无插件级默认值。
fileFormat
渲染文件格式,默认值来自 defaults.fileFormat。
fileQuality
PNG 或 PDF 渲染质量预设。
fileScale number
设备缩放倍率覆盖,范围 1-4。
fileMaxWidth number
最大渲染宽度(CSS 像素),范围 640-2400。
ttlSeconds number
制品 TTL(秒),适用于查看器和文件输出。最大 21600(6 小时)。
baseUrl string
查看器 URL 的 origin 覆盖。必须为 http 或 https,不含查询参数和 hash。覆盖插件 viewerBaseUrl。
已废弃的输入别名
以下旧字段仍向后兼容:
- `format` -> `fileFormat`
- `imageFormat` -> `fileFormat`
- `imageQuality` -> `fileQuality`
- `imageScale` -> `fileScale`
- `imageMaxWidth` -> `fileMaxWidth`
输入验证与大小限制
- `before` 和 `after` 各自最大 512 KiB。
- `patch` 最大 2 MiB。
- `path` 最大 2048 字节。
- `lang` 最大 128 字节。
- `title` 最大 1024 字节。
- Patch 复杂度上限:最多 128 个文件,120000 总行数。
- `patch` 与 `before`/`after` 同时提供会被拒绝。
- 渲染文件安全限制(同时作用于 PNG 和 PDF):
- `fileQuality: "standard"`:最大 8 MP(800 万渲染像素)
- `fileQuality: "hq"`:最大 14 MP(1400 万渲染像素)
- `fileQuality: "print"`:最大 24 MP(2400 万渲染像素)
- PDF 额外限制:最多 50 页
输出 details 契约
工具在 details 下返回结构化元数据。
查看器模式字段
适用于所有创建查看器的模式:
- `artifactId`
- `viewerUrl`
- `viewerPath`
- `title`
- `expiresAt`
- `inputKind`
- `fileCount`
- `mode`
- `context`(包含 `agentId`、`sessionId`、`messageChannel`、`agentAccountId`,视情况)
文件模式字段
当渲染 PNG 或 PDF 时返回:
- `artifactId`
- `expiresAt`
- `filePath`
- `path`(与 `filePath` 相同,用于消息工具兼容)
- `fileBytes`
- `fileFormat`
- `fileQuality`
- `fileScale`
- `fileMaxWidth`
向后兼容别名
为旧客户端同时返回:
- `format`(同 `fileFormat`)
- `imagePath`(同 `filePath`)
- `imageBytes`(同 `fileBytes`)
- `imageQuality`(同 `fileQuality`)
- `imageScale`(同 `fileScale`)
- `imageMaxWidth`(同 `fileMaxWidth`)
模式行为汇总:
| 模式 | 返回内容 |
|---|---|
"view" | 仅查看器字段 |
"file" | 仅文件字段,不创建查看器制品 |
"both" | 查看器字段 + 文件字段。若文件渲染失败,查看器仍正常返回,并额外附带 fileError(别名 imageError) |
未改动行的折叠显示
- 查看器可以显示如
N unmodified lines的行。 - 这些行上的展开控件并非对所有输入类型都保证出现。
- 当渲染的差异包含可展开上下文数据时,才会出现展开控制;对于 before/after 输入这是典型的。
- 对于许多 unified patch 输入,解析的 hunk 中缺少省略的上下文,因此未改动行可能不带展开控件——这是预期行为。
expandUnchanged仅当存在可展开上下文时生效。
插件默认值配置
在 ~/.openclaw/openclaw.json 中设置:
json5
{
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",
ttlSeconds: 21600,
},
},
},
},
},
}支持的默认字段:
fontFamilyfontSizelineSpacinglayoutshowLineNumbersdiffIndicatorswordWrapbackgroundthemefileFormatfileQualityfileScalefileMaxWidthmodettlSeconds
工具调用中的显式参数会覆盖这些默认值。
查看器 URL 持久化配置
viewerBaseUrl string
插件级别的查看器 URL 回退。当工具调用未传 baseUrl 时使用。必须为 http 或 https,不含查询参数和 hash。
json5
{
plugins: {
entries: {
diffs: {
enabled: true,
config: {
viewerBaseUrl: "https://gateway.example.com/openclaw",
},
},
},
},
}安全配置
security.allowRemoteViewer boolean
false:非 loopback 的查看器请求被拒绝。true:允许远程查看器(若 token 化路径有效)。
json5
{
plugins: {
entries: {
diffs: {
enabled: true,
config: {
security: {
allowRemoteViewer: false,
},
},
},
},
},
}制品生命周期与存储
- 制品存储在临时子目录:
$TMPDIR/openclaw-diffs。 - 查看器制品元数据包含:
- 随机 artifact ID(20 位十六进制)
- 随机 token(48 位十六进制)
createdAt和expiresAt- 存储的
viewer.html路径
- 默认查看器 TTL:30 分钟(1800 秒)。
- 最大接受查看器 TTL:6 小时(21600 秒)。
- 清理在制品创建后机会性地运行。
- 过期制品会被删除。
- 元数据缺失时,回退清理删除超过 24 小时的过期文件夹。
查看器 URL 与网络行为
查看器路由:
/plugins/diffs/view/{artifactId}/{token}
查看器静态资源:
/plugins/diffs/assets/viewer.js/plugins/diffs/assets/viewer-runtime.js
查看器文档相对于 URL 解析这些资源,因此可选的 baseUrl 路径前缀也会保留给资产请求。
URL 构建顺序:
- 若工具调用提供了
baseUrl,经严格验证后使用。 - 否则若插件配置了
viewerBaseUrl,使用它。 - 无覆盖时,查看器 URL 默认为 loopback
127.0.0.1。 - 若网关绑定模式为
custom且设置了gateway.customBindHost,则使用该 host。
baseUrl 规则:
- 必须以
http://或https://开头。 - 拒绝包含查询参数或 hash。
- 允许 origin 加可选基础路径。
安全模型
查看器加固
- 默认仅限 loopback 地址。
- Token 化的查看器路径,严格校验 ID 和 token。
- 查看器响应 CSP:
- `default-src 'none'`
- 脚本和资源仅来自 self
- 无出站 `connect-src`
- 启用远程访问时的限流:每 60 秒 40 次失败,60 秒锁定(`429 Too Many Requests`)
文件渲染加固
- 截屏浏览器的请求路由默认拒绝一切。
- 仅允许访问本地的查看器资产:`http://127.0.0.1/plugins/diffs/assets/*`
- 外部网络请求被阻断。
file 模式的浏览器要求
mode: "file" 和 mode: "both" 需要 Chromium 兼容浏览器。
浏览器解析顺序:
配置文件
OpenClaw 配置中的 `browser.executablePath`
环境变量
- `OPENCLAW_BROWSER_EXECUTABLE_PATH`
- `BROWSER_EXECUTABLE_PATH`
- `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH`
平台回退
平台命令 / 路径发现回退
常见失败提示:
Diff PNG/PDF rendering requires a Chromium-compatible browser...
解决方法:安装 Chrome、Chromium、Edge 或 Brave,或设置上述可执行路径选项之一。
排错
输入验证错误怎么解决
- `Provide patch or both before and after text.` — 同时提供 `before` 和 `after`,或提供 `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`。
- 对于远程场景,请:
- 设置插件 `viewerBaseUrl`,或
- 每次调用传入 `baseUrl`,或
- 使用 `gateway.bind=custom` 和 `gateway.customBindHost`
- 如果 `gateway.trustedProxies` 包含 loopback(例如 Tailscale Serve),裸 loopback 查看器请求因缺少转发客户端 IP 头会被拒绝——这是预期设计。
- 对于那种代理拓扑:
- 如果只需附件,优先用 `mode: "file"` 或 `mode: "both"`
- 如果需要可分享的查看器 URL,主动启用 `security.allowRemoteViewer` 并设置插件 `viewerBaseUrl` 或传入代理 / 公开 `baseUrl`
- 仅在打算开放外部查看器访问时才启用 `security.allowRemoteViewer`。
未改动行没有展开按钮
对于 patch 输入,当 patch 不包含可展开上下文时可能出现。这是预期行为,不表示查看器故障。
制品未找到
- 制品因 TTL 过期。
- Token 或路径已变更。
- 清理进程删除了过期数据。
运维建议
- 本地交互式审查时,优先使用
mode: "view"。 - 需要作为附件发送到外部聊天渠道时,优先使用
mode: "file"。 - 保持
allowRemoteViewer禁用,除非你的部署确实需要远程查看器 URL。 - 对敏感差异设置较短的显式
ttlSeconds。 - 避免在差异输入中包含不应传输的密钥。
- 如果聊天渠道会大幅压缩图片(如 Telegram、WhatsApp),优先使用 PDF 输出(
fileFormat: "pdf")。
INFO
差异渲染引擎由 Diffs 提供支持。
相关文档
常见问题
如何让外部用户访问 Diffs 查看器?
查看器默认仅允许本地环回地址(127.0.0.1)。要让外部访问,需要在插件配置中设置 viewerBaseUrl(例如 https://your-gateway.com/openclaw)并将 security.allowRemoteViewer 设为 true。注意:远程查看器路径带 token,但一旦暴露链接即可分享。启用限流:每 60 秒 40 次失败后锁定 60 秒。
为什么 mode: "file" 或 mode: "both" 报错要求 Chromium 浏览器?
文件模式需要 Chromium 兼容浏览器来渲染 PNG/PDF。OpenClaw 会依次检查配置 browser.executablePath、环境变量(OPENCLAW_BROWSER_EXECUTABLE_PATH 等)和平台路径。如果都没有找到,就会报错 Diff PNG/PDF rendering requires a Chromium-compatible browser。安装 Chrome/Chromium/Edge/Brave 或设置上述环境变量即可解决。
制品默认有效期多久?能延长吗?
默认有效期 30 分钟(1800 秒),可通过工具调用的 ttlSeconds 参数延长,最大 21600 秒(6 小时)。过期后制品会被自动清理,无法恢复,需要重新调用 diffs 生成。