Diffs
diffs é uma ferramenta opcional de plugin com uma orientação curta integrada ao sistema e uma Skill complementar que transforma conteúdo de mudanças em um artefato de diff somente leitura para agentes.
Ela aceita:
- texto
beforeeafter - um
patchunificado
- uma URL de visualização do gateway para apresentação em Canvas
- um caminho de arquivo renderizado (PNG ou PDF) para entrega por mensagem
- ambas as saídas em uma chamada
Início rápido
- Habilite o plugin.
- Chame
diffscommode: "view"para fluxos priorizando Canvas. - Chame
diffscommode: "file"para fluxos de entrega de arquivo no chat. - Chame
diffscommode: "both"quando precisar de ambos os artefatos.
Habilitar o plugin
Desabilitar a orientação integrada do sistema
Se você quiser manter a ferramentadiffs habilitada, mas desabilitar sua orientação integrada no prompt do sistema, defina plugins.entries.diffs.hooks.allowPromptInjection como false:
before_prompt_build do plugin diffs, mantendo o plugin, a ferramenta e a Skill complementar disponíveis.
Se você quiser desabilitar tanto a orientação quanto a ferramenta, desabilite o plugin.
Workflow típico do agente
- O agente chama
diffs. - O agente lê os campos
details. - O agente então:
- abre
details.viewerUrlcomcanvas present - envia
details.filePathcommessageusandopathoufilePath - faz ambos
- abre
Exemplos de entrada
Before e after:Referência de entrada da ferramenta
Todos os campos são opcionais, salvo indicação em contrário:before(string): texto original. Obrigatório comafterquandopatché omitido.after(string): texto atualizado. Obrigatório combeforequandopatché omitido.patch(string): texto de diff unificado. Mutuamente exclusivo combeforeeafter.path(string): nome de arquivo exibido para o modo before e after.lang(string): dica de sobrescrita de linguagem para o modo before e after. Valores desconhecidos usam texto simples como fallback.title(string): sobrescrita do título do visualizador.mode("view" | "file" | "both"): modo de saída. O padrão é o padrão do plugindefaults.mode. Alias obsoleto:"image"se comporta como"file"e ainda é aceito por compatibilidade retroativa.theme("light" | "dark"): tema do visualizador. O padrão é o padrão do plugindefaults.theme.layout("unified" | "split"): layout do diff. O padrão é o padrão do plugindefaults.layout.expandUnchanged(boolean): expande seções inalteradas quando o contexto completo está disponível. Opção apenas por chamada (não é uma chave padrão do plugin).fileFormat("png" | "pdf"): formato do arquivo renderizado. O padrão é o padrão do plugindefaults.fileFormat.fileQuality("standard" | "hq" | "print"): preset de qualidade para renderização em PNG ou PDF.fileScale(number): sobrescrita da escala do dispositivo (1-4).fileMaxWidth(number): largura máxima de renderização em pixels CSS (640-2400).ttlSeconds(number): TTL do artefato em segundos para o visualizador e saídas de arquivo independentes. Padrão 1800, máximo 21600.baseUrl(string): sobrescrita da origem da URL do visualizador. SobrescreveviewerBaseUrldo plugin. Deve serhttpouhttps, sem query/hash.
format->fileFormatimageFormat->fileFormatimageQuality->fileQualityimageScale->fileScaleimageMaxWidth->fileMaxWidth
beforeeaftertêm no máximo 512 KiB cada.patchtem no máximo 2 MiB.pathtem no máximo 2048 bytes.langtem no máximo 128 bytes.titletem no máximo 1024 bytes.- Limite de complexidade do patch: no máximo 128 arquivos e 120000 linhas totais.
patchjunto combeforeouafteré rejeitado.- Limites de segurança do arquivo renderizado, válidos para PNG e PDF:
fileQuality: "standard": máximo de 8 MP (8.000.000 pixels renderizados).fileQuality: "hq": máximo de 14 MP (14.000.000 pixels renderizados).fileQuality: "print": máximo de 24 MP (24.000.000 pixels renderizados).- PDF também tem limite máximo de 50 páginas.
Contrato de saída de details
A ferramenta retorna metadados estruturados em details.
Campos compartilhados para modos que criam um visualizador:
artifactIdviewerUrlviewerPathtitleexpiresAtinputKindfileCountmodecontext(agentId,sessionId,messageChannel,agentAccountIdquando disponível)
artifactIdexpiresAtfilePathpath(mesmo valor defilePath, para compatibilidade com a ferramenta de mensagem)fileBytesfileFormatfileQualityfileScalefileMaxWidth
format(mesmo valor defileFormat)imagePath(mesmo valor defilePath)imageBytes(mesmo valor defileBytes)imageQuality(mesmo valor defileQuality)imageScale(mesmo valor defileScale)imageMaxWidth(mesmo valor defileMaxWidth)
mode: "view": apenas campos do visualizador.mode: "file": apenas campos do arquivo, sem artefato de visualizador.mode: "both": campos do visualizador mais campos do arquivo. Se a renderização do arquivo falhar, o visualizador ainda retorna comfileErrore o alias de compatibilidadeimageError.
Seções inalteradas recolhidas
- O visualizador pode mostrar linhas como
N unmodified lines. - Os controles de expansão nessas linhas são condicionais e não são garantidos para todo tipo de entrada.
- Os controles de expansão aparecem quando o diff renderizado tem dados de contexto expansíveis, o que é típico em entradas before e after.
- Em muitos inputs de patch unificado, os corpos de contexto omitidos não estão disponíveis nos hunks do patch analisado, então a linha pode aparecer sem controles de expansão. Esse é o comportamento esperado.
expandUnchangedse aplica apenas quando existe contexto expansível.
Padrões do plugin
Defina padrões globais do plugin em~/.openclaw/openclaw.json:
fontFamilyfontSizelineSpacinglayoutshowLineNumbersdiffIndicatorswordWrapbackgroundthemefileFormatfileQualityfileScalefileMaxWidthmode
viewerBaseUrl(string, opcional)- Fallback pertencente ao plugin para links de visualizador retornados quando uma chamada da ferramenta não passa
baseUrl. - Deve ser
httpouhttps, sem query/hash.
- Fallback pertencente ao plugin para links de visualizador retornados quando uma chamada da ferramenta não passa
Configuração de segurança
security.allowRemoteViewer(boolean, padrãofalse)false: solicitações fora de loopback para rotas do visualizador são negadas.true: visualizadores remotos são permitidos se o caminho com token for válido.
Ciclo de vida e armazenamento de artefatos
- Os artefatos são armazenados na subpasta temporária:
$TMPDIR/openclaw-diffs. - Os metadados do artefato do visualizador contêm:
- ID de artefato aleatório (20 caracteres hex)
- token aleatório (48 caracteres hex)
createdAteexpiresAt- caminho armazenado de
viewer.html
- O TTL padrão do artefato é de 30 minutos quando não especificado.
- O TTL máximo aceito para visualizador é de 6 horas.
- A limpeza roda de forma oportunista após a criação do artefato.
- Artefatos expirados são excluídos.
- A limpeza de fallback remove pastas obsoletas com mais de 24 horas quando os metadados estão ausentes.
URL do visualizador e comportamento de rede
Rota do visualizador:/plugins/diffs/view/{artifactId}/{token}
/plugins/diffs/assets/viewer.js/plugins/diffs/assets/viewer-runtime.js
baseUrl também é preservado para as solicitações de ativos.
Comportamento de construção da URL:
- Se
baseUrlfor fornecido na chamada da ferramenta, ele será usado após validação rigorosa. - Caso contrário, se
viewerBaseUrldo plugin estiver configurado, ele será usado. - Sem nenhuma dessas sobrescritas, a URL do visualizador usa por padrão loopback
127.0.0.1. - Se o modo de bind do gateway for
customegateway.customBindHostestiver definido, esse host será usado.
baseUrl:
- Deve ser
http://ouhttps://. - Query e hash são rejeitados.
- Origem mais caminho base opcional são permitidos.
Modelo de segurança
Proteção do visualizador:- Apenas loopback por padrão.
- Caminhos tokenizados do visualizador com validação rígida de ID e token.
- CSP da resposta do visualizador:
default-src 'none'- scripts e ativos apenas do próprio host
- sem
connect-srcde saída
- Limitação de tentativas para erros remotos quando o acesso remoto está habilitado:
- 40 falhas por 60 segundos
- bloqueio de 60 segundos (
429 Too Many Requests)
- O roteamento de solicitações do navegador para screenshot é deny-by-default.
- Apenas ativos locais do visualizador de
http://127.0.0.1/plugins/diffs/assets/*são permitidos. - Solicitações de rede externas são bloqueadas.
Requisitos de navegador para o modo arquivo
mode: "file" e mode: "both" exigem um navegador compatível com Chromium.
Ordem de resolução:
browser.executablePathna configuração do OpenClaw.- Variáveis de ambiente:
OPENCLAW_BROWSER_EXECUTABLE_PATHBROWSER_EXECUTABLE_PATHPLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH
- Fallback de descoberta de comando/caminho pela plataforma.
Diff PNG/PDF rendering requires a Chromium-compatible browser...
Solução de problemas
Erros de validação de entrada:Provide patch or both before and after text.- Inclua
beforeeafter, ou forneçapatch.
- Inclua
Provide either patch or before/after input, not both.- Não misture modos de entrada.
Invalid baseUrl: ...- Use origem
http(s)com caminho opcional, sem query/hash.
- Use origem
{field} exceeds maximum size (...)- Reduza o tamanho do payload.
- Rejeição de patch grande
- Reduza a quantidade de arquivos ou o total de linhas do patch.
- A URL do visualizador usa
127.0.0.1por padrão. - Para cenários de acesso remoto:
- defina
viewerBaseUrlno plugin, ou - passe
baseUrlpor chamada da ferramenta, ou - use
gateway.bind=customegateway.customBindHost
- defina
- Se
gateway.trustedProxiesincluir loopback para um proxy no mesmo host, por exemplo Tailscale Serve, solicitações brutas ao visualizador em loopback sem headers encaminhados de IP do cliente falham em modo fail-closed por projeto. - Para essa topologia de proxy:
- prefira
mode: "file"oumode: "both"quando precisar apenas de um anexo, ou - habilite intencionalmente
security.allowRemoteViewere definaviewerBaseUrlno plugin ou passe umbaseUrlde proxy/público quando precisar de uma URL de visualizador compartilhável
- prefira
- Habilite
security.allowRemoteViewerapenas quando você quiser acesso externo ao visualizador.
- Isso pode acontecer com entrada de patch quando o patch não carrega contexto expansível.
- Isso é esperado e não indica falha no visualizador.
- O artefato expirou devido ao TTL.
- O token ou o caminho mudou.
- A limpeza removeu dados obsoletos.
Orientação operacional
- Prefira
mode: "view"para revisões interativas locais em Canvas. - Prefira
mode: "file"para canais de chat de saída que precisam de um anexo. - Mantenha
allowRemoteViewerdesabilitado, a menos que sua implantação exija URLs remotas de visualizador. - Defina
ttlSecondscurtos e explícitos para diffs sensíveis. - Evite enviar segredos na entrada do diff quando isso não for necessário.
- Se o seu canal comprime imagens agressivamente, por exemplo Telegram ou WhatsApp, prefira saída em PDF (
fileFormat: "pdf").
- Desenvolvido por Diffs.