Вебхуки
Принимайте события от внешних сервисов (GitHub, GitLab, JIRA, Stripe и др.) и автоматически запускайте выполнение агента Hermes. Адаптер вебхуков запускает HTTP-сервер, который принимает POST-запросы, а затем HMAC-подписки, преобразует полезные данные по запросу агенту и направляет ответы обратно к источнику или на другую настроенную платформу.
Агент обрабатывает событие и может ответить, разместив комментарии в PR, отправив сообщение в Telegram/Discord или записав результат.
Видеурок
Быстрый старт
- Включите через
hermesgatewaysetupили переменные окружения. - Определите маршруты в
config.yamlили создайте их движение с помощьюhermes webhook subscribe - Укажите ваш сервис и отправьте данные на
http://your-server:8644/webhooks/<route-name>
Настройка
Есть два выхода для включения адаптера вебхуков.
Через мастер настройки
hermes gateway setup
Следуйте подсказкам, чтобы включить вебхуки, установить порт и глобальный секрет HMAC.
Через переменные окружения
Добавьте в ~/.hermes/.env:
WEBHOOK_ENABLED=true
WEBHOOK_PORT=8644 # по умолчанию
WEBHOOK_SECRET=your-global-secret
Проверка сервера
После запуска шлюза:
curl http://localhost:8644/health
Ожидаемый ответ:
{"status": "ok", "platform": "webhook"}
Настройка маршрутов {#configuring-routes}
Маршруты определяют, как обрабатываются различные источники вебхуков. Каждый маршрут — это именная запись в разделе platforms.webhook.extra.routes вашего config.yaml.
Свойства маршрута
| Свойство | Обязательно | Описание |
|---|---|---|
события |
Нет | Список типов событий для приема (например, ["pull_request"]). Если пусто, примем все события. Тип событий читается из X-GitHub-Event, X-GitLab-Event или event_type в источниках данных. |
секрет |
Да | HMAC-секрет для проверки почты. Если маршрут не задан, используется глобальный «секрет». Установите INSECURE_NO_AUTH только для тестирования (проверка запуска). |
подсказка |
Нет | Шаблонная строка с доступом к данным через точечную нотацию (например, {pull_request.title}). Если опущены, в запросе остаются полные JSON-данные. |
навыки |
Нет | Список названий функций для загрузки при выполнении агента. |
доставить |
Нет | Куда отправить ответ: github_comment, telegram, discord, slack, signal, sms, whatsapp, matrix, mattermost, homeassistant, email, dingtalk, feishu, wecom, weixin, bluebubbles, qqbot или log (по умолчанию). |
доставить_экстра |
Нет | Дополнительная разновидность доставки — ключи происходят по типу «deliver» (например, «repo», «pr_number», «chat_id»). В Значениях используются те же шаблоны {dot.notation}, что и prompt. |
доставить_только |
Нет | Если true, пропустите агента полностью — отрендеренный шаблон prompt становится буквальным сообщением, которое доставляется. Нулевая стоимость LLM, доставка за долю секунды. См. Режим прямой доставки для случаев использования. Требует, чтобы "доставка" была видимым объектом (не "журнал"). |
Полный пример
platforms:
webhook:
enabled: true
extra:
port: 8644
secret: "global-fallback-secret"
routes:
github-pr:
events: ["pull_request"]
secret: "github-webhook-secret"
prompt: |
Проверь этот pull request:
Репозиторий: {repository.full_name}
PR #{number}: {pull_request.title}
Автор: {pull_request.user.login}
URL: {pull_request.html_url}
URL diff: {pull_request.diff_url}
Действие: {action}
skills: ["github-code-review"]
deliver: "github_comment"
deliver_extra:
repo: "{repository.full_name}"
pr_number: "{number}"
deploy-notify:
events: ["push"]
secret: "deploy-secret"
prompt: "Новый push в {repository.full_name} ветка {ref}: {head_commit.message}"
deliver: "telegram"
Шаблоны запросов
Запросы использования точечной нотации для доступа к вложенным полям данных вебхука:
{pull_request.title}разрешается вpayload["pull_request"]["title"]{repository.full_name}разрешается вpayload["repository"]["full_name"]{__raw__}— специальный токен, который выводит все полезные данные в виде JSON с отступами (обрезается до 4000 символов). Полезно для оповещений или базы вебхуков, где агенту нужен полный контекст.- Отсутствующие ключи отображаются как буквенная строка
{key}(без ошибок) - Вложенные словари и упорядочены сериализуются в JSON и обрезаются до 2000 символов.
Вы можете переключать {__raw__} с обычными переменными шаблонами:
prompt: "PR #{pull_request.number} от {pull_request.user.login}: {__raw__}"
Если для маршрута не настроен шаблон «подсказка», все полезные данные создаются в виде JSON с отступами (обрезается до 4000 символов).
Те же самые шаблоны точечной нотации работают в значениях deliver_extra.
Доставка в тему форума
При отправке ответов вебхука в Telegram вы можете указать конкретную тему форума, включив message_thread_id (или thread_id) в deliver_extra:
webhooks:
routes:
alerts:
events: ["alert"]
prompt: "Оповещение: {__raw__}"
deliver: "telegram"
deliver_extra:
chat_id: "-1001234567890"
message_thread_id: "42"
Если chat_id не указан в deliver_extra, доставка возвращается на домашний канал, настроенный для открытой платформы.
Проверка PR на GitHub (пошагово) {#github-pr-review}
Это руководство устанавливает минимальное рецензирование кода при каждом запросе на включение.
1. Создать вебхук на GitHub
- Перейдите в свой репозиторий → Настройки → Веб-перехватчики → Добавить веб-перехватчик.
- Установите URL-адрес полезной нагрузки в
http://your-server:8644/webhooks/github-pr - Установите Тип контента в
application/json - Установите Secret в соответствии с конфигурацией вашего маршрута (например,
github-webhook-secret). - В разделе Какие события? выберите Разрешить выбирать отдельные события и от запросов Pull-запросы.
- Нажмите Добавить вебхук.
2. Добавить конфигурацию маршрута
Добавьте маршрут github-pr в ваш ~/.hermes/config.yaml, как показано в статье выше.
3. Убедитесь, что CLI gh аутентифицирован.
Тип доставки github_comment использует GitHub CLI для публикации комментариев:
gh auth login
4. Протестируйте
Откройте запрос на включение в репозитории. Вебхук с внедрением, Hermes обрабатывает мероприятие и публикует рецензирующий комментарий в PR.
Настройка вебхука GitLab {#gitlab-webhook-setup}
Вебхуки GitLab работают круглосуточно, но используют другой механизм аутентификации. GitLab отправляет секрет как простой заголовок X-Gitlab-Token (точное совпадение строк, не HMAC).
1. Создать вебхук в GitLab
- Перейдите в свой проект → Настройки → Вебхуки.
- Установите URL в
http://ваш-сервер:8644/webhooks/gitlab-mr - Введите свой Секретный токен.
- Выберите События мерж-реквеста (и любые другие события, которые вам нужны)
- Нажмите Добавить вебхук.
2. Добавить конфигурацию маршрута
platforms:
webhook:
enabled: true
extra:
routes:
gitlab-mr:
events: ["merge_request"]
secret: "your-gitlab-secret-token"
prompt: |
Проверь этот merge request:
Проект: {project.path_with_namespace}
MR!{object_attributes.iid}: {object_attributes.title}
Автор: {object_attributes.last_commit.author.name}
URL: {object_attributes.url}
Действие: {object_attributes.action}
deliver: "log"
Варианты доставки {#delivery-options}
После настройки доставки, отправьте ответ агенту после обработки событий вебхука.
| Тип доставки | Описание |
|---|---|
журнал |
Записывает ответ в выводе лога шлюза. Это значение по умолчанию и полезно для тестирования. |
github_comment |
Публикует ответ как комментарий к PR/проблеме через CLI gh. Требует deliver_extra.repo и deliver_extra.pr_number. CLI gh должен быть установлен и аутентифицирован на хост-шлюзе (gh auth login). |
телеграмма |
Направляет ответ в Telegram. Использует домашний канал или указывает «chat_id» в «deliver_extra». |
раздор |
Направляет ответ в Discord. Использует домашний канал или указывает «chat_id» в «deliver_extra». |
слаба |
Направляет ответ в Slack. Использует домашний канал или указывает «chat_id» в «deliver_extra». |
сигнал |
Направляет ответ в Signal. Использует домашний канал или указывает «chat_id» в «deliver_extra». |
смс |
Направляет ответ через SMS (Twilio). Использует домашний канал или указывает «chat_id» в «deliver_extra». |
WhatsApp |
Направляет ответ в WhatsApp. Использует домашний канал или указывает «chat_id» в «deliver_extra». |
матрица |
Направляет ответ в Матрице. Использует домашний канал или указывает «chat_id» в «deliver_extra». |
самое важное |
Направляет ответ в Mattermost. Использует домашний канал или указывает «chat_id» в «deliver_extra». |
домашний помощник |
Направляет ответ в Home Assistant. Использует домашний канал или указывает «chat_id» в «deliver_extra». |
электронная почта |
Направляет ответ по электронной почте. Использует домашний канал или указывает «chat_id» в «deliver_extra». |
дингтолк |
Направляет ответ в DingTalk. Использует домашний канал или указывает «chat_id» в «deliver_extra». |
фейшу |
Направляет ответ в Feishu/Lark. Использует домашний канал или указывает «chat_id» в «deliver_extra». |
веком |
Направляет ответ в WeCom. Использует домашний канал или указывает «chat_id» в «deliver_extra». |
вэйсинь |
Направляет ответ в Weixin (WeChat). Использует домашний канал или указывает «chat_id» в «deliver_extra». |
голубые пузыри |
Направляет ответ в BlueBubbles (iMessage). Использует домашний канал или указывает «chat_id» в «deliver_extra». |
Для межплатформенной доставки целевая платформа также должна быть включена и подключена к шлюзу. Если chat_id не указан в deliver_extra, ответ отправляется на настроенный домашний канал платформы.
Режим прямой доставки {#direct-delivery-mode}
По умолчанию каждый POST вебхука запускает выполнение агента — полезные данные становятся запросом, агент обрабатывает их, и агент доставляет ответ. Это расходует токены LLM на каждое событие.
Для случаев использования, когда вы просто хотите отредактировать простое). — без рассуждений, без цикла агента, просто доставьте сообщение — установите deliver_only: true на маршруте. Отрендеренный шаблон prompt становится буквальным индивидуальным сообщением, и адаптер отправляет его напрямую настроенной цели доставки.
Когда использовать прямую доставку
- Внешние сервисы — вебхук Supabase/Firebase с поддержкой предоставления баз данных → мгновенно уведомить пользователя в Telegram
- Оповещения Диптихи — вебхук оповещений Datadog/Grafana → отправить в канал Discord
- Межагентские сигналы — Агент A уведомляет пользователя Агента B о завершении длительной задачи.
- Завершение фоновых заданий — Задание Cron завершено → опубликовать результат в Slack
Преимущества:
- Нулевые токены LLM — агент никогда не возникает
- Доставка за долю секунды — один вызов адаптера, без цикла рассуждений.
- Та же безопасность, что и в режиме агента — HMAC-аутентификация, ограничения скорости, идемпотентность и ограничения размера тела все еще контролируются.
- Синхронный ответ — POST возвращает
200 OK, как только доставка была осуществлена, или502, если цель отклонила его, чтобы ваш вышестоящий сервис мог разумно отобразить
Пример: отправка в Telegram из Supabase
platforms:
webhook:
enabled: true
extra:
port: 8644
secret: "global-secret"
routes:
antenna-matches:
secret: "antenna-webhook-secret"
deliver: "telegram"
deliver_only: true
prompt: "🎉 Новое совпадение: {match.user_name} совпал(а) с вами!"
deliver_extra:
chat_id: "{match.telegram_chat_id}"
Ваша Edge-функция Supabase подписывает полезные данные с помощью HMAC-SHA256 и отправляет POST на https://your-server:8644/webhooks/antenna-matches. Адаптер вебхука затем подписывает, отображает шаблон данных, доставляет в Telegram и возвращает «200 ОК».
Пример: динамическая подписка через CLI
hermes webhook subscribe antenna-matches \
--deliver telegram \
--deliver-chat-id "123456789" \
--deliver-only \
--prompt "🎉 Новое совпадение: {match.user_name} совпал(а) с вами!" \
--description "Уведомления о совпадениях Antenna"
Коды ответов
| Статус | Значение |
|---|---|
200 ОК |
Успешно доставлено. Тело: {"status": "доставлено", "route": "...", "target": "...", "delivery_id": "..."} |
200 ОК (статус = дубликат) |
Дублирующийся ID X-GitHub-Delivery в пределах TTL идемпотентности (1 час). Не доставляется повторно. |
401 Несанкционированный |
HMAC-подпись недействительна или отсутствует. |
400 неверных запросов |
Некорректное тело JSON. |
404 не найден |
Неизвестное имя маршрута. |
413 Полезная нагрузка слишком велика |
Тело превышено max_body_bytes. |
429 Слишком много запросов |
Превышен лимит скорости маршрута. |
502 Bad Gateway |
Целевой адаптер отклонил сообщение или произошла ошибка. Ошибка регистрируется на стороне сервера; тело ответа — общее сообщение «Не удалось доставить», чтобы избежать утечки внутренних деталей адаптера. |
Особенности конфигурации
deliver_only: trueтребует, чтобыdeliverбыл объектом поиска.deliver: log(или отсутствиеdeliver) отклоняется при запуске — адаптер отказывается запускаться, если сочтет неправильный настроенный маршрут.- Поле
skillsотключается в режиме прямой доставки (нет выполнения агента, поэтому нечего внедрять). - Шаблон рендеринга использует тот же синтаксис
{dot.notation}, что и в режиме агента, включая токен{__raw__}. - Идемпотентность использует тот же заголовок
X-GitHub-Delivery/X-Request-ID— повторные попытки с тем же ID возвращаютstatus=duulateи НЕ доставляются повторно.
Динамические подписки (CLI) {#dynamic-subscriptions}
В дополнение к статическим маршрутам в config.yaml вы можете создавать подписки вебхуков с помощью команды CLI hermes webhook. Это особенно полезно, когда сам агент должен настроить триггеры на основе событий.
Создание подписки
hermes webhook subscribe github-issues \
--events "issues" \
--prompt "Новый issue #{issue.number}: {issue.title}\nОт: {issue.user.login}\n\n{issue.body}" \
--deliver telegram \
--deliver-chat-id "-100123456789" \
--description "Сортировка новых issues GitHub"
Он получает URL-адрес вебхука и автоматически генерирует HMAC-секрет. Настройте свой сервис на отправку POST по этому URL.
Список подписок
hermes webhook list
Удаление подписки
hermes webhook remove github-issues
Тестирование подписки
hermes webhook test github-issues
hermes webhook test github-issues --payload '{"issue": {"number": 42, "title": "Test"}}'
Как работать с подпиской
- Подписки хранятся в
~/.hermes/webhook_subscriptions.json - Адаптер вебхуков «горячо» перезагружает этот файл при каждом запросе (с проверкой времени, незначительные дополнительные расходы)
- Статические маршруты из
config.yamlвсегда имеют приоритет над движениями с тем же именем. - Динамические подписки используют тот же маршрут и возможности, что и статические маршруты (события, шаблоны запросов, навыки, доставка)
- Перезагрузка шлюза не требуется — создайте подписку, и она сразу же заработает
Подписки, управляемые агентом
Агент может создавать подписки через инструмент терминала при использовании навыка «webhook-subscriptions». Попросите агента «настроить вебхук для проблем GitHub», и он выполнит соответствующую команду «hermes webhook subscribe».
Безопасность {#security}
Адаптер вебхуков включает несколько уровней безопасности:
Проверка HMAC-подписи
Затем подключите адаптер к подключению мобильных веб-хуков, используя соответствующий метод для каждого источника:
- GitHub: заголовок
X-Hub-Signature-256— шестнадцатеричный дайджест HMAC-SHA256 с префиксомsha256= - GitLab: заголовок
X-Gitlab-Token— простое совпадение строк секрета - Общий: заголовок
X-Webhook-Signature— сырой HMAC-SHA256 hex-дайджест
Если ни один из обнаруженных заголовков не присутствует, запрос отклоняется.
Секрет обязателен
Каждый маршрут должен иметь секрет — либо заданный непосредственно на маршруте, либо не зависящий от глобальной «секретности». Маршруты без секрета при запуске приводят к нужному адаптеру. Только для разработки/тестирования вы можете установить секрет в `"INSECURE_NO_AUTH", чтобы полностью запустить проверку.
INSECURE_NO_AUTH принимается только тогда, когда принимается решение по шлейфу адреса (127.0.0.1, localhost, ::1). Если он сочетается с привязкой не к шлейфу, такому как 0.0.0.0 или IP-адресу локальной сети, адаптер отказывается запускаться — это случайное открытие неаутентифицированной конечной точки на публичном интерфейсе.
Ограничение скорости
Каждый маршрут ограничен 30 запросами в минуту по умолчанию (фиксированное окно). Настройте это глобально:
platforms:
webhook:
extra:
rate_limit: 60 # запросов в минуту
На запросы, превышающие лимит, приходит ответ «429 Too Many Requests».
Идемпотентность
Идентификатор доставки (из X-GitHub-Delivery, X-Request-ID или запасного варианта во временной метке) кэшируется за 1 час. Дублирующиеся доставки (например, повторные попытки вебхука) молча выдают с ответом «200», предотвращающие повторные запуски агента.
Ограничения размера тела
Полезные данные, превышающие 1 МБ, отклоняются до чтения тела. Настроить это:
platforms:
webhook:
extra:
max_body_bytes: 2097152 # 2 МБ