Diffs
diffs es una herramienta de plugin opcional con una guía del sistema integrada breve y una habilidad complementaria que convierte contenido de cambios en un artefacto de diferencias de solo lectura para agentes. Acepta:
- texto
beforeyafter - un
patchunificado
Puede devolver:
- una URL de visor del gateway para presentación en el lienzo
- una ruta de archivo renderizado (PNG o PDF) para entrega en mensajes
- ambas salidas en una sola llamada
Cuando está habilitado, el plugin antepone una guía de uso concisa al espacio del system-prompt y también expone una habilidad detallada para los casos en que el agente necesite instrucciones más completas.
Inicio rápido
- Habilita el plugin.
- Llama a
diffsconmode: "view"para flujos centrados en el lienzo. - Llama a
diffsconmode: "file"para flujos de entrega de archivos en el chat. - Llama a
diffsconmode: "both"cuando necesites ambos artefactos.
Habilitar el plugin
{
plugins: {
entries: {
diffs: {
enabled: true,
},
},
},
}
Deshabilitar la guía del sistema integrada
Si deseas mantener la herramienta diffs habilitada pero deshabilitar su guía integrada del system-prompt, establece plugins.entries.diffs.hooks.allowPromptInjection en false:
{
plugins: {
entries: {
diffs: {
enabled: true,
hooks: {
allowPromptInjection: false,
},
},
},
},
}
Esto bloquea el hook before_prompt_build del plugin diffs mientras mantiene disponible el plugin, la herramienta y la habilidad complementaria. Si deseas deshabilitar tanto la guía como la herramienta, deshabilita el plugin en su lugar.
Flujo de trabajo típico del agente
- El agente llama a
diffs. - El agente lee los campos
details. - El agente, o bien:
- abre
details.viewerUrlconcanvas present - envía
details.filePathconmessageusandopathofilePath - hace ambas cosas
- abre
Ejemplos de entrada
Before y 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"
}
Referencia de entrada de la herramienta
Todos los campos son opcionales a menos que se indique lo contrario:
before(string): texto original. Requerido conaftercuando se omitepatch.after(string): texto actualizado. Requerido conbeforecuando se omitepatch.patch(string): texto de diff unificado. Excluyente mutuamente conbeforeyafter.path(string): nombre de archivo para mostrar en el modo before y after.lang(string): sugerencia de anulación de idioma para el modo before y after.title(string): anulación del título del visor.mode("view" | "file" | "both"): modo de salida. Por defecto, el valor predeterminado del plugindefaults.mode.theme("light" | "dark"): tema del visor. Por defecto, el valor predeterminado del plugindefaults.theme.layout("unified" | "split"): diseño de diferencias. Por defecto, el valor predeterminado del plugindefaults.layout.expandUnchanged(boolean): expandir secciones sin cambios cuando el contexto completo está disponible. Opción solo por llamada (no es una clave predeterminada del plugin).fileFormat("png" | "pdf"): formato de archivo renderizado. Por defecto, el valor predeterminado del plugindefaults.fileFormat.fileQuality("standard" | "hq" | "print"): preajuste de calidad para renderizado PNG o PDF.fileScale(number): anulación de escala del dispositivo (1-4).fileMaxWidth(number): ancho máximo de renderizado en píxeles CSS (640-2400).ttlSeconds(number): TTL del artefacto del visor en segundos. Por defecto 1800, máximo 21600.baseUrl(string): anulación del origen de la URL del visor. Debe serhttpohttps, sin query/hash.
Validación y límites:
beforeyaftermáximo 512 KiB cada uno.patchmáximo 2 MiB.pathmáximo 2048 bytes.langmáximo 128 bytes.titlemáximo 1024 bytes.- Límite de complejidad del patch: máximo 128 archivos y 120000 líneas en total.
patchjunto conbeforeoafteres rechazado.- Límites de seguridad del archivo renderizado (se aplican a PNG y PDF):
fileQuality: "standard": máximo 8 MP (8,000,000 píxeles renderizados).fileQuality: "hq": máximo 14 MP (14,000,000 píxeles renderizados).fileQuality: "print": máximo 24 MP (24,000,000 píxeles renderizados).- PDF también tiene un máximo de 50 páginas.
Contrato de detalles de salida
La herramienta devuelve metadatos estructurados bajo details. Campos compartidos para modos que crean un visor:
artifactIdviewerUrlviewerPathtitleexpiresAtinputKindfileCountmode
Campos de archivo cuando se renderiza PNG o PDF:
filePathpath(mismo valor quefilePath, para compatibilidad con la herramienta message)fileBytesfileFormatfileQualityfileScalefileMaxWidth
Resumen del comportamiento del modo:
mode: "view": solo campos del visor.mode: "file": solo campos de archivo, sin artefacto de visor.mode: "both": campos del visor más campos de archivo. Si falla el renderizado del archivo, el visor aún se devuelve confileError.
Secciones sin cambios colapsadas
- El visor puede mostrar filas como
N líneas sin modificar. - Los controles de expansión en esas filas son condicionales y no están garantizados para cada tipo de entrada.
- Los controles de expansión aparecen cuando el diff renderizado tiene datos de contexto expandibles, lo cual es típico para la entrada before y after.
- Para muchas entradas de patch unificado, los cuerpos de contexto omitidos no están disponibles en los fragmentos del patch analizado, por lo que la fila puede aparecer sin controles de expansión. Este es el comportamiento esperado.
expandUnchangedse aplica solo cuando existe contexto expandible.
Valores predeterminados del plugin
Establece valores predeterminados para todo el plugin en ~/.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",
},
},
},
},
},
}
Valores predeterminados admitidos:
fontFamilyfontSizelineSpacinglayoutshowLineNumbersdiffIndicatorswordWrapbackgroundthemefileFormatfileQualityfileScalefileMaxWidthmode
Los parámetros explícitos de la herramienta anulan estos valores predeterminados.
Configuración de seguridad
security.allowRemoteViewer(boolean, predeterminadofalse)false: se deniegan las solicitudes no loopback a las rutas del visor.true: se permiten visores remotos si la ruta tokenizada es válida.
Ejemplo:
{
plugins: {
entries: {
diffs: {
enabled: true,
config: {
security: {
allowRemoteViewer: false,
},
},
},
},
},
}
Ciclo de vida y almacenamiento de artefactos
- Los artefactos se almacenan en la subcarpeta temporal:
$TMPDIR/openclaw-diffs. - Los metadatos del artefacto del visor contienen:
- ID de artefacto aleatorio (20 caracteres hex)
- token aleatorio (48 caracteres hex)
createdAtyexpiresAt- ruta almacenada
viewer.html
- El TTL predeterminado del visor es de 30 minutos cuando no se especifica.
- El TTL máximo aceptado del visor es de 6 horas.
- La limpieza se ejecuta de forma oportunista después de la creación del artefacto.
- Los artefactos expirados se eliminan.
- La limpieza de respaldo elimina carpetas obsoletas de más de 24 horas cuando faltan metadatos.
URL del visor y comportamiento de red
Ruta del visor:
/plugins/diffs/view/{artifactId}/{token}
Recursos del visor:
/plugins/diffs/assets/viewer.js/plugins/diffs/assets/viewer-runtime.js
Comportamiento de construcción de URL:
- Si se proporciona
baseUrl, se utiliza después de una validación estricta. - Sin
baseUrl, la URL del visor predeterminada es loopback127.0.0.1. - Si el modo de enlace del gateway es
customygateway.customBindHostestá establecido, se utiliza ese host.
Reglas de baseUrl:
- Debe ser
http://ohttps://. - Se rechazan query y hash.
- Se permite el origen más una ruta base opcional.
Modelo de seguridad
Refuerzo del visor:
- Solo loopback por defecto.
- Rutas de visor tokenizadas con validación estricta de ID y token.
- CSP de respuesta del visor:
default-src 'none'- scripts y recursos solo desde sí mismo
- sin
connect-srcsaliente
- Limitación de fallos remotos cuando el acceso remoto está habilitado:
- 40 fallos por 60 segundos
- bloqueo de 60 segundos (
429 Too Many Requests)
Refuerzo del renderizado de archivos:
- El enrutamiento de solicitudes del navegador de captura de pantalla es denegar por defecto.
- Solo se permiten recursos del visor local desde
http://127.0.0.1/plugins/diffs/assets/*. - Las solicitudes de red externas están bloqueadas.
Requisitos del navegador para el modo archivo
mode: "file" y mode: "both" necesitan un navegador compatible con Chromium. Orden de resolución:
browser.executablePathen la configuración de OpenClaw.- Variables de entorno:
OPENCLAW_BROWSER_EXECUTABLE_PATHBROWSER_EXECUTABLE_PATHPLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH
- Respaldo de descubrimiento de comando/ruta de la plataforma.
Texto de error común:
Diff PNG/PDF rendering requires a Chromium-compatible browser...
Solución instalando Chrome, Chromium, Edge o Brave, o estableciendo una de las opciones de ruta ejecutable anteriores.
Resolución de problemas
Errores de validación de entrada:
Provide patch or both before and after text.- Incluye tanto
beforecomoafter, o proporcionapatch.
- Incluye tanto
Provide either patch or before/after input, not both.- No mezcles modos de entrada.
Invalid baseUrl: ...- Usa origen
http(s)con ruta opcional, sin query/hash.
- Usa origen
{field} exceeds maximum size (...)- Reduce el tamaño de la carga útil.
- Rechazo de patch grande
- Reduce el número de archivos del patch o el total de líneas.
Problemas de accesibilidad del visor:
- La URL del visor se resuelve a
127.0.0.1por defecto. - Para escenarios de acceso remoto, o bien:
- pasa
baseUrlpor llamada de herramienta, o - usa
gateway.bind=customygateway.customBindHost
- pasa
- Habilita
security.allowRemoteViewersolo cuando tengas la intención de acceso externo al visor.
La fila de líneas sin modificar no tiene botón de expandir:
- Esto puede ocurrir para la entrada de patch cuando el patch no lleva contexto expandible.
- Esto es esperado y no indica un fallo del visor.
Artefacto no encontrado:
- El artefacto expiró debido al TTL.
- El token o la ruta cambiaron.
- La limpieza eliminó datos obsoletos.
Guía operativa
- Prefiere
mode: "view"para revisiones interactivas locales en el lienzo. - Prefiere
mode: "file"para canales de chat salientes que necesiten un adjunto. - Mantén
allowRemoteViewerdeshabilitado a menos que tu despliegue requiera URLs de visor remotas. - Establece un
ttlSecondscorto y explícito para diffs sensibles. - Evita enviar secretos en la entrada de diff cuando no sea necesario.
- Si tu canal comprime imágenes agresivamente (por ejemplo Telegram o WhatsApp), prefiere la salida PDF (
fileFormat: "pdf").
Motor de renderizado de diferencias: