Diffs
diffs 是一个可选插件工具,带有简短的内置系统指导和一个配套 skill,可将变更内容转换为供智能体使用的只读 diff 工件。
它接受以下任一输入:
before和after文本- 统一格式的
patch
- 用于 canvas 展示的 Gateway 网关查看器 URL
- 用于消息投递的渲染文件路径(PNG 或 PDF)
- 一次调用同时返回以上两种输出
快速开始
- 启用插件。
- 在以 canvas 为主的流程中,调用
diffs并设置mode: "view"。 - 在聊天文件投递流程中,调用
diffs并设置mode: "file"。 - 当你同时需要两种工件时,调用
diffs并设置mode: "both"。
启用插件
禁用内置系统指导
如果你希望保持diffs 工具启用,但禁用其内置 system-prompt 指导,请将 plugins.entries.diffs.hooks.allowPromptInjection 设置为 false:
before_prompt_build hook,同时保留插件、工具和配套 skill 可用。
如果你想同时禁用指导和工具,请直接禁用该插件。
典型智能体工作流
- 智能体调用
diffs。 - 智能体读取
details字段。 - 智能体执行以下之一:
- 使用
canvas present打开details.viewerUrl - 使用
message发送details.filePath,并通过path或filePath - 两者都做
- 使用
输入示例
Before 和 after:工具输入参考
除特别说明外,所有字段均为可选:before(string):原始文本。当省略patch时,必须与after一起提供。after(string):更新后的文本。当省略patch时,必须与before一起提供。patch(string):统一 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"):diff 布局。默认使用插件默认值defaults.layout。expandUnchanged(boolean):当完整上下文可用时展开未更改部分。仅为单次调用选项(不是插件默认键)。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 源覆盖值。会覆盖插件的viewerBaseUrl。必须为http或https,且不能带 query/hash。
format->fileFormatimageFormat->fileFormatimageQuality->fileQualityimageScale->fileScaleimageMaxWidth->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(8,000,000 渲染像素)。fileQuality: "hq":最大 14 MP(14,000,000 渲染像素)。fileQuality: "print":最大 24 MP(24,000,000 渲染像素)。- PDF 另有最多 50 页的限制。
输出 details 契约
该工具会在details 下返回结构化元数据。
适用于会创建查看器的模式的共享字段:
artifactIdviewerUrlviewerPathtitleexpiresAtinputKindfileCountmodecontext(如可用则包括agentId、sessionId、messageChannel、agentAccountId)
artifactIdexpiresAtfilePathpath(与filePath相同的值,用于兼容 message 工具)fileBytesfileFormatfileQualityfileScalefileMaxWidth
format(与fileFormat相同的值)imagePath(与filePath相同的值)imageBytes(与fileBytes相同的值)imageQuality(与fileQuality相同的值)imageScale(与fileScale相同的值)imageMaxWidth(与fileMaxWidth相同的值)
mode: "view":仅返回查看器字段。mode: "file":仅返回文件字段,不创建查看器工件。mode: "both":返回查看器字段加文件字段。如果文件渲染失败,查看器仍会返回,同时带有fileError和兼容别名imageError。
折叠的未更改部分
- 查看器可以显示类似
N unmodified lines的行。 - 这些行上的展开控件是有条件的,并不保证适用于每一种输入类型。
- 当渲染后的 diff 具有可展开的上下文数据时,会显示展开控件,这在 before/after 输入中很常见。
- 对于许多统一 patch 输入,解析后的 patch hunk 中并不包含被省略的上下文主体,因此可能会显示该行但没有展开控件。这是预期行为。
expandUnchanged仅在存在可展开上下文时生效。
插件默认值
在~/.openclaw/openclaw.json 中设置插件级默认值:
fontFamilyfontSizelineSpacinglayoutshowLineNumbersdiffIndicatorswordWrapbackgroundthemefileFormatfileQualityfileScalefileMaxWidthmode
viewerBaseUrl(string,可选)- 当工具调用未传入
baseUrl时,作为返回查看器链接的插件自有回退值。 - 必须为
http或https,且不能带 query/hash。
- 当工具调用未传入
安全配置
security.allowRemoteViewer(boolean,默认false)false:拒绝对查看器路由的非 loopback 请求。true:如果 tokenized 路径有效,则允许远程查看器。
工件生命周期与存储
- 工件存储在临时子文件夹下:
$TMPDIR/openclaw-diffs。 - 查看器工件元数据包含:
- 随机工件 ID(20 个十六进制字符)
- 随机令牌(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
baseUrl 路径前缀也会被保留并用于这些资源请求。
URL 构造行为:
- 如果提供了工具调用级
baseUrl,则在严格验证后使用它。 - 否则如果配置了插件
viewerBaseUrl,则使用它。 - 如果两者都未覆盖,查看器 URL 默认使用 loopback
127.0.0.1。 - 如果 gateway 绑定模式为
custom且设置了gateway.customBindHost,则使用该主机。
baseUrl 规则:
- 必须是
http://或https://。 - 不接受 query 和 hash。
- 允许源加可选基础路径。
安全模型
查看器加固:- 默认仅限 loopback。
- 使用 tokenized 查看器路径,并对 ID 和令牌进行严格验证。
- 查看器响应 CSP:
default-src 'none'- 脚本和资源仅允许来自 self
- 不允许出站
connect-src
- 启用远程访问时,对远程 miss 进行节流:
- 每 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...
故障排除
输入验证错误:Provide patch or both before and after text.- 请同时提供
before和after,或提供patch。
- 请同时提供
Provide either patch or before/after input, not both.- 不要混用输入模式。
Invalid baseUrl: ...- 请使用带可选路径、无 query/hash 的
http(s)源。
- 请使用带可选路径、无 query/hash 的
{field} exceeds maximum size (...)- 请减小载荷大小。
- 大 patch 被拒绝
- 请减少 patch 文件数量或总行数。
- 查看器 URL 默认解析为
127.0.0.1。 - 对于远程访问场景,可选择:
- 设置插件
viewerBaseUrl,或 - 在每次工具调用中传入
baseUrl,或 - 使用
gateway.bind=custom和gateway.customBindHost
- 设置插件
- 如果
gateway.trustedProxies对同主机代理(例如 Tailscale Serve)包含 loopback,那么在没有转发客户端 IP 头的情况下,原始 loopback 查看器请求会按设计失败关闭。 - 对于这种代理拓扑:
- 如果你只需要附件,优先使用
mode: "file"或mode: "both",或 - 如果你需要可分享的查看器 URL,则有意启用
security.allowRemoteViewer,并设置插件viewerBaseUrl或在需要时传入代理/公共baseUrl
- 如果你只需要附件,优先使用
- 仅当你确实打算允许外部查看器访问时,才启用
security.allowRemoteViewer。
- 这可能发生在 patch 输入中,因为 patch 不携带可展开上下文。
- 这是预期行为,并不表示查看器失败。
- 工件因 TTL 到期而失效。
- 令牌或路径已更改。
- 清理过程移除了陈旧数据。
运维指导
- 对于 canvas 中的本地交互式审查,优先使用
mode: "view"。 - 对于需要附件的外发聊天渠道,优先使用
mode: "file"。 - 除非你的部署需要远程查看器 URL,否则请保持
allowRemoteViewer禁用。 - 对敏感 diff,请显式设置较短的
ttlSeconds。 - 在非必要情况下,避免在 diff 输入中包含密钥。
- 如果你的渠道会强烈压缩图片(例如 Telegram 或 WhatsApp),请优先使用 PDF 输出(
fileFormat: "pdf")。
- 由 Diffs 提供支持。