Ir al contenido

Configura Diffs en OpenClaw: Genera visualizaciones en 3 pas

¿Alguna vez has intentado revisar cambios de código en una interfaz de chat y has terminado con dolor de cabeza por culpa del formato? Leer diffs en texto plano puede ser frustrante y propenso a errores. Para solucionar esto, diffs te permite visualizar cambios de forma clara y profesional, ya sea directamente en un Canvas o mediante archivos listos para enviar.

diffs es una herramienta de plugin opcional que incluye una guía de sistema integrada y una habilidad complementaria. Su función es transformar el contenido de los cambios en un artefacto de diff de solo lectura para los agents.

Acepta dos tipos de entrada:

  • Texto before (antes) y after (después).
  • Un patch unificado.

Puede devolver:

  • Una URL del visor del Gateway para presentaciones en Canvas.
  • Una ruta de archivo renderizado (PNG o PDF) para entrega de mensajes.
  • Ambos resultados en una sola llamada.

Cuando está activado, el plugin añade una guía de uso concisa en el espacio del system-prompt y expone una habilidad detallada para los casos en los que el agent necesite instrucciones más completas.

  1. Activa el plugin.
  2. Llama a diffs con mode: "view" para flujos centrados en Canvas.
  3. Llama a diffs con mode: "file" para flujos de entrega de archivos en el chat.
  4. Llama a diffs con mode: "both" cuando necesites ambos artefactos.
{
plugins: {
entries: {
diffs: {
enabled: true,
},
},
},
}

Si quieres mantener la herramienta diffs activa pero prefieres desactivar su guía integrada en el 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, pero mantiene disponibles el plugin, la herramienta y la habilidad complementaria.

Si prefieres desactivar tanto la guía como la herramienta, desactiva el plugin por completo.

  1. El agent llama a diffs.
  2. El agent lee los campos de details.
  3. El agent realiza una de estas acciones:
    • Abre details.viewerUrl con canvas present.
    • Envía details.filePath con un message usando path o filePath.
    • Realiza ambas acciones.

Antes y después:

{
"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"
}

Todos los campos son opcionales a menos que se indique lo contrario:

  • before (string): texto original. Obligatorio con after si se omite patch.
  • after (string): texto actualizado. Obligatorio con before si se omite patch.
  • patch (string): texto de diff unificado. Excluyente con before y after.
  • path (string): nombre de archivo a mostrar para el modo antes/después.
  • lang (string): sugerencia de lenguaje para el modo antes/después. Los valores desconocidos usarán texto plano.
  • title (string): sobrescribe el título del visor.
  • mode ("view" | "file" | "both"): modo de salida. Por defecto usa el valor de defaults.mode del plugin. Alias obsoleto: "image" funciona como "file" y se acepta por compatibilidad.
  • theme ("light" | "dark"): tema del visor. Por defecto usa defaults.theme.
  • layout ("unified" | "split"): diseño del diff. Por defecto usa defaults.layout.
  • expandUnchanged (boolean): expande secciones sin cambios cuando el contexto completo está disponible. Solo por llamada.
  • fileFormat ("png" | "pdf"): formato del archivo renderizado. Por defecto usa defaults.fileFormat.
  • fileQuality ("standard" | "hq" | "print"): ajuste de calidad para PNG o PDF.
  • fileScale (number): sobrescribe la escala del dispositivo (1-4).
  • fileMaxWidth (number): ancho máximo de renderizado en píxeles CSS (640-2400).
  • ttlSeconds (number): tiempo de vida (TTL) del artefacto en segundos. Por defecto 1800, máximo 21600.
  • baseUrl (string): sobrescribe el origen de la URL del visor. Debe ser http o https, sin query ni hash.

Validación y límites:

  • before y after: máximo 512 KiB cada uno.
  • patch: máximo 2 MiB.
  • path: máximo 2048 bytes.
  • lang: máximo 128 bytes.
  • title: máximo 1024 bytes.
  • Límite de complejidad del patch: máximo 128 archivos y 120000 líneas totales.
  • Se rechaza el uso de patch junto con before o after.
  • Límites de seguridad para archivos renderizados (PNG y PDF):
    • fileQuality: "standard": máx. 8 MP (8,000,000 píxeles).
    • fileQuality: "hq": máx. 14 MP (14,000,000 píxeles).
    • fileQuality: "print": máx. 24 MP (24,000,000 píxeles).
    • El formato PDF tiene un máximo de 50 páginas.

La herramienta devuelve metadatos estructurados bajo el objeto details.

Campos compartidos para modos que crean un visor:

  • artifactId
  • viewerUrl
  • viewerPath
  • title
  • expiresAt
  • inputKind
  • fileCount
  • mode
  • context (agentId, sessionId, messageChannel, agentAccountId si están disponibles)

Campos de archivo cuando se renderiza PNG o PDF:

  • artifactId
  • expiresAt
  • filePath
  • path (mismo valor que filePath, para compatibilidad con herramientas de mensajes)
  • fileBytes
  • fileFormat
  • fileQuality
  • fileScale
  • fileMaxWidth

Resumen de comportamiento por modo:

  • mode: "view": solo campos del visor.
  • mode: "file": solo campos de archivo, sin artefacto de visor.
  • mode: "both": campos de visor y campos de archivo. Si el renderizado del archivo falla, el visor se devuelve con un fileError.
  • El visor puede mostrar filas como N unmodified lines.
  • Los controles para expandir esas filas son condicionales y no se garantizan para todos los tipos de entrada.
  • Los controles aparecen cuando el diff renderizado tiene datos de contexto expandibles, algo común en entradas de tipo antes/después.
  • En muchas entradas de tipo patch unificado, los cuerpos de contexto omitidos no están disponibles en los fragmentos (hunks) analizados, por lo que la fila puede aparecer sin controles de expansión. Este es el comportamiento esperado.
  • expandUnchanged solo se aplica cuando existe contexto expandible.

Puedes configurar los valores globales 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 admitidos:

  • fontFamily
  • fontSize
  • lineSpacing
  • layout
  • showLineNumbers
  • diffIndicators
  • wordWrap
  • background
  • theme
  • fileFormat
  • fileQuality
  • fileScale
  • fileMaxWidth
  • mode

Los parámetros explícitos en la herramienta sobrescriben estos valores.

  • security.allowRemoteViewer (boolean, por defecto false)
    • false: se deniegan las peticiones que no sean de loopback a las rutas del visor.
    • true: se permiten visores remotos si la ruta con token es válida.

Ejemplo:

{
plugins: {
entries: {
diffs: {
enabled: true,
config: {
security: {
allowRemoteViewer: false,
},
},
},
},
},
}

Ciclo de vida y almacenamiento de artefactos

Sección titulada «Ciclo de vida y almacenamiento de artefactos»
  • Los artefactos se guardan en la carpeta temporal: $TMPDIR/openclaw-diffs.
  • Los metadatos del artefacto del visor contienen:
    • ID de artefacto aleatorio (20 caracteres hex).
    • Token aleatorio (48 caracteres hex).
    • createdAt y expiresAt.
    • Ruta del archivo viewer.html almacenado.
  • El TTL por defecto del visor es de 30 minutos.
  • El TTL máximo aceptado es de 6 horas.
  • La limpieza se ejecuta tras la creación de cada artefacto.
  • Los artefactos caducados se eliminan automáticamente.
  • Existe una limpieza de respaldo para carpetas de más de 24 horas sin metadatos.

Ruta del visor:

  • /plugins/diffs/view/{artifactId}/{token}

Assets del visor:

  • /plugins/diffs/assets/viewer.js
  • /plugins/diffs/assets/viewer-runtime.js

El documento del visor resuelve estos assets de forma relativa a su URL, por lo que cualquier prefijo baseUrl opcional se mantiene para las peticiones de assets.

Comportamiento de construcción de la URL:

  • Si se proporciona baseUrl, se usa tras una validación estricta.
  • Sin baseUrl, la URL del visor apunta por defecto a 127.0.0.1.
  • Si el modo de bind del Gateway es custom y gateway.customBindHost está configurado, se usará ese host.

Reglas de baseUrl:

  • Debe ser http:// o https://.
  • No se permiten query ni hash.
  • Se permite el origen más una ruta base opcional.

Protección del visor:

  • Solo loopback por defecto.
  • Rutas con tokens y validación estricta de ID.
  • CSP en la respuesta del visor:
    • default-src 'none'
    • Scripts y assets solo desde self.
    • Sin connect-src de salida.
  • Limitación de errores remotos (throttling):
    • 40 fallos cada 60 segundos.
    • Bloqueo de 60 segundos (429 Too Many Requests).

Protección de renderizado de archivos:

  • El enrutamiento de peticiones del navegador para capturas está denegado por defecto.
  • Solo se permiten assets locales del visor desde http://127.0.0.1/plugins/diffs/assets/*.
  • Las peticiones a redes externas están bloqueadas.

Requisitos del navegador para el modo de archivo

Sección titulada «Requisitos del navegador para el modo de archivo»

Los modos mode: "file" y mode: "both" requieren un navegador compatible con Chromium.

Orden de resolución:

  1. browser.executablePath en la configuración de OpenClaw.
  2. Variables de entorno:
    • OPENCLAW_BROWSER_EXECUTABLE_PATH
    • BROWSER_EXECUTABLE_PATH
    • PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH
  3. Descubrimiento automático según la plataforma.

Error común:

  • Diff PNG/PDF rendering requires a Chromium-compatible browser...

Para solucionarlo, instala Chrome, Chromium, Edge o Brave, o configura una de las rutas mencionadas arriba.

Errores de validación de entrada:

  • Provide patch or both before and after text.
    • Asegúrate de incluir before y after, o bien el patch.
  • Provide either patch or before/after input, not both.
    • No mezcles los modos de entrada.
  • Invalid baseUrl: ...
    • Usa un origen http(s) con ruta opcional, sin query ni hash.
  • {field} exceeds maximum size (...)
    • Reduce el tamaño de la carga útil.
  • Rechazo de patch grande
    • Reduce el número de archivos o líneas totales del patch.

Problemas de acceso al visor:

  • La URL del visor resuelve a 127.0.0.1 por defecto.
  • Para acceso remoto, puedes:
    • Pasar baseUrl en cada llamada.
    • Usar gateway.bind=custom y gateway.customBindHost.
  • Activa security.allowRemoteViewer solo si realmente necesitas acceso externo.

La fila de líneas sin cambios no tiene botón de expansión:

  • Ocurre con entradas de tipo patch cuando este no incluye contexto expandible.
  • Es un comportamiento esperado, no un fallo.

Artefacto no encontrado:

  • El artefacto caducó (TTL).
  • El token o la ruta han cambiado.
  • El proceso de limpieza eliminó los datos antiguos.
  • Te recomiendo usar mode: "view" para revisiones interactivas locales en Canvas.
  • Usa mode: "file" para canales de chat externos que necesiten un archivo adjunto.
  • Mantén allowRemoteViewer desactivado a menos que tu despliegue lo exija.
  • Configura un ttlSeconds corto para diffs que contengan información sensible.
  • Evita enviar secretos en los diffs si no es estrictamente necesario.
  • Si tu canal de chat comprime mucho las imágenes (como Telegram o WhatsApp), te sugiero usar la salida en PDF (fileFormat: "pdf").

Motor de renderizado de diffs:

  • Configura tus herramientas para maximizar la eficiencia.
  • Aprende más sobre la gestión de plugins.

AI Setup Assistant

OpenClaw

OpenClaw Expert

Sigues atascado?

Si esta pagina no resolvio tu caso, pregunta a OpenClaw Expert para pasos concretos.