Перейти до основного вмісту

Дифи

diffs — це необов’язковий інструмент plugin із короткими вбудованими системними вказівками та супровідною навичкою, яка перетворює вміст змін на артефакт дифа лише для читання для агентів. Він приймає або:
  • текст before і after
  • уніфікований patch
Він може повертати:
  • URL переглядача gateway для представлення в canvas
  • шлях до відрендереного файла (PNG або PDF) для надсилання в повідомленні
  • обидва результати за один виклик
Коли plugin увімкнено, він додає стислий довідник із використання в простір системного промпта, а також надає докладну навичку для випадків, коли агенту потрібні повніші інструкції.

Швидкий старт

  1. Увімкніть plugin.
  2. Викликайте diffs з mode: "view" для сценаріїв, орієнтованих насамперед на canvas.
  3. Викликайте diffs з mode: "file" для сценаріїв доставки файлів у чаті.
  4. Викликайте diffs з mode: "both", коли потрібні обидва артефакти.

Увімкнення plugin

{
  plugins: {
    entries: {
      diffs: {
        enabled: true,
      },
    },
  },
}

Вимкнення вбудованих системних вказівок

Якщо ви хочете залишити інструмент diffs увімкненим, але вимкнути його вбудовані вказівки для системного промпта, встановіть plugins.entries.diffs.hooks.allowPromptInjection у false:
{
  plugins: {
    entries: {
      diffs: {
        enabled: true,
        hooks: {
          allowPromptInjection: false,
        },
      },
    },
  },
}
Це блокує хук before_prompt_build plugin diffs, але залишає доступними plugin, інструмент і супровідну навичку. Якщо ви хочете вимкнути і вказівки, і інструмент, натомість вимкніть plugin.

Типовий робочий процес агента

  1. Агент викликає diffs.
  2. Агент читає поля details.
  3. Далі агент або:
    • відкриває details.viewerUrl через canvas present
    • надсилає details.filePath через message, використовуючи path або filePath
    • робить обидві дії

Приклади вхідних даних

До і після:
{
  "before": "# Hello\n\nOne",
  "after": "# Hello\n\nTwo",
  "path": "docs/example.md",
  "mode": "view"
}
Патч:
{
  "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): початковий текст. Обов’язковий разом із after, якщо patch пропущено.
  • after (string): оновлений текст. Обов’язковий разом із before, якщо patch пропущено.
  • patch (string): текст уніфікованого дифа. Взаємовиключний із before та after.
  • path (string): відображуване ім’я файла для режиму before/after.
  • lang (string): підказка перевизначення мови для режиму before/after. Невідомі значення переводяться до простого тексту.
  • title (string): перевизначення заголовка переглядача.
  • mode ("view" | "file" | "both"): режим виводу. За замовчуванням використовується значення plugin defaults.mode. Застарілий псевдонім: "image" поводиться як "file" і досі приймається для зворотної сумісності.
  • theme ("light" | "dark"): тема переглядача. За замовчуванням використовується значення plugin defaults.theme.
  • layout ("unified" | "split"): макет дифа. За замовчуванням використовується значення plugin defaults.layout.
  • expandUnchanged (boolean): розгортати незмінені секції, коли доступний повний контекст. Лише параметр окремого виклику (не ключ значення plugin за замовчуванням).
  • fileFormat ("png" | "pdf"): формат відрендереного файла. За замовчуванням використовується значення plugin defaults.fileFormat.
  • fileQuality ("standard" | "hq" | "print"): профіль якості для рендерингу PNG або PDF.
  • fileScale (number): перевизначення масштабу пристрою (1-4).
  • fileMaxWidth (number): максимальна ширина рендерингу в CSS-пікселях (640-2400).
  • ttlSeconds (number): TTL артефакта в секундах для переглядача та окремих файлових виводів. За замовчуванням 1800, максимум 21600.
  • baseUrl (string): перевизначення origin URL переглядача. Перевизначає plugin viewerBaseUrl. Має бути http або https, без query/hash.
Застарілі псевдоніми вхідних даних, які все ще приймаються для зворотної сумісності:
  • format -> fileFormat
  • imageFormat -> fileFormat
  • imageQuality -> fileQuality
  • imageScale -> fileScale
  • imageMaxWidth -> fileMaxWidth
Перевірка й обмеження:
  • Максимум для before і after окремо — 512 KiB.
  • Максимум для patch — 2 MiB.
  • Максимум для path — 2048 байтів.
  • Максимум для lang — 128 байтів.
  • Максимум для title — 1024 байти.
  • Обмеження складності патча: максимум 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. Спільні поля для режимів, які створюють переглядач:
  • artifactId
  • viewerUrl
  • viewerPath
  • title
  • expiresAt
  • inputKind
  • fileCount
  • mode
  • context (agentId, sessionId, messageChannel, agentAccountId, якщо доступні)
Поля файла, коли рендериться PNG або PDF:
  • artifactId
  • expiresAt
  • filePath
  • path (те саме значення, що й filePath, для сумісності з інструментом message)
  • fileBytes
  • fileFormat
  • fileQuality
  • fileScale
  • fileMaxWidth
Для наявних викликачів також повертаються псевдоніми сумісності:
  • format (те саме значення, що й fileFormat)
  • imagePath (те саме значення, що й filePath)
  • imageBytes (те саме значення, що й fileBytes)
  • imageQuality (те саме значення, що й fileQuality)
  • imageScale (те саме значення, що й fileScale)
  • imageMaxWidth (те саме значення, що й fileMaxWidth)
Підсумок поведінки режимів:
  • mode: "view": лише поля переглядача.
  • mode: "file": лише поля файла, без артефакта переглядача.
  • mode: "both": поля переглядача плюс поля файла. Якщо рендеринг файла не вдається, переглядач усе одно повертається з fileError і псевдонімом сумісності imageError.

Згорнуті незмінені секції

  • Переглядач може показувати рядки на кшталт N unmodified lines.
  • Елементи керування розгортанням у таких рядках умовні й не гарантуються для кожного виду вхідних даних.
  • Елементи керування розгортанням з’являються, коли відрендерений диф має дані розгортаного контексту, що типово для вхідних даних before/after.
  • Для багатьох уніфікованих патчів пропущені тіла контексту недоступні в розібраних фрагментах патча, тому рядок може з’являтися без елементів керування розгортанням. Це очікувана поведінка.
  • expandUnchanged застосовується лише тоді, коли існує контекст, який можна розгорнути.

Значення plugin за замовчуванням

Установіть загальні значення plugin за замовчуванням у ~/.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",
          },
        },
      },
    },
  },
}
Підтримувані значення за замовчуванням:
  • fontFamily
  • fontSize
  • lineSpacing
  • layout
  • showLineNumbers
  • diffIndicators
  • wordWrap
  • background
  • theme
  • fileFormat
  • fileQuality
  • fileScale
  • fileMaxWidth
  • mode
Явно задані параметри інструмента перевизначають ці значення за замовчуванням. Постійна конфігурація URL переглядача:
  • viewerBaseUrl (string, необов’язково)
    • Належний plugin резервний варіант для повернених посилань переглядача, коли виклик інструмента не передає baseUrl.
    • Має бути http або https, без query/hash.
Приклад:
{
  plugins: {
    entries: {
      diffs: {
        enabled: true,
        config: {
          viewerBaseUrl: "https://gateway.example.com/openclaw",
        },
      },
    },
  },
}

Конфігурація безпеки

  • security.allowRemoteViewer (boolean, за замовчуванням false)
    • false: запити не через loopback до маршрутів переглядача відхиляються.
    • true: віддалені переглядачі дозволені, якщо токенізований шлях дійсний.
Приклад:
{
  plugins: {
    entries: {
      diffs: {
        enabled: true,
        config: {
          security: {
            allowRemoteViewer: false,
          },
        },
      },
    },
  },
}

Життєвий цикл артефактів і зберігання

  • Артефакти зберігаються в тимчасовій підпапці: $TMPDIR/openclaw-diffs.
  • Метадані артефакта переглядача містять:
    • випадковий ID артефакта (20 hex-символів)
    • випадковий токен (48 hex-символів)
    • 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 зберігається також і для запитів до ресурсів. Поведінка побудови URL:
  • Якщо надано baseUrl у виклику інструмента, він використовується після суворої перевірки.
  • Інакше, якщо налаштовано plugin viewerBaseUrl, використовується він.
  • Без жодного з цих перевизначень URL переглядача за замовчуванням вказує на loopback 127.0.0.1.
  • Якщо режим прив’язки gateway — custom і встановлено gateway.customBindHost, використовується цей хост.
Правила baseUrl:
  • Має бути http:// або https://.
  • Query і hash відхиляються.
  • Дозволено origin плюс необов’язковий базовий шлях.

Модель безпеки

Посилення безпеки переглядача:
  • Лише loopback за замовчуванням.
  • Токенізовані шляхи переглядача зі суворою перевіркою ID і токена.
  • CSP відповіді переглядача:
    • default-src 'none'
    • скрипти й ресурси лише з того ж джерела
    • без зовнішнього connect-src
  • Обмеження частоти віддалених промахів, коли віддалений доступ увімкнено:
    • 40 збоїв за 60 секунд
    • блокування на 60 секунд (429 Too Many Requests)
Посилення безпеки рендерингу файла:
  • Маршрутизація запитів браузера для знімків екрана за замовчуванням усе забороняє.
  • Дозволено лише локальні ресурси переглядача з http://127.0.0.1/plugins/diffs/assets/*.
  • Зовнішні мережеві запити блокуються.

Вимоги до браузера для файлового режиму

Для mode: "file" і mode: "both" потрібен браузер, сумісний із Chromium. Порядок визначення:
  1. browser.executablePath у конфігурації OpenClaw.
  2. Змінні середовища:
    • OPENCLAW_BROWSER_EXECUTABLE_PATH
    • BROWSER_EXECUTABLE_PATH
    • PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH
  3. Резервне визначення через команди/шляхи платформи.
Типовий текст помилки:
  • 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: ...
    • Використовуйте origin http(s) з необов’язковим шляхом, без query/hash.
  • {field} exceeds maximum size (...)
    • Зменште розмір payload.
  • Відхилення великого патча
    • Зменште кількість файлів у патчі або загальну кількість рядків.
Проблеми з доступністю переглядача:
  • URL переглядача за замовчуванням вказує на 127.0.0.1.
  • Для сценаріїв віддаленого доступу:
    • установіть plugin viewerBaseUrl, або
    • передавайте baseUrl для кожного виклику інструмента, або
    • використовуйте gateway.bind=custom і gateway.customBindHost
  • Якщо gateway.trustedProxies включає loopback для проксі на тому самому хості (наприклад Tailscale Serve), сирі loopback-запити до переглядача без заголовків forwarded client-IP навмисно завершуються за принципом fail closed.
  • Для такої топології проксі:
    • віддавайте перевагу mode: "file" або mode: "both", коли вам потрібне лише вкладення, або
    • навмисно увімкніть security.allowRemoteViewer і встановіть plugin viewerBaseUrl або передайте проксі/public baseUrl, коли потрібен URL переглядача, яким можна ділитися
  • Увімкнюйте security.allowRemoteViewer лише тоді, коли вам справді потрібен зовнішній доступ до переглядача.
Рядок незмінених рядків не має кнопки розгортання:
  • Це може трапитися для вхідних даних у форматі patch, якщо патч не містить контексту, який можна розгорнути.
  • Це очікувана поведінка й не означає збій переглядача.
Артефакт не знайдено:
  • Артефакт прострочився через TTL.
  • Токен або шлях змінилися.
  • Очищення видалило застарілі дані.

Операційні рекомендації

  • Віддавайте перевагу mode: "view" для локального інтерактивного перегляду в canvas.
  • Віддавайте перевагу mode: "file" для зовнішніх чат-каналів, яким потрібне вкладення.
  • Тримайте allowRemoteViewer вимкненим, якщо вашому розгортанню не потрібні віддалені URL переглядача.
  • Для чутливих дифів явно задавайте короткий ttlSeconds.
  • Уникайте передавання секретів у вхідних даних дифа, якщо це не потрібно.
  • Якщо ваш канал сильно стискає зображення (наприклад Telegram або WhatsApp), віддавайте перевагу PDF-виводу (fileFormat: "pdf").
Рушій рендерингу дифів:
  • Працює на базі Diffs.

Пов’язані документи