Шлюз для мессенджеров
Общайтесь с Hermes из Telegram, Discord, Slack, WhatsApp, Signal, SMS, Email, Home Assistant, Mattermost, Matrix, DingTalk, Feishu/Lark, WeCom, Weixin, BlueBubbles (iMessage), QQ, Yuanbao, Microsoft Teams, LINE, ntfy или прямо из браузера. Шлюз — это единый фоновый процесс, который подключается ко всем настроенным платформам, управляет сессиями, выполняет cron-задачи и доставляет голосовые сообщения.
Полный набор голосовых возможностей — включая режим микрофона в CLI, голосовые ответы в мессенджерах и разговоры в голосовых каналах Discord — описан в разделах Голосовой режим и Использование голосового режима с Hermes.
Ботам нужен и провайдер модели, и провайдеры инструментов (TTS, веб-поиск). Подписка Nous Portal включает всё сразу.
Статус мессенджеров в десктопе и дашборде
Статус мессенджеров относится к выбранному профилю на выбранной машине. Учётные данные,
сохранённые через hermes gateway setup, способны включить платформу, работающую по
учётным данным, даже без записи в platforms в config.yaml; а явный
platforms.<name>.enabled: false по-прежнему её выключает. Учётные данные серверного
процесса другой профиль не наследует никогда. Платформы без обязательных полей учётных
данных не включаются лишь потому, что этот список пуст.
Если назвать собственный профиль сервера явно (например, profile=default на сервере с
профилем по умолчанию), статус будет тот же, что и у запроса без уточнения. Saved
означает, что учётные данные сохранены, — а не что шлюз сообщений работает и платформа
подключена. Включённая платформа вполне справедливо может показывать Messaging gateway
stopped.
Сравнение платформ
| Платформа | Голос | Изображения | Файлы | Треды | Реакции | Индикатор набора | Стриминг |
|---|---|---|---|---|---|---|---|
| Telegram | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ |
| Discord | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Slack | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Google Chat | — | ✅ | ✅ | ✅ | — | ✅ | — |
| — | ✅ | ✅ | — | — | ✅ | ✅ | |
| WhatsApp Cloud API | ✅ | ✅ | ✅ | — | — | ✅ | — |
| Signal | — | ✅ | ✅ | — | — | ✅ | — |
| SMS | — | — | — | — | — | — | — |
| — | ✅ | ✅ | ✅ | — | — | — | |
| Home Assistant (плагин) | — | — | — | — | — | — | — |
| Mattermost | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ |
| Matrix | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| DingTalk | — | ✅ | ✅ | — | ✅ | — | ✅ |
| Feishu/Lark | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| WeCom | ✅ | ✅ | ✅ | — | — | — | — |
| WeCom Callback | — | — | — | — | — | — | — |
| Weixin | ✅ | ✅ | ✅ | — | — | ✅ | — |
| BlueBubbles | — | ✅ | ✅ | — | ✅ | ✅ | — |
| Photon (iMessage) | ✅ | ✅ | ✅ | — | ✅ | ✅ | — |
| ✅ | ✅ | ✅ | — | — | ✅ | — | |
| Yuanbao | ✅ | ✅ | ✅ | — | — | ✅ | ✅ |
| Microsoft Teams | — | ✅ | — | ✅ | — | ✅ | — |
| LINE | — | ✅ | ✅ | — | — | ✅ | — |
| ntfy | — | — | — | — | — | — | — |
| Raft | — | — | — | — | — | — | — |
| IRC | — | — | — | — | — | — | — |
| Buzz | — | ✅ | — | ✅ | — | — | — |
| SimpleX | ✅ | ✅ | ✅ | — | — | ✅ | — |
Голос — озвученные ответы (TTS) и/или расшифровка голосовых сообщений. Изображения — отправка/приём изображений. Файлы — отправка/приём вложений. Треды — ветвление разговора. Реакции — эмодзи-реакции на сообщения. Индикатор набора — статус «печатает…» во время обработки. Стриминг — постепенное обновление сообщения через редактирование.
Hermes Relay (экспериментальный) — не мессенджер сам по себе, а система коннекторов: она выводит наружу Discord, Telegram, Slack, WhatsApp и другие площадки через внешний коннектор, который держит учётные данные платформы. Возможности (медиа, нативные запросы подтверждения и уточнения, реакции, треды, индикатор набора, стриминг) согласуются с каждым коннектором на этапе рукопожатия, а не зафиксированы таблицей выше.
Архитектура
flowchart TB
subgraph Gateway["Hermes Gateway"]
subgraph Adapters["Platform adapters"]
tg[Telegram]
dc[Discord]
wa[WhatsApp]
sl[Slack]
gc[Google Chat]
sig[Signal]
sms[SMS]
em[Email]
ha[Home Assistant]
mm[Mattermost]
mx[Matrix]
dt[DingTalk]
fs[Feishu/Lark]
wc[WeCom]
wcb[WeCom Callback]
wx[Weixin]
bb[BlueBubbles]
qq[QQ]
yb[Yuanbao]
ms[Microsoft Teams]
api["API Server<br/>(OpenAI-compatible)"]
wh[Webhooks]
end
store["Session store<br/>per chat"]
agent["AIAgent<br/>run_agent.py"]
cron["Cron scheduler<br/>ticks every 60s"]
end
tg --> store
dc --> store
wa --> store
sl --> store
gc --> store
sig --> store
sms --> store
em --> store
ha --> store
mm --> store
mx --> store
dt --> store
fs --> store
wc --> store
wcb --> store
wx --> store
bb --> store
qq --> store
yb --> store
ms --> store
api --> store
wh --> store
store --> agent
cron --> store
Каждый адаптер платформы принимает сообщения, пропускает их через хранилище сессий для конкретного чата и передаёт AIAgent на обработку. Помимо этого шлюз запускает планировщик cron, который проверяет очередь задач каждые 60 секунд.
Токены осознанного молчания
Для групповых чатов, хуков и автоматизации Hermes поддерживает явные токены молчания. Если финальный ответ агента состоит ровно из одного поддерживаемого токена, шлюз подавляет исходящую доставку и ничего не отправляет в чат.
Поддерживаемые токены:
[SILENT]SILENTNO_REPLYNO REPLY[静默]/静默и[沉默]/沉默— китайские варианты, которые модель выдаёт, когда переводит маркер вместо того, чтобы выпустить его дословно
Пробелы и регистр нормализуются, но токеном должен быть весь финальный ответ целиком. Фраза вида «Используйте [SILENT], когда ничего не изменилось» будет доставлена как обычно.
Молчание — это решение только про доставку. Ход с молчанием ассистента всё равно попадает в стенограмму сессии, поэтому диалог по-прежнему чередуется нормально:
user: side-channel chatter
assistant: [SILENT] # stored, not delivered
user: next message
Неудачные ходы по-прежнему проявляются как ошибки — Hermes не скрывает сбой только потому, что текст похож на токен молчания.
На сообщение от человека голый токен молчания заменяется коротким уведомлением: сообщение, требовавшее ответа, не должно просто исчезнуть. Внутренние пробуждения вроде уведомлений фоновых процессов могут остаться без ответа, как и сообщение, которое адаптер платформы помечает как не адресованное боту. Slack так помечает сообщения, которые начинаются с @-упоминания другого человека, и сообщения верхнего уровня без упоминания, открывающие новую ветку в канале со свободными ответами; на остальных платформах уведомление приходит всегда.
Быстрая настройка
Проще всего настроить платформы для мессенджеров через интерактивный мастер:
hermes gateway setup # Interactive setup for all messaging platforms
Мастер проведёт вас через настройку каждой платформы с выбором стрелками, покажет, какие платформы уже настроены, и предложит запустить/перезапустить шлюз по завершении.
Команды шлюза
hermes gateway # Run in foreground
hermes gateway setup # Configure messaging platforms interactively
hermes gateway install # Install as a user service (Linux) / launchd service (macOS)
sudo hermes gateway install --system # Linux only: install a boot-time system service
hermes gateway start # Start the default service
hermes gateway stop # Stop the default service
hermes gateway status # Check default service status
hermes gateway status --system # Linux only: inspect the system service explicitly
Дамп стеков по требованию (SIGUSR2)
На Linux и macOS kill -USR2 <pid шлюза> дописывает дамп стеков всех потоков в
~/.hermes/logs/gateway_faulthandler.log, а шлюз продолжает работать — так можно
посмотреть, чем занят зависший или странно ведущий себя шлюз, не перезапуская его.
Встроенный сторож живости цикла событий
На любой платформе шлюз держит вне цикла событий поток-сторож, который прощупывает
цикл asyncio (gateway.loop_watchdog_probe_interval_s, по умолчанию 30 с). Если цикл
перестаёт диспетчеризовать задачи на gateway.loop_watchdog_max_strikes проверок подряд
(по умолчанию 3), значит, вместе с ним замёрзли и служебные задачи, и планировщик cron, и
встроенный диспетчер kanban. Тогда сторож сбрасывает в лог стеки всех потоков, помечает
gateway_state.json значениями gateway_state: degraded и
exit_reason: loop_liveness_watchdog и завершается с кодом 75, чтобы супервизор службы
перезапустил процесс. hermes gateway status показывает эту запись как
⚠ Gateway exited degraded: event loop stopped dispatching …, пока её не перезапишет
новый процесс шлюза, а бейдж шлюза в дашборде показывает Degraded с той же причиной.
Чтобы отключить сторож, задайте gateway.loop_watchdog: false в config.yaml.
Служебные задачи к тому же на каждом тике (60 с) обновляют updated_at в
gateway_state.json, так что эта метка работает и как пульс: если процесс ещё жив, а
метка старше 120 с, hermes gateway status печатает
⚠ Gateway heartbeat stale: housekeeping has not refreshed gateway_state.json for N s …, а бейдж в дашборде показывает Heartbeat stale — случай «вроде работает,
но ничего не планируется». Перезапустите шлюз.
Опциональный сторож цикла событий (Linux)
Шлюз под управлением systemd можно подписать на восстановление процесса, когда цикл событий asyncio перестаёт получать время планировщика. Это закрывает зависания всего процесса — те самые, при которых не работают и проверки живости отдельных платформ:
gateway:
systemd_watchdog_seconds: 120
После изменения настройки перегенерируйте юнит службы:
hermes gateway install --force
Положительное значение переводит сгенерированный юнит на Type=notify, NotifyAccess=main и соответствующий WatchdogSec. Hermes шлёт сердцебиения, только пока его цикл событий вовремя продвигается вперёд; как только они прекращаются, systemd перезапускает процесс. Значение по умолчанию 0 сохраняет прежнее поведение Type=simple. Настройка работает только в Linux с systemd и не считает обычный обрыв сети у платформы отказом цикла событий.
Команды чата (внутри мессенджера)
| Команда | Описание |
|---|---|
/new или /reset | Начать новую беседу |
/model [provider:model] | Показать или сменить модель (поддерживает синтаксис provider:model) |
/personality [name] | Задать личность (none — сбросить) |
/retry | Повторить последнее сообщение |
/undo | Убрать последний обмен репликами |
/status | Показать информацию о сессии |
/whoami | Показать ваш доступ к слэш-командам в этой области (admin / user / unrestricted) |
/stop | Остановить работающего агента |
/approve | Подтвердить выполнение отложенной опасной команды |
/deny | Отклонить отложенную опасную команду |
/sethome | Сделать этот чат домашним каналом |
/compress | Вручную сжать контекст беседы |
/title [name] | Задать или показать название сессии |
/resume [name] | Возобновить ранее названную сессию |
/sessions [all] [search <query>] | Список прошлых сессий; search <query> фильтрует по названию или id |
/usage | Показать расход токенов для этой сессии (/usage reset [--force] использует накопленный сброс лимита Codex) |
/insights [days] | Показать аналитику и статистику использования |
/reasoning [level|show|hide] | Изменить уровень рассуждений или переключить их отображение |
/voice [on|off|tts|join|leave|status] | Управлять голосовыми ответами в мессенджере и поведением голосовых каналов Discord |
/rollback [number] | Показать список или восстановить контрольные точки файловой системы |
/bg <prompt> | Выполнить промпт в отдельной фоновой сессии |
/btw <question> | Задать побочный вопрос по текущей беседе, не прерывая её |
/reload-mcp | Перезагрузить MCP-серверы из конфигурации |
/update | Обновить Hermes Agent до последней версии |
/help | Показать доступные команды |
/<skill-name> | Вызвать любой установленный навык |
Управление сессиями
Сохранение сессии
Сессии сохраняются между сообщениями до момента сброса. Агент помнит контекст вашей беседы.
Поиск прошлых сессий (/sessions)
/sessions показывает список ваших прошлых сессий для текущего чата — включая ту, в которой вы сейчас находитесь, помеченную (current), — а /sessions <name> возобновляет одну из них (короткая форма /resume). Когда список разрастается, /sessions search <query> (псевдоним find) фильтрует по совпадению названия или id сессии, сортируя по свежести активности. Просмотр сессий из чужих чатов через /sessions all доступен только администраторам — обычный пользователь получает уведомление о том, что список остался ограничен его чатом, и видит только сессии своего чата.
Переопределения /model теперь переживают перезапуск
Переключение /model в чате шлюза действует на эту сессию и теперь переживает перезапуск шлюза: выбор модели и провайдера сохраняется в хранилище сессий и восстанавливается при первом обращении после перезапуска (учётные данные разрешаются заново в момент загрузки и на диск не пишутся). /new (или /reset) переопределение снимает, а /model <name> --global вместо этого прописывает выбор в config.yaml. /model <name> --once действует ровно на один ход.
Надёжность доставки
Финальные ответы агента записываются в устойчивый журнал доставки (state.db) вокруг каждой отправки на платформу. Если шлюз упал или перезапустился между тем, как ответ сформирован, и подтверждением от платформы, следующий запуск доставит сохранённый ответ заново — вместо того чтобы потерять его или переигрывать весь ход. Журнал живёт в том домашнем каталоге, из которого запущен шлюз; мультиплексированный шлюз хранит там же и ответы всех обслуживаемых профилей.
Семантика честная, «хотя бы один раз»:
- Ответ, отправка которого не началась, доставляется как есть.
- Ответ, который был в процессе отправки в момент падения шлюза (платформа могла его получить, а могла и нет), в том числе повторная доставка, которую ещё отправлял предыдущий запуск, доставляется заново с видимой пометкой «♻️ Recovered reply — … may be a duplicate». Неоднозначность помечается, а не заминается молчаливой переотправкой.
- Финальная отправка, отвергнутая флуд-контролем (скажем, лимитами Telegram), повторяется автоматически, когда истечёт записанное наказание, — ни переподключения, ни перезапуска для этого не нужно. Перезапуск во время наказания подхватывает сохранённый ответ, не тратя попытку повтора и не прогоняя агента заново. Повторы сохраняют исходный профиль бота, чат и тред. Префикс восстановления после лимита предупреждает, что более ранние куски могли уже дойти: по длине сообщения журнал частичную доставку определить не может.
- Любая другая отвергнутая финальная отправка (5xx от платформы, неклассифицированная ошибка) повторяется так же, с нарастающей паузой (30 с, затем 2 мин); последняя попытка из бюджета оставляется до следующего запуска шлюза, так что сбой, переживший таймер, не бросит ответ на произвол судьбы. Навсегда недоступный чат (бот заблокирован, группа удалена) повторно не пробуется.
- Повторы ограничены: 3 попытки, свежесть 24 часа, дальше запись бросается. Доставленные записи чистятся через 7 дней.
Отключается через gateway.delivery_ledger: false в config.yaml (возвращает прежнее поведение: ответы «в полёте» при падении теряются).
Непрерывность сессии
Разговоры в шлюзе не сбрасываются ни по простою, ни на суточной границе. Явно новый разговор
начинают /new или /reset, а сжатие контекста работает автоматически, как и раньше. Ядро игнорирует старые
настройки session_reset, переопределения политик сброса и переменные окружения с таймерами
сброса. Если в вашем конфиге session_reset.mode всё ещё равен idle, daily или both,
при старте шлюза и в hermes doctor появится предупреждение. Чтобы сохранить сбросы по
времени, установите плагин из каталога, который читает тот же блок без изменений:
hermes plugins install hermes-session-reset-policy. Закэшированных агентов могут отпускать ради ресурсов — постоянный разговор
это не подменяет. Ограничение свежести при восстановлении после перезапуска касается
автоматического продолжения, а не истории, которая загрузится, когда вы напишете сообщение.
Переопределения модели и системного промпта по каналам
Разные каналы могут работать с разными моделями и характерами из одного шлюза — скажем, дешёвая быстрая модель в #daily и передовая с промптом-специалистом в #dev. Настраивается через channel_overrides внутри платформы в ~/.hermes/config.yaml:
platforms:
discord:
enabled: true
channel_overrides:
"123456789012345678": # channel/thread id
model: anthropic/claude-sonnet-4.6
provider: anthropic
system_prompt: "You are the #dev channel code-review specialist."
"987654321098765432":
model: openai/gpt-5-mini
Подробности:
- Все три ключа опциональны — задайте только
model, толькоsystem_promptили любое сочетание. Незаданные поля берутся из глобальных умолчаний. - Поиск идёт сначала по точному id канала или треда, затем по id родительского канала или форума — так треды Discord автоматически наследуют переопределение родительского канала.
- Приоритет выбора модели: переопределение
/modelв сессии →channel_overrides→ глобальный конфиг. Пользователь, вызвавший/modelв чате, всё равно побеждает канальное умолчание. - Переопределение
system_promptзаменяет глобальный промпт шлюза для этого канала (оно эфемерно — подставляется на каждом ходу, а не хранится в истории).
Безопасность
По умолчанию шлюз отказывает всем пользователям, которых нет в списке разрешённых или которые не прошли сопряжение через личные сообщения. Это безопасное поведение по умолчанию для бота с доступом к терминалу.
# Restrict to specific users (recommended):
TELEGRAM_ALLOWED_USERS=123456789,987654321
DISCORD_ALLOWED_USERS=123456789012345678
SIGNAL_ALLOWED_USERS=+155****4567,+155****6543
SMS_ALLOWED_USERS=+155****4567,+155****6543
EMAIL_ALLOWED_USERS=trusted@example.com,colleague@work.com
MATTERMOST_ALLOWED_USERS=3uo8dkh1p7g1mfk49ear5fzs5c
MATRIX_ALLOWED_USERS=@alice:matrix.org
DINGTALK_ALLOWED_USERS=user-id-1
FEISHU_ALLOWED_USERS=ou_xxxxxxxx,ou_yyyyyyyy
WECOM_ALLOWED_USERS=user-id-1,user-id-2
WECOM_CALLBACK_ALLOWED_USERS=user-id-1,user-id-2
TEAMS_ALLOWED_USERS=aad-object-id-1,aad-object-id-2
# Or allow
GATEWAY_ALLOWED_USERS=123456789,987654321
# Or explicitly allow all users (NOT recommended for bots with terminal access):
GATEWAY_ALLOW_ALL_USERS=true
Сопряжение через личные сообщения (альтернатива спискам разрешённых)
Вместо ручной настройки идентификаторов пользователей неизвестные пользователи получают одноразовый код сопряжения, когда пишут боту в личные сообщения. Email — исключение: неизвестные отправители email игнорируются, пока сопряжение по почте не включено явно.
# The user sees: "Pairing code: XKGH5N7P"
# You approve them with:
hermes pairing approve telegram XKGH5N7P
# Other pairing commands:
hermes pairing list # View pending + approved users
hermes pairing revoke telegram 123456789 # Remove access
Коды сопряжения истекают через 1 час, ограничены по частоте использования и генерируются криптографически случайным образом.
Администраторы и обычные пользователи
Списки разрешённых отвечают на вопрос «может ли этот человек вообще достучаться до бота?». Разделение на администраторов и пользователей отвечает на другой вопрос: «раз уж он внутри, что ему разрешено делать?»
Каждый допущенный пользователь попадает в один из двух уровней для каждой области видимости (личные сообщения или группа/канал):
- Администратор — полный доступ. Может выполнять любую зарегистрированную слэш-команду (встроенную или из плагина) и пользоваться любой защищённой функцией.
- Обычный пользователь — ограниченный доступ. Может обычным образом общаться с агентом, но выполнять только те слэш-команды, которые вы явно разрешили. Минимальный набор, доступный всегда, —
/helpи/whoami.
Уровни настраиваются отдельно для каждой платформы и для каждой области видимости. Статус администратора в личных сообщениях не подразумевает статус администратора в группе/канале — у каждой области свой список администраторов.
Что уровни ограничивают сегодня: слэш-команды. Разделение работает через живой реестр команд, поэтому охватывает как встроенные команды, так и команды из плагинов без ручной настройки под каждую функцию. Обычный чат при этом не затронут — не-администраторы всё так же могут разговаривать с агентом.
Что может ограничиваться в будущем: по мере добавления новых поверхностей возможностей (доступ к инструментам, смена модели, дорогостоящие операции) они будут опираться на то же разделение на администраторов и пользователей. Настроив разделение уже сейчас, вы избавите себя от необходимости заново продумывать, кто администратор, когда появятся эти будущие ограничения.
Настройка
gateway:
platforms:
discord:
extra:
allow_from: ["111", "222", "333"]
allow_admin_from: ["111"] # admins → all slash commands
user_allowed_commands: [status, model] # what non-admins may run
# Optional: separate group/channel scope
group_allow_admin_from: ["111"]
group_user_allowed_commands: [status]
Обратная совместимость: если allow_admin_from не задан для области видимости, разделение на уровни для неё отключено, и каждый допущенный пользователь получает полный доступ. Существующие установки продолжают работать без изменений — подключайте разделение, когда оно понадобится.
Проверка своего доступа
Используйте /whoami на любой платформе, чтобы увидеть текущую область видимости, свой уровень (admin / user / unrestricted) и какие слэш-команды вам доступны. Если настроен список администраторов, /help и /commands показывают не-администратору только те команды, которые он действительно может выполнить (/help, /whoami плюс user_allowed_commands); администраторы видят полный каталог. Примеры для конкретных платформ смотрите на страницах Telegram и Discord.
Направление агента на ходу
Отправьте сообщение, пока агент работает, чтобы поправить текущий ход:
- Генерация модели перезапускается с контекстом — уже показанные рассуждения и видимый частичный текст сохраняются обычной контрольной точкой ассистента
- Сделанная работа остаётся — прежние вызовы инструментов и их результаты никуда из хода не деваются
- Работающие инструменты доигрывают безопасно — поправка применяется на ближайшей границе результата инструмента, а не убивает инструмент
/stopпо-прежнему жёсткая остановка — ею отменяют текущий ход и работу на переднем плане
Очередь, прерывание или направление (режим при занятом агенте)
По умолчанию сообщение занятому агенту направляет его текущий ход (запущенная в переднем плане команда терминала при этом уходит в фон, а не убивается, поэтому ваше сообщение прочитают сразу). Доступны ещё два режима:
queue— последующие сообщения ждут и выполняются следующим ходом после завершения текущей задачи. Каждое последующее сообщение (текст, голосовое, видео, документ) получает собственный ход в порядке поступления; в один ход-альбом сливается только быстрая серия фотографий.steer— последующие сообщения внедряются в текущий запуск через/steerи попадают к агенту после следующего вызова инструмента. Без прерывания, без нового хода. Если агент ещё не начал работу, поведение откатывается кqueue.
Корректировки со стороны шлюза (включая явный /steer) и перенаправления активного хода несут доступные идентификаторы запросившего события — платформу, чат, тред, отправителя, сообщение, профиль и область — отдельным JSON-контекстом для каждого сообщения. При privacy.redact_pii: true идентификаторы в этом видимом модели контексте на поддерживаемых платформах хешируются, включая альтернативные и родительские; исходные идентификаторы события остаются внутри — для маршрутизации. Иначе идентификаторы сохраняются как есть. Ни один из режимов ни системный промпт сессии не меняет, ни запасного адресата ответа не выбирает. Этот контекст — данные для маршрутизации, а не авторизация и не гарантия автоматической доставки.
display:
busy_input_mode: steer # or queue, or interrupt (default)
busy_ack_enabled: true # set to false to suppress the ⚡/⏳/⏩ chat reply entirely
busy_text_debounce_seconds: 0.35 # quiet window before merged busy text is delivered
busy_text_hard_cap_seconds: 1.0 # never hold merged busy text longer than this
Все четыре ключа читаются из собственного config.yaml каждого профиля, так что у мультиплексированных профилей независимые правила поведения при занятом агенте; переопределения через окружение процесса нет.
При первом сообщении занятому агенту на любой платформе Hermes добавляет к подтверждению занятости однострочную подсказку про этот параметр («💡 First-time tip — …»). Подсказка срабатывает один раз на установку — её фиксирует флаг onboarding.seen.busy_input_prompt. Удалите этот ключ, чтобы увидеть подсказку снова.
Если подтверждение занятости кажется избыточным, установите display.busy_ack_enabled: false. Обработка ввода не меняется, скрывается только сообщение-подтверждение.
Уточняющие вопросы (множественный выбор)
Когда агент задаёт вопрос через инструмент clarify, шлюз рисует варианты нумерованным списком (или нативными кнопками там, где платформа их поддерживает). Уточнение поддерживает и множественный выбор — агент может позволить отметить сразу несколько вариантов:
- Мессенджеры — в запросе написано «Multiple selections allowed»; ответьте номерами через запятую или пробел (например,
1, 3), текстом варианта или своим свободным ответом. - Классический CLI и TUI — множественный выбор рисуется чекбоксами: Space переключает вариант, Enter отправляет выбор.
Вопросы с одиночным выбором работают как раньше: выберите вариант номером, кнопкой или текстом либо наберите собственный ответ через путь «Other».
Уведомления о прогрессе инструментов
Управляйте тем, сколько активности инструментов отображается, в ~/.hermes/config.yaml:
display:
tool_progress: all # off | new | all | verbose | log
tool_progress_command: false # set to true to enable /verbose in messaging
# How progress is grouped on platforms that support message editing:
# accumulate (default) — edit one bubble in place as tools run
# separate — send one message per tool (pre-v0.9 style; noisier)
# Only applies where tool_progress is already enabled.
tool_progress_grouping: accumulate # accumulate | separate
Режим log — файл аудита вместо сообщений в чате
При display.tool_progress: log пузыри прогресса в чат не уходят вовсе. Вместо этого каждый вызов инструмента дописывается строкой в ~/.hermes/logs/tool_calls.log — ротируемый файл аудита (5 МБ × 3 копии), прогоняемый через тот же форматтер с вычищением секретов, что и обычные логи, так что учётные данные на диск не попадают. Берите этот режим, когда нужен полный след вызовов инструментов без шума в чате.
Настраиваемые фразы статуса
Долгие строки статуса шлюза (сердцебиения в духе «всё ещё работаю…») берутся из каталога фраз. Встроенные умолчания лежат в gateway/assets/status_phrases.yaml; свои добавляются файлами внутри HERMES_HOME — так они переезжают вместе с профилем:
~/.hermes/status_phrases.yamlлибо любой*.yamlв~/.hermes/status_phrases/(общепринятые пути, подхватываются сами), либо- укажите в конфиге относительный путь:
display:
status_phrases:
path: status_phrases/whatsapp.yaml # relative to HERMES_HOME
mode: append # append (default) or replace
Файл фраз сопоставляет поверхность (status, generic) со списком строк (не больше 80 фраз на поверхность, по 160 символов). Абсолютные пути и выходы через .. игнорируются, чтобы конфиг оставался переносимым между профилями. Используются только ваши строки фраз — сырые аргументы инструментов, команды и текст рассуждений в статус никогда не подставляются.
Временные метки сообщений в контексте модели
По умолчанию отключено. Если включить, Hermes добавляет к каждому сообщению пользователя
человекочитаемую метку времени (например, [Tue 2026-04-28 13:40:53 CEST])
в контексте модели, чтобы агент знал, когда сообщения были отправлены — это полезно для
временных рассуждений («вы спрашивали это утром…», замечание длинной паузы). Метка не
добавляется к сообщениям ассистента или системному промпту.
gateway:
message_timestamps:
enabled: false # set true to show send-times to the model
Сохранённые стенограммы всегда остаются чистыми — метка времени хранится как метаданные сообщения независимо от этого переключателя, так что включение опции позже также раскрывает время отправки для прошлых сообщений, а повторное воспроизведение никогда не накапливает дублирующиеся префиксы.
Когда опция включена, бот присылает статусные сообщения по ходу работы:
💻 `ls -la`...
🔍 web_search...
📄 web_extract...
🐍 execute_code...
Фоновые сессии
Запустите промпт в отдельной фоновой сессии, чтобы агент работал над ним независимо, пока основной чат остаётся отзывчивым:
/bg Check all servers in the cluster and report any that are down
Hermes подтверждает запуск немедленно:
🔄 Background task started: "Check all servers in the cluster..."
Task ID: bg_143022_a1b2c3
Как это работает
Каждый промпт /bg порождает отдельный экземпляр агента, который работает асинхронно:
- Изолированная сессия — у фонового агента своя сессия со своей историей беседы. Он ничего не знает о контексте текущего чата и получает только тот промпт, который вы указали.
- Та же конфигурация — наследует модель, провайдера, наборы инструментов, настройки рассуждений и маршрутизацию провайдера из текущей настройки шлюза.
- Неблокирующий режим — основной чат остаётся полностью интерактивным. Отправляйте сообщения, выполняйте другие команды или запускайте новые фоновые задачи, пока эта работает.
- Доставка результата — по завершении задачи результат отправляется обратно в тот же чат или канал, откуда была вызвана команда, с префиксом «✅ Background task complete». В случае сбоя вы увидите «❌ Background task failed» с текстом ошибки.
Уведомления о фоновых процессах
Когда агент в фоновой сессии запускает долгоживущие процессы (серверы, сборки и т. п.) через terminal(background=true), шлюз может присылать в чат обновления статуса. Управляется это параметром display.background_process_notifications в ~/.hermes/config.yaml:
display:
background_process_notifications: concise # concise | all | result | error | off
| Режим | Что вы получаете |
|---|---|
concise | Однострочное сообщение о статусе по завершении; при сбое добавляется короткий хвост вывода (по умолчанию) |
all | Обновления по ходу выполнения и финальное сообщение о статусе с хвостом вывода |
result | Только финальное сообщение о статусе с хвостом вывода (вне зависимости от кода выхода) |
error | Только финальное сообщение о статусе с хвостом вывода, если код выхода ненулевой |
off | Никаких сообщений от наблюдателя за процессом. Учитывается и в CLI, TUI и Desktop: завершения и heartbeat фоновых процессов больше не будят агента (результаты субагентов по-прежнему будят) |
Этот же параметр можно задать через переменную окружения:
HERMES_BACKGROUND_NOTIFICATIONS=result
При terminal(background=true, notify_on_complete=true) завершившийся процесс запускает новый ход агента, и агент сам сообщает результат, так что отдельная строка статуса не отправляется. Исключение — процесс, завершившийся, пока ход, который его запустил, ещё идёт: завершение ставится в очередь как следующий ход агента, а вы сразу получаете однострочный статус concise (если только режим не off или не error при нулевом коде выхода), вместо тишины до конца того хода.
Сценарии использования
- Мониторинг серверов — «/bg Check the health of all services and alert me if anything is down»
- Долгие сборки — «/bg Build and deploy the staging environment», пока вы продолжаете переписку
- Исследовательские задачи — «/bg Research competitor pricing and summarize in a table»
- Операции с файлами — «/bg Organize the photos in ~/Downloads by date into folders»
Фоновые задачи в мессенджерах работают по принципу «запустил и забыл» — не нужно ждать или проверять их состояние. Результат придёт в тот же чат автоматически, когда задача завершится.
Управление службой
Linux (systemd)
hermes gateway install # Install as user service
hermes gateway start # Start the service
hermes gateway stop # Stop the service
hermes gateway status # Check status
journalctl --user -u hermes-gateway -f # View logs
# Enable lingering (keeps running after logout)
sudo loginctl enable-linger $USER
# Or install a boot-time system service that still runs as your user
sudo hermes gateway install --system
sudo hermes gateway start --system
sudo hermes gateway status --system
journalctl -u hermes-gateway -f
Используйте пользовательскую службу на ноутбуках и машинах для разработки. Используйте системную службу на VPS или headless-хостах, которые должны подниматься при загрузке независимо от systemd linger.
ExecStopPost для завершения процесса
Юнит, который устанавливает Hermes, уже корректно останавливает шлюз через KillMode=mixed + KillSignal=SIGTERM и использует Restart=always с RestartForceExitStatus, чтобы обновления и /restart перезапускали процесс правильно. Не добавляйте systemd drop-in вида ExecStopPost=/bin/kill -9 $MAINPID — ExecStopPost срабатывает при каждой остановке, включая штатные рестарты, поэтому он отправляет SIGKILL только что запущенному экземпляру ещё до его стабилизации, а Restart=always немедленно перезапускает его заново. В итоге получается бесконечный цикл перезапусков (а в Telegram — поток сообщений о рестартах). Если вы уже добавили такой drop-in, удалите его: systemctl --user edit hermes-gateway (или sudo systemctl edit hermes-gateway для системной службы), уберите строку ExecStopPost и выполните systemctl --user daemon-reload.
Прямой systemctl restart / stop завершает работу чисто
Установленный юнит объявляет ExecStop=, который до доставки SIGTERM записывает для $MAINPID маркер плановой остановки, поэтому прямая остановка или перезапуск службы считаются намеренными: шлюз доделывает работу, сохраняет gateway_state=stopped и выходит с кодом 0 — в журнале видна чистая остановка и запуск без строки Failed with result exit-code.
systemctl --user restart hermes-gateway # or: sudo systemctl restart hermes-gateway
Если важны ходы агента, которые ещё идут, предпочитайте hermes gateway restart: он просит шлюз сначала доделать работу (SIGUSR1, с учётом бюджета ожидания перезапуска) и дожидается замены, тогда как сырой systemctl restart останавливает текущий процесс по расписанию systemd. После обновления Hermes один раз выполните hermes gateway restart, чтобы работающая служба подхватила перегенерированный юнит со строкой ExecStop= (hermes gateway status предупреждает, пока установленный юнит устарел).
Установленный юнит также сопоставляет systemctl reload hermes-gateway с SIGUSR1. Для Hermes reload поэтому означает мягкое завершение работы, выход процесса и перезапуск супервизором; это не перезагрузка конфигурации внутри процесса. Если нужно, чтобы CLI дождался процесса-замены и проверил его, используйте hermes gateway restart.
Системной службе нужен root для каждого перезапуска — в том числе для автоматического перезапуска шлюза в конце hermes update. Если hermes update выполняется от имени обычного пользователя, он пробует беспарольный sudo systemctl; если это недоступно, перезапуск пропускается, и выводится команда sudo systemctl restart hermes-gateway для ручного запуска (никакого интерактивного запроса пароля никогда не будет).
Для headless-виртуалки, в которую вы никогда не заходите вручную, пользовательская служба с включённым linger даёт то же поведение запуска при загрузке, но вообще без участия root:
hermes gateway install # user service
sudo loginctl enable-linger $USER # one-time: start at boot, survive logoutПосле этого hermes update сможет перезапускать шлюз без каких-либо привилегий. Если вы предпочитаете оставить системную службу, либо запускайте обновления через sudo hermes update, либо выдайте учётной записи службы беспарольный sudo для systemctl, например в sudo visudo -f /etc/sudoers.d/hermes-gateway:
hermes ALL=(root) NOPASSWD: /usr/bin/systemctl --no-ask-password reset-failed hermes-gateway*, /usr/bin/systemctl --no-ask-password start hermes-gateway*, /usr/bin/systemctl --no-ask-password restart hermes-gateway*Избегайте одновременной установки и пользовательского, и системного юнита шлюза, если только вы не делаете это осознанно. Hermes предупредит, если обнаружит оба сразу, поскольку поведение start/stop/status становится неоднозначным.
Установленный юнит (или plist launchd) принадлежит тому HERMES_HOME, который в нём закреплён. Шлюз, запущенный из другого домашнего каталога (например, тестового или временного, который случайно получает то же имя сервиса), его никогда не перезаписывает: gateway run, start, restart и install --force отказываются с сообщением, называющим оба каталога, и не трогают файл. Чтобы намеренно направить существующий сервис на текущий каталог, выполните hermes gateway install --force-unit-path.
hermes gateway install (как и мастер hermes gateway setup) отказывается ставить пользовательскую службу, если Hermes обнаруживает, что работает внутри контейнера. Пользовательский юнит ложится в ~/.config/systemd/user, и когда этот домашний каталог примонтирован с хоста (podman/distrobox), собственный systemd --user хоста включает и запускает тот же юнит — второй шлюз, опрашивающий тот же токен бота. Запускайте шлюз главным процессом контейнера (hermes gateway run с политикой перезапуска контейнера) либо в контейнере с systemd (systemd как PID 1) ставьте изолированный системный уровень: sudo hermes gateway install --system --run-as-user <user>.
Если на одной машине запущено несколько установок Hermes (с разными каталогами HERMES_HOME), у каждой будет своё имя службы systemd. Установка по умолчанию ~/.hermes использует hermes-gateway; остальные установки используют hermes-gateway-<hash>. Команды hermes gateway автоматически нацеливаются на нужную службу для текущего HERMES_HOME.
macOS (launchd)
hermes gateway install # Install as launchd agent
hermes gateway start # Start the service
hermes gateway stop # Stop the service
hermes gateway status # Check status
tail -f ~/.hermes/logs/gateway.log # View logs
Сгенерированный plist находится в ~/Library/LaunchAgents/ai.hermes.gateway.plist. Он включает три переменные окружения:
- PATH — ваш полный PATH оболочки на момент установки, с добавленными в начало
bin/виртуального окружения иnode_modules/.bin. Это гарантирует, что установленные пользователем инструменты (Node.js, ffmpeg и т. д.) доступны для подпроцессов шлюза, таких как мост WhatsApp. - VIRTUAL_ENV — указывает на виртуальное окружение Python, чтобы инструменты могли корректно находить пакеты.
- HERMES_HOME — привязывает шлюз к вашей установке Hermes.
Файлы plist для launchd статичны — если вы устанавливаете новые инструменты (например, новую версию Node.js через nvm или ffmpeg через Homebrew) уже после настройки шлюза, запустите hermes gateway install ещё раз, чтобы зафиксировать обновлённый PATH. Шлюз обнаружит устаревший plist и перезагрузится автоматически.
В plist задан RunAtLoad, поэтому его загрузка запускает шлюз. hermes gateway install --no-start-now, как и ответ No на вопрос «Start the gateway now?» в hermes gateway setup, записывает plist, не загружая его: шлюз стартует при следующем входе в систему или когда вы выполните hermes gateway start. Шлюз, который launchd уже запустил, перезагружается на новый plist, а не останавливается.
Local Network Privacy в macOS приписывает сокет исполняемому файлу, который launchd запустил для задания. У голого Python из venv нет идентичности приложения, поэтому шлюз под launchd не мог достучаться до хостов в LAN (Home Assistant, локальные серверы моделей): каждое подключение падало с errno 65 No route to host, хотя тот же URL открывался из Terminal, а запроса на разрешение не появлялось вовсе. Поэтому сгенерированный plist запускает шлюз через /usr/bin/osascript; вызов JXA system() стартует шлюз без интерактивного цикла опроса событий, и его дочерние процессы macOS считает процессами самого osascript — платформенного бинарника Apple, на который проверка не распространяется. ps показывает osascript → stderr_timestamp → gateway run; stop/restart/KeepAlive работают ровно как раньше. Plist, установленный старой версией Hermes, обновляется командой hermes gateway install (или при следующем hermes gateway start).
hermes auth add / hermes auth reset
Агенты работают потоками внутри единственного процесса шлюза; дочерние процессы — только подпроцессы инструментов (команды терминала, браузеры), и учётных данных провайдера они не держат. Работающий шлюз к тому же перечитывает логин openai-codex, засеянный из auth.json, когда его пул в следующий раз выбирает эту запись после того, как она ушла в exhausted или dead (записи, добавленные через hermes auth add openai-codex, — независимые аккаунты и не пересинхронизируются). Если нужно перевести все сессии на свежий логин разом, перезапустите шлюз, но предпочтите путь с аккуратным завершением, а не голое убийство процесса:
hermes gateway restartпросит шлюз (SIGUSR1) не принимать новые ходы, ждёт доagent.restart_after_turn_timeout(по умолчанию 1800 с), пока доработают текущие, выходит и даётKeepAliveв launchd перезапустить его; новый процесс читаетauth.jsonс нуля.launchctl kickstart -k gui/$UID/ai.hermes.gatewayвместо этого шлёт SIGTERM: шлюз прерывает идущие ходы чата послеagent.restart_drain_timeout(по умолчанию0— сразу; пользователю сообщают об этом, и ход продолжится с его следующим сообщением), даёт cron-запускам и запускам api_server (/v1)agent.cron_drain_timeout(по умолчанию 30 с), убивает подпроцессы инструментов и выходит, после чего launchd его перезапускает. От старого процесса не остаётся ничего, так что если сессия после перезапуска всё ещё падает с401, она говорит с другим процессом шлюза — поищите второй PID черезhermes gateway status(иlaunchctl list | grep hermes), например вручную запущенныйhermes gateway run, и остановите и его.
Как и в случае с systemd-службой на Linux, у каждого каталога HERMES_HOME свой ярлык launchd. Установка по умолчанию ~/.hermes использует ai.hermes.gateway; остальные установки используют ai.hermes.gateway-<suffix>.
Windows (Планировщик заданий)
hermes gateway install # Register the Hermes_Gateway Scheduled Task (runs at logon)
hermes gateway start # Start the gateway hidden, without a console window
hermes gateway stop # Drain and stop the service
hermes gateway status # Check status, including registration drift
Запланированное задание запускает wscript.exe со сгенерированным лаунчером .vbs из %USERPROFILE%\.hermes\gateway-service\. Лаунчер стартует python.exe -m hermes_cli.main gateway run в скрытом окне и сразу выходит — так задумано: у wscript.exe нет консоли, поэтому при входе в систему он никогда не получает CTRL_CLOSE_EVENT, который убивает шлюз, запущенный из cmd.exe, а шлюз наследует одну скрытую консоль, и подпроцессы не мелькают каждый своей (см. hermes_cli/gateway_windows.py::_build_gateway_vbs_script).
Лаунчер возвращается сразу после запуска шлюза, поэтому Планировщик заданий видит только код выхода лаунчера. Политика <RestartOnFailure> в зарегистрированном задании срабатывает лишь тогда, когда сам wscript.exe не смог запустить шлюз, — шлюз, который упал или был убит позже, она не перезапускает. Автоперезапуск шлюза в Windows опирается на его собственный внутрипроцессный путь перезапуска (/restart, обновления и команда hermes gateway restart); шлюз, убитый извне, остаётся лежать до hermes gateway start или schtasks /Run /TN <task>.
hermes gateway install записывает задание по текущему шаблону; задание, зарегистрированное старой сборкой, иначе навсегда сохранило бы прежние настройки (без RestartOnFailure, без задержки Delay при входе, со старой командной строкой лаунчера). hermes gateway status сравнивает зарегистрированное задание с текущим шаблоном и предупреждает, если оно старше:
⚠ Scheduled Task registration predates the current template (missing: RestartOnFailure, LogonTrigger Delay; version 1.3 vs 1.4)
Repair: hermes gateway start (or: hermes gateway install)
hermes gateway start и hermes update выполняют то же сравнение и автоматически перерегистрируют разошедшееся задание по текущему шаблону (как обновление юнита systemd на Linux); если schtasks отказывается без повышения прав, запустите заново hermes gateway install — он может запросить подтверждение администратора. Если задание не удаётся опросить, проверка молчит, и смотрит она лишь на несколько настроек, которыми владеет Hermes (версия задания, RestartOnFailure, задержка триггера входа и аргументы лаунчера), так что намеренные локальные правки в остальных частях задания не помечаются.
Наборы инструментов для конкретных платформ
У каждой платформы свой набор инструментов:
| Платформа | Набор инструментов | Возможности |
|---|---|---|
| CLI | hermes-cli | Полный доступ |
| Telegram | hermes-telegram | Полный набор инструментов, включая терминал |
| Discord | hermes-discord | Полный набор инструментов, включая терминал |
hermes-whatsapp | Полный набор инструментов, включая терминал | |
| WhatsApp Cloud API | hermes-whatsapp | Полный набор инструментов, включая терминал (общий набор инструментов с мостом Baileys) |
| Slack | hermes-slack | Полный набор инструментов, включая терминал |
| Google Chat | hermes-google_chat | Полный набор инструментов, включая терминал |
| Signal | hermes-signal | Полный набор инструментов, включая терминал |
| SMS | hermes-sms | Полный набор инструментов, включая терминал |
hermes-email | Полный набор инструментов, включая терминал | |
| Home Assistant (плагин) | hermes-homeassistant | Полный набор инструментов + управление устройствами HA (ha_list_entities, ha_get_state, ha_call_service, ha_list_services) из плагина каталога homeassistant |
| Mattermost | hermes-mattermost | Полный набор инструментов, включая терминал |
| Matrix | hermes-matrix | Полный набор инструментов, включая терминал |
| DingTalk | hermes-dingtalk | Полный набор инструментов, включая терминал |
| Feishu/Lark | hermes-feishu | Полный набор инструментов, включая терминал |
| WeCom | hermes-wecom | Полный набор инструментов, включая терминал |
| WeCom Callback | hermes-wecom-callback | Полный набор инструментов, включая терминал |
| Weixin | hermes-weixin | Полный набор инструментов, включая терминал |
| BlueBubbles | hermes-bluebubbles | Полный набор инструментов, включая терминал |
| QQBot | hermes-qqbot | Полный набор инструментов, включая терминал |
| Yuanbao | hermes-yuanbao | Полный набор инструментов, включая терминал |
| Microsoft Teams | hermes-teams | Полный набор инструментов, включая терминал |
| API Server | hermes-api-server | Полный набор инструментов (без clarify, text_to_speech — у программного доступа нет интерактивного пользователя) |
| Webhooks | hermes-webhook | Полный набор инструментов, включая терминал |
| Raft | hermes-raft | Канал только для пробуждения; агент использует Raft CLI для ввода-вывода сообщений |
Эксплуатация многоплатформенного шлюза
Обычно шлюз одновременно запускает несколько адаптеров (Telegram + Discord + Slack и т. д.). Разделы ниже описывают повседневную эксплуатацию, затрагивающую все платформы сразу.
Команда /platform
Когда шлюз запущен, используйте слэш-команду /platform из любой подключённой CLI-сессии или чата, чтобы осматривать и управлять отдельными адаптерами без перезапуска всего шлюза целиком:
/platform list # show all adapters and their state
/platform pause <name> # stop dispatching new messages to one adapter
/platform resume <name> # re-enable a paused adapter
/platform list показывает, находится ли адаптер в состоянии running, paused (вручную) или paused-by-breaker (см. ниже). Пауза оставляет адаптер загруженным, а его фоновые циклы — живыми: входящие сообщения отбрасываются, но само соединение остаётся открытым, поэтому возобновление происходит мгновенно.
См. также более общую команду сводки статуса /platforms.
Как отключить платформу, чьи учётные данные остались в .env
Ключ platforms.<name>.enabled: false в ~/.hermes/config.yaml теперь главнее всего.
Учётные данные этой платформы, оставшиеся в окружении (TELEGRAM_BOT_TOKEN,
WEIXIN_TOKEN, HASS_TOKEN, EMAIL_*, TWILIO_ACCOUNT_SID, …), по-прежнему
попадают в конфигурацию платформы, чтобы инструменты, работающие только на
отправку, продолжали действовать, но адаптер они больше не поднимают:
platforms:
weixin:
enabled: false # перевешивает WEIXIN_TOKEN из .env
В прежних релизах одно лишь наличие учётных данных включало обратно двенадцать платформ (Weixin, WhatsApp Cloud, Home Assistant, электронная почта, SMS, DingTalk, Feishu, WeCom, callback WeCom, BlueBubbles, QQ Bot, Yuanbao) независимо от этого ключа. Если вы на такое поведение опирались, шлюз теперь при старте пишет по одному WARNING на каждую затронутую платформу — чтобы она не пропала молча:
Platform 'weixin' is explicitly disabled by platforms.weixin.enabled: false in config.yaml,
so the credentials found in the environment (WEIXIN_TOKEN, WEIXIN_ACCOUNT_ID) will NOT start
its adapter. Environment credentials no longer override an explicit disable. Remove the key
or set platforms.weixin.enabled: true to turn it back on.
Если ключ enabled не указывать вовсе, поведение остаётся прежним: есть учётные
данные — адаптер стартует.
Как игнорировать унаследованный прокси (gateway.trust_env)
По умолчанию каждый адаптер платформы уважает HTTP_PROXY / HTTPS_PROXY /
NO_PROXY (и SSL_CERT_FILE) из окружения шлюза, а на macOS ещё и сам определяет
системный прокси. Шлюз, запущенный планировщиком заданий Windows или менеджером
служб, способен унаследовать прокси, которого интерактивная оболочка в глаза не
видела, — например, локальный слушатель Clash или V2Ray, который ещё не поднят, —
и сыпать Cannot connect to host 127.0.0.1:7890 на каждом опросе. Отключить
унаследованный прокси сразу для всех адаптеров:
gateway:
trust_env: false
Явные переменные прокси по платформам (DISCORD_PROXY, TELEGRAM_PROXY,
MATRIX_PROXY, …) продолжают действовать. После изменения перезапустите шлюз.
Автоматический предохранитель
Каждый адаптер обёрнут в предохранитель (circuit breaker). Повторяющиеся ошибки, допускающие повтор (сетевые сбои, ответы о превышении лимита запросов, ответы 5xx от вышестоящего сервиса, разрывы websocket-соединения), приводят к срабатыванию предохранителя — адаптер автоматически ставится на паузу, оператору отправляется уведомление в домашний канал другой активной платформы, если она настроена, и записывается структурированная строка в лог.
Предохранитель не возобновляет работу автоматически — он остаётся разомкнутым, пока вы вручную не выполните /platform resume <name>. Это сделано намеренно: если платформа переживает длительный сбой, вам не нужно, чтобы шлюз без конца пытался переподключиться.
Куда смотреть, если платформа на паузе
Когда адаптер поставлен на паузу, проверьте:
- Лог шлюза (
~/.hermes/logs/gateway.logили лог юнита systemd / launchd). Найдите название платформы и словаcircuit breaker,pausedилиdisabled. Событие срабатывания включает счётчик ошибок и текст последней ошибки. - Вывод
/platform list— показывает текущее состояние и последнюю причину. - Страницу статуса провайдера (статус Telegram Bot API, статус Discord и т. д.). Предохранитель сработал потому, что платформа была нездорова; не пытайтесь возобновить работу, пока она не восстановится.
Как только внешний сервис снова здоров, /platform resume <name> сбрасывает предохранитель и заново включает адаптер.
Уведомления о перезапуске
При перезапуске шлюза (или его остановке с незавершёнными сессиями) он может отправить одноразовое сообщение «агент снова на связи» / «работа агента была прервана» в домашний канал каждой платформы. Это управляется для каждой платформы флагом gateway_restart_notification в config.yaml, который по умолчанию равен true:
gateway:
platforms:
telegram:
home_chat_id: "123456789"
gateway_restart_notification: false # opt out for this platform
discord:
home_chat_id: "987654321"
# gateway_restart_notification omitted → defaults to true
Отключите его на шумных или второстепенных платформах, оставив включённым для основного чата. Уведомление отправляется один раз за перезапуск, независимо от того, сколько сессий было в работе.
Индикаторы набора текста
Пока агент обрабатывает сообщение, шлюз показывает живой статус набора текста на платформах, которые это поддерживают, — «печатает…» в Telegram/Discord/Signal или статус ассистента «думает…» в Slack. Это управляется для каждой платформы флагом typing_indicator в config.yaml, который по умолчанию равен true:
gateway:
platforms:
slack:
typing_indicator: false # don't show "is thinking…" on Slack
telegram:
# typing_indicator omitted → defaults to true
Установите typing_indicator: false на любой платформе, где индикатор не нужен. Некоторым пользователям статус «думает…» в Slack кажется навязчивым (пока он показан, он ещё и ненадолго отключает поле ввода, поскольку использует Slack Assistant API). Отключение только скрывает индикатор — доставка сообщений и всё остальное не меняется. Флаг универсальный, так что один и тот же ключ работает для любой платформы.
Возобновление сессии после перезапуска шлюза
Если шлюз завершает работу с незакрытым вызовом инструмента или генерацией, соответствующие сессии помечаются как restart_interrupted. При следующем запуске шлюз планирует автовозобновление для каждой из них — пользователь получает короткое уведомление в чате («Отправьте любое сообщение после перезапуска, и я попробую продолжить с того места, где остановился»), а сессия подхватывает работу с последнего зафиксированного хода, когда он отвечает.
Возобновляются только ходы, которые действительно были в полёте, и каждый — один раз. Чат, чей ход уже завершился, не получит повторного ответа только потому, что был активен незадолго до падения. Если шлюз убили после того, как агент закончил ответ, но до его отправки, доставляется сохранённый ответ (с пометкой «Recovered reply»), а не генерируется заново.
Это поведение включено по умолчанию и логируется при старте шлюза:
Scheduled auto-resume for N restart-interrupted session(s)
Никакой настройки не требуется. Если уведомление не нужно, установите gateway_restart_notification: false для платформы.
Настройки прогресса по умолчанию для мобильных устройств
Telegram обычно используется как мобильный почтовый ящик, поэтому настройки по умолчанию подстроены под это:
tool_progressпо умолчаниюoff— поток из хлебных крошек по каждому инструменту не заваливает чат.busy_ack_detailпо умолчаниюoff— подтверждения занятости и долгоживущие сигналы-«пульсы» остаются лаконичными (без отладочных деталей вродеiteration 21/60).interim_assistant_messagesостаётся включённым — реальные промежуточные комментарии ассистента (модель буквально рассказывает, что собирается делать) — это полезный сигнал, а не шум.long_running_notificationsостаётся включённым — один редактируемый на месте пузырь «⏳ Working — N min» обновляется каждые несколько минут, чтобы у вас был пульс, а не просто застывшее «печатает…» на полчаса.
Эти значения по умолчанию для платформ действуют, только пока тот же ключ не задан прямо под display:. Глобальные display.tool_progress, display.show_reasoning, display.busy_ack_detail, display.interim_assistant_messages или display.long_running_notifications применяются ко всем платформам и заменяют их значения по умолчанию. config.yaml, скопированный из старого cli-config.yaml.example, задаёт все пять глобально, а старый первый запуск hermes setup записывал tool_progress: all; удалите эти строки, чтобы вернуть значения по умолчанию для платформ.
Отключите любую из включённых по умолчанию опций или, наоборот, включите подробный прогресс для отдельной платформы:
display:
platforms:
telegram:
# Re-enable the tool-progress stream
tool_progress: new
# Show "iteration N/M, running: tool" in heartbeats and busy acks
busy_ack_detail: true
# Or quiet them entirely
interim_assistant_messages: false
long_running_notifications: false
Уведомления о предупреждениях и ошибках (подавление по желанию)
Автоматические уведомления о предупреждениях и ошибках показываются по умолчанию.
Чтобы их подавить, включите suppress_warning_notifications глобально или для
отдельной поверхности:
display:
suppress_warning_notifications: true
platforms:
telegram:
suppress_warning_notifications: false
Этот пример подавляет уведомления глобально, но оставляет их видимыми в
Telegram. Не задавайте настройку или поставьте false, чтобы доставка шла как обычно.
Переопределения для платформ имеют приоритет; null наследует значение. Некорректные
значения подавление не включают.
Настройка управляет автоматическими предупреждениями движка, диагностикой повторов и резервных провайдеров, уведомлениями сторожа и базы данных, уведомлениями о сбоях cron и Kanban, диагностикой фоновых задач и делегирования и сообщениями об ошибках, которые генерируют адаптеры. Она действует на платформы сообщений, на отображение в CLI/TUI и на показ уведомлений API. Классификацию определяет источник: похожий на предупреждение текст в запросе пользователя или обычном результате по формулировке не фильтруется.
Подавление меняет отображение, а не выполнение. Существующие логи, сохранённое диагностическое содержимое, решения о повторах, состояние сбоев, учёт планировщика и курсоры уведомлений остаются доступны. Внутреннее пробуждение ради одной лишь диагностики (сбой субагента или кредитов, уведомление о падении в Kanban) всё равно выполняет свой ход агента — так агент может отреагировать на сбой, а история сессии остаётся согласованной, — и этот ход тарифицируется как обычно; глушатся только его непрошеные текст, медиа и потоковый вывод. Структурированные элементы подтверждения и уточнения, прямые результаты команд и API и запрошенные результаты не превращаются в успех и не отбрасываются. Флаги сбоев API, коды статуса и учёт использования остаются правдивыми, даже когда текст диагностики скрыт.
Cron-параметр failure_deliver по-прежнему выбирает адресата; будет ли там показано
автоматическое уведомление о сбое, решают правила предупреждений этого адресата.
Подавленные доставки закрываются, не заявляя об успешной отправке. Уже принятые
доставки сохраняют свою идентичность и исход.
Правила определяются для профиля-владельца и логического адресата. Ходы агента используют правила своего хода; независимые уведомления и отложенные доставки вычисляют правила на собственной границе доставки. Уже доставленные сообщения не удаляются. Подавление не чинит исходный сбой и не добавляет новое место для логов.
Очистка пузырей прогресса (опционально)
Сообщения о прогрессе инструментов, сигнал-«пульс» «всё ещё работаю…» и пузыри статус-коллбэков тоже можно автоматически удалять после того, как придёт финальный ответ. Включается для каждой платформы через display.platforms.<platform>.cleanup_progress:
display:
platforms:
telegram:
cleanup_progress: true
discord:
cleanup_progress: true
По умолчанию false. Настройку учитывают только платформы, чей адаптер реализует delete_message (сейчас это Telegram и Discord). Неудачные запуски пропускают очистку, чтобы пузыри оставались хлебными крошками.
Дальнейшие шаги
- Настройка Telegram
- Настройка Discord
- Настройка Slack
- Настройка Google Chat
- Настройка WhatsApp
- Настройка WhatsApp Business Cloud API
- Настройка Signal
- Настройка SMS (Twilio)
- Настройка Email
- Интеграция с Home Assistant (плагин из каталога)
- Настройка Mattermost
- Настройка Matrix
- Настройка DingTalk
- Настройка Feishu/Lark
- Настройка WeCom
- Настройка WeCom Callback
- Настройка Weixin (WeChat)
- Настройка BlueBubbles (iMessage)
- Настройка Photon (iMessage)
- Настройка QQBot
- Настройка Yuanbao
- Настройка Microsoft Teams
- Конвейер встреч Teams
- Слушатель вебхуков Microsoft Graph
- Настройка LINE
- Настройка ntfy
- Настройка SimpleX Chat
- Open WebUI + API-сервер
- Настройка Raft
- Настройка IRC
- Настройка Buzz
- Настройка A2A (Agent-to-Agent)
- Вебхуки