Appearance
Diffs 差异查看工具
diffs 是一个可选的插件工具,内置简短的系统提示引导,并附带一个技能(skill),能够将变更内容转化为 Agent 可呈现的只读差异制品。
接受以下输入之一:
before和after文本- unified
patch
可返回:
- 用于画布展示的 Gateway 查看器 URL
- 用于消息投递的渲染文件路径(PNG 或 PDF)
- 一次调用同时返回两者
启用后,插件会将简洁的使用说明注入到系统提示空间,同时也暴露一个详细技能,供 Agent 需要完整指导时使用。
快速开始
- 启用插件。
- 本地画布展示流程:使用
mode: "view"调用diffs。 - 聊天文件投递流程:使用
mode: "file"调用diffs。 - 同时需要两种输出:使用
mode: "both"调用diffs。
启用插件
json5
{
plugins: {
entries: {
diffs: {
enabled: true,
},
},
},
}禁用内置系统提示引导
如果你想保留 diffs 工具但禁用其内置系统提示引导,设置 plugins.entries.diffs.hooks.allowPromptInjection 为 false:
json5
{
plugins: {
entries: {
diffs: {
enabled: true,
hooks: {
allowPromptInjection: false,
},
},
},
},
}这会屏蔽 diffs 插件的 before_prompt_build 钩子,同时保持插件、工具和配套技能可用。
若要同时禁用引导和工具,则直接禁用插件。
典型 Agent 工作流
- Agent 调用
diffs。 - Agent 读取
details字段。 - Agent 选择:
- 用
canvas present打开details.viewerUrl - 通过
path或filePath在message中发送details.filePath - 两者都做
- 用
输入示例
before 和 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):before/after 模式下的语言覆盖提示。title(string):查看器标题覆盖。mode("view" | "file" | "both"):输出模式,默认为插件默认值defaults.mode。已废弃别名:"image"行为与"file"相同,仍向后兼容。theme("light" | "dark"):查看器主题,默认为插件默认值defaults.theme。layout("unified" | "split"):差异布局,默认为插件默认值defaults.layout。expandUnchanged(boolean):在有完整上下文时展开未改动部分。仅限每次调用设置(不是插件默认 key)。fileFormat("png" | "pdf"):渲染文件格式,默认为插件默认值defaults.fileFormat。fileQuality("standard" | "hq" | "print"):PNG 或 PDF 渲染的质量预设。fileScale(number):设备缩放倍率覆盖(1-4)。fileMaxWidth(number):最大渲染宽度(CSS 像素,640-2400)。ttlSeconds(number):查看器制品 TTL(秒),默认 1800,最大 21600。baseUrl(string):查看器 URL origin 覆盖,必须是http或https,不含查询参数和 hash。
验证与限制:
before和after各最大 512 KiB。patch最大 2 MiB。path最大 2048 字节。lang最大 128 字节。title最大 1024 字节。- Patch 复杂度上限:最多 128 个文件、120000 行总计。
patch与before/after同时提供时会被拒绝。- 渲染文件安全限制(适用于 PNG 和 PDF):
fileQuality: "standard":最大 800 万像素(8,000,000)。fileQuality: "hq":最大 1400 万像素(14,000,000)。fileQuality: "print":最大 2400 万像素(24,000,000)。- PDF 另有最大 50 页限制。
输出 details 契约
工具在 details 下返回结构化元数据。
创建查看器模式下的公共字段:
artifactIdviewerUrlviewerPathtitleexpiresAtinputKindfileCountmodecontext(agentId、sessionId、messageChannel、agentAccountId,有值时返回)
渲染 PNG 或 PDF 时的文件字段:
artifactIdexpiresAtfilePathpath(值与filePath相同,兼容 message 工具)fileBytesfileFormatfileQualityfileScalefileMaxWidth
模式行为摘要:
mode: "view":仅查看器字段。mode: "file":仅文件字段,不创建查看器制品。mode: "both":查看器字段加文件字段。若文件渲染失败,查看器仍返回,并附fileError。
未改动行折叠
- 查看器可以显示"N 行未修改"之类的折叠行。
- 折叠行的展开控件是条件性的,不保证对所有输入类型都出现。
- 展开控件在渲染差异有可展开上下文数据时出现,这在 before/after 输入中很常见。
- 对于许多 unified patch 输入,已省略的上下文内容在解析后的 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",
},
},
},
},
},
}支持的默认值字段:
fontFamilyfontSizelineSpacinglayoutshowLineNumbersdiffIndicatorswordWrapbackgroundthemefileFormatfileQualityfileScalefileMaxWidthmode
工具显式参数会覆盖这些默认值。
安全配置
security.allowRemoteViewer(boolean,默认false)false:拒绝从非回环地址访问查看器路由。true:若 tokenized 路径有效,允许远程访问查看器。
示例:
json5
{
plugins: {
entries: {
diffs: {
enabled: true,
config: {
security: {
allowRemoteViewer: false,
},
},
},
},
},
}制品生命周期与存储
- 制品存储在临时子目录:
$TMPDIR/openclaw-diffs。 - 查看器制品元数据包含:
- 随机制品 ID(20 位十六进制)
- 随机 token(48 位十六进制)
createdAt和expiresAt- 存储的
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 加可选基础路径。
安全模型
查看器加固措施:
- 默认仅限回环地址。
- Tokenized 查看器路径,严格校验 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_PATHBROWSER_EXECUTABLE_PATHPLAYWRIGHT_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: ...- 使用不含查询参数/hash 的
http(s)origin(加可选路径)。
- 使用不含查询参数/hash 的
{field} exceeds maximum size (...)- 减小 payload 大小。
- Large patch rejection
- 减少 patch 文件数或总行数。
查看器访问问题:
- 查看器 URL 默认解析为
127.0.0.1。 - 远程访问场景下,可以:
- 每次调用时传
baseUrl,或 - 使用
gateway.bind=custom和gateway.customBindHost
- 每次调用时传
- 仅在需要外部查看器访问时才启用
security.allowRemoteViewer。
未改动行无展开按钮:
- patch 输入不包含可展开上下文时会出现此情况。
- 这是预期行为,不代表查看器故障。
制品未找到:
- 制品因 TTL 过期。
- Token 或路径已变更。
- 清理程序已删除过期数据。
运维建议
- 本地交互式审查,优先使用
mode: "view"。 - 需要作为附件发送到外部聊天渠道时,优先使用
mode: "file"。 - 除非部署需要远程查看器 URL,否则保持
allowRemoteViewer禁用。 - 对敏感差异设置较短的显式
ttlSeconds。 - 非必要时避免在 diff 输入中包含机密信息。
- 如果你的渠道会大幅压缩图片(如 Telegram 或 WhatsApp),优先使用 PDF 输出(
fileFormat: "pdf")。
差异渲染引擎:
- 由 Diffs 提供支持。