Настройка Discord
Hermes Agent интегрируется с Discord как бот, позволяя общаться с вашим ИИ-ассистентом через личные сообщения или каналы сервера. Бот принимает ваши сообщения, пропускает их через конвейер Hermes Agent (включая работу с инструментами, память и рассуждение) и отвечает в реальном времени. Поддерживаются текст, голосовые сообщения, файловые вложения и слэш-команды.
Прежде чем перейти к настройке — вот что интересует большинство пользователей в первую очередь: как Hermes ведёт себя после появления на сервере.
Как ведёт себя Hermes
| Контекст | Поведение |
|---|---|
| Личные сообщения (DM) | Hermes отвечает на каждое сообщение. @упоминание не требуется. У каждого DM своя отдельная сессия. |
| Каналы сервера | По умолчанию Hermes отвечает только при @упоминании. Если написать в канале без упоминания бота, Hermes проигнорирует сообщение. |
| Каналы свободного ответа | Можно сделать отдельные каналы «безупоминательными» через DISCORD_FREE_RESPONSE_CHANNELS или отключить требование упоминания глобально через DISCORD_REQUIRE_MENTION=false. Сообщения в таких каналах по умолчанию получают ответ прямо в канале — автосоздание тредов пропускается, чтобы канал оставался лёгким чатом. Задайте discord.free_response_auto_thread: true, чтобы получить и ответы без упоминания, и тред на каждое сообщение верхнего уровня. |
| Треды | Hermes отвечает в том же треде. Правила упоминания продолжают действовать, если только этот тред или его родительский канал не настроен как канал свободного ответа. Треды изолированы от родительского канала с точки зрения истории сессии. |
| Общие каналы с несколькими пользователями | По умолчанию Hermes изолирует историю сессии по пользователям внутри канала — ради безопасности и ясности. Два человека, пишущие в одном канале, не делят одну переписку, если вы явно не отключите эту изоляцию. |
| Сообщения с упоминанием других пользователей | Когда DISCORD_IGNORE_NO_MENTION равен true (по умолчанию), Hermes молчит, если сообщение упоминает других пользователей, но не упоминает бота. Это не даёт боту встревать в разговоры, адресованные другим людям. Установите false, если хотите, чтобы бот отвечал на все сообщения независимо от того, кто упомянут. Это применяется только в каналах сервера, но не в личных сообщениях. |
Если нужен обычный канал для общения с Hermes без необходимости каждый раз его тегать, добавьте этот канал в DISCORD_FREE_RESPONSE_CHANNELS.
Модель Discord Gateway
Hermes в Discord — не вебхук, отвечающий без сохранения состояния. Он работает через полноценный шлюз обмена сообщениями, а значит каждое входящее сообщение проходит через:
- авторизацию (
DISCORD_ALLOWED_USERS) - проверку упоминания / свободного ответа
- поиск сессии
- загрузку истории сессии
- обычное выполнение агента Hermes, включая инструменты, память и слэш-команды
- доставку ответа обратно в Discord
Это важно, потому что поведение в загруженном сервере зависит и от маршрутизации Discord, и от политики сессий Hermes.
Модель сессий в Discord
По умолчанию:
- у каждого личного сообщения (DM) своя сессия
- у каждого треда сервера — своё пространство сессий
- у каждого пользователя в общем канале — своя сессия внутри этого канала
Так, если Alice и Bob оба пишут Hermes в #research, по умолчанию Hermes считает это отдельными разговорами, хотя оба используют один и тот же видимый канал Discord.
Это управляется через config.yaml:
group_sessions_per_user: true
Устанавливайте false только если вы явно хотите единую общую переписку для всей комнаты:
group_sessions_per_user: false
Общие сессии полезны для совместной работы в комнате, но при этом:
- пользователи делят рост контекста и расход токенов
- долгая задача одного человека с активным использованием инструментов может раздуть контекст всем остальным
- запущенный процесс одного человека может прервать последующий запрос другого в той же комнате
Прерывания и конкурентность
Hermes отслеживает запущенных агентов по ключу сессии.
При настройке по умолчанию group_sessions_per_user: true:
- если Alice прерывает своё же выполняющееся действие, это затрагивает только её сессию в этом канале
- Bob может продолжать писать в том же канале, не унаследуя историю Alice и не прерывая её выполнение
При group_sessions_per_user: false:
- вся комната делит один слот запущенного агента для этого канала/треда
- последующие сообщения от разных людей могут прерывать друг друга или вставать в очередь
Это руководство проведёт вас через весь процесс настройки — от создания бота в Discord Developer Portal до отправки первого сообщения.
Здоровье WebSocket-шлюза
REST Discord и WebSocket шлюза — разные транспорты. Успешный ответ REST (в том числе fetch_user() с HTTP 200) не доказывает, что бот всё ещё получает события шлюза. Поэтому Hermes смотрит сразу на несколько сигналов: состояние ready, состояние закрытия клиента и сокета, открытость сокета, возраст последнего ACK на heartbeat, конечность задержки heartbeat и — со стороны диспетчеризации — сколько времени прошло с последнего разобранного события шлюза.
После заданного числа подряд идущих нездоровых замеров адаптер выдаёт одно повторяемое фатальное событие. Закрытый транспорт (socket_closed / client_closed) — подтверждённая смерть, и переподключение запускается уже на первом нездоровом замере; порог действует только для мягких сигналов (устаревший ACK на heartbeat, задержка, тишина событий) — см. #118487. Существующий наблюдатель за переподключением шлюза создаёт свежий адаптер; собственного бесконечного цикла переподключения адаптер Discord не запускает.
Несекретные пороги настраиваются в config.yaml:
discord:
websocket_liveness_interval_seconds: 15
websocket_liveness_failure_threshold: 2
websocket_heartbeat_ack_max_age_seconds: 60
websocket_max_latency_seconds: 30
websocket_event_max_silence_seconds: 14400
Любая ручка в 0 отключает всю проверку живости WebSocket. Значения, которые не разбираются как положительное число (например, 15s, nan, true, -1), тоже её отключают и при каждом старте адаптера пишут предупреждение в лог — если проверка выглядит неактивной, загляните в gateway.log.
websocket_event_max_silence_seconds — исключение: она сторожит одно измерение (доставку событий), поэтому 0 отключает только эту проверку; ready/ACK/задержка продолжают сторожить. Сокет может оставаться ESTABLISHED и исправно подтверждать heartbeat, доставляя при этом ноль событий шлюза; ACK на heartbeat — это фреймы без типа события, так что ни одна проверка на уровне транспорта такое состояние не увидит. Значение по умолчанию (4 часа) совпадает с окном сбоя, которое операторы наблюдали на практике; тихий сервер вполне законно может часами не порождать ни одного события шлюза, так что держите эту границу щедрой, если не знаете свой трафик.
Прежние имена liveness_interval_seconds и liveness_failure_threshold остаются только псевдонимами для совместимости; REST-проверок они больше не означают.
Создайте приложение и скопируйте токен бота (Шаги 1–4), затем выполните hermes gateway setup и выберите Discord. Hermes проверит токен в Discord, сообщит, если Message Content Intent выключен (со ссылкой прямо на нужный переключатель), напечатает готовую ссылку-приглашение для вашего сервера и внесёт вас в список разрешённых как владельца бота — режим разработчика включать не нужно.
Шаг 1: создание Discord-приложения
- Перейдите в Discord Developer Portal и войдите со своим аккаунтом Discord.
- Нажмите New Application в правом верхнем углу.
- Введите название приложения (например, «Hermes Agent») и примите условия Developer Terms of Service.
- Нажмите Create.
Вы попадёте на страницу General Information. Запомните Application ID — он понадобится позже для формирования ссылки-приглашения.
Шаг 2: создание бота
- В левой боковой панели нажмите Bot.
- Discord автоматически создаёт пользователя-бота для вашего приложения. Вы увидите имя бота, которое можно изменить.
- В разделе Authorization Flow:
- Включите Public Bot — это требуется для использования ссылки-приглашения от Discord (рекомендуется). Это позволяет вкладке Installation сгенерировать URL авторизации по умолчанию.
- Оставьте Require OAuth2 Code Grant выключенным (OFF).
На этой странице можно задать боту собственный аватар и баннер. Именно их увидят пользователи в Discord.
Если вы хотите оставить бота приватным (Public Bot = OFF), вместо вкладки Installation вам необходимо использовать метод Manual URL из Шага 5. Ссылка от Discord требует включённого Public Bot.
Шаг 3: включение привилегированных Gateway Intents
Это самый критичный шаг во всей настройке. Hermes всегда запрашивает у Discord содержимое сообщений, поэтому, если Message Content Intent выключен, Discord отклоняет подключение бота, и бот так и не появляется онлайн.
На странице Bot прокрутите вниз до раздела Privileged Gateway Intents. Там три переключателя:
| Intent | Назначение | Обязателен? |
|---|---|---|
| Presence Intent | Видеть статус пользователя онлайн/оффлайн | Опционально |
| Server Members Intent | Доступ к списку участников, определение имён пользователей | Обязателен |
| Message Content Intent | Чтение текста сообщений | Обязателен |
Включите оба — Server Members Intent и Message Content Intent, переведя переключатели в положение ON.
- Без Message Content Intent Discord отклоняет подключение; в
gateway.logбудет строка «Discord rejected the connection because privileged Gateway Intents are not enabled». - Без Server Members Intent бот не может определить имена пользователей для списка разрешённых пользователей и может не понять, кто именно ему пишет.
Если бот остаётся офлайн, а в gateway.log упоминаются привилегированные Gateway Intents, значит, отключён Message Content Intent. Вернитесь в Developer Portal, выберите ваше приложение → Bot → Privileged Gateway Intents и убедитесь, что Message Content Intent включён. Нажмите Save Changes.
Что касается количества серверов:
- Если бот подключён менее чем к 100 серверам, вы можете свободно включать и выключать intent-ы.
- Если бот подключён к 100 или более серверам, Discord потребует подать заявку на верификацию для использования привилегированных intent-ов. Для личного использования это не проблема.
Нажмите Save Changes внизу страницы.
Шаг 4: получение токена бота
Токен бота — это учётные данные, которые Hermes Agent использует для входа от имени бота. Всё ещё на странице Bot:
- В разделе Token нажмите Reset Token.
- Если на вашем аккаунте Discord включена двухфакторная аутентификация, введите код 2FA.
- Discord покажет новый токен. Сразу же скопируйте его.
Токен отображается лишь однажды. Если вы его потеряете, придётся сбросить и сгенерировать новый. Никогда не публикуйте токен и не коммитьте его в Git — тот, у кого есть этот токен, получает полный контроль над ботом.
Сохраните токен в надёжном месте (например, в менеджере паролей). Он понадобится вам на Шаге 8.
Шаг 5: генерация ссылки-приглашения
Для приглашения бота на сервер нужна ссылка OAuth2. Есть два способа её получить:
Вариант A: через вкладку Installation (рекомендуется)
Этот метод требует, чтобы Public Bot был включён (ON) на Шаге 2. Если вы отключили Public Bot, используйте ниже метод Manual URL.
- В левой боковой панели нажмите Installation.
- В разделе Installation Contexts включите Guild Install.
- Для Install Link выберите Discord Provided Link.
- В разделе Default Install Settings для Guild Install:
- Scopes: выберите
botиapplications.commands - Permissions: выберите права доступа, перечисленные ниже.
- Scopes: выберите
Вариант B: Manual URL
Ссылку-приглашение можно составить напрямую по этому формату:
https://discord.com/oauth2/authorize?client_id=YOUR_APP_ID&scope=bot+applications.commands&permissions=309237763136
Замените YOUR_APP_ID на Application ID из Шага 1.
Необходимые права доступа
Минимальный набор прав, необходимых боту:
- View Channels — видеть каналы, к которым у него есть доступ
- Send Messages — отвечать на ваши сообщения
- Embed Links — форматировать насыщенные ответы
- Attach Files — отправлять изображения, аудио и файловые результаты
- Read Message History — поддерживать контекст переписки
Рекомендуемые дополнительные права
- Create Public Threads — создавать изолированные беседы через
/threadи автотреды - Send Messages in Threads — отвечать в тредах
- Add Reactions — реагировать на сообщения эмодзи для подтверждения
Целочисленные значения прав
| Уровень | Число прав | Что включено |
|---|---|---|
| Минимальный | 117760 | View Channels, Send Messages, Embed Links, Attach Files, Read Message History |
| Рекомендуемый | 309237763136 | Всё вышеперечисленное плюс Create Public Threads, Send Messages in Threads, Add Reactions |
Полный (его печатает hermes gateway setup) | 309240908864 | Рекомендуемый плюс Connect и Speak (голосовые каналы) |
Уже установленные боты не получают новые запрошенные права автоматически. Если вы пользовались старой ссылкой с Рекомендуемым набором, пригласите бота заново по ссылке выше, чтобы выдать Create Public Threads.
Шаг 6: приглашение на сервер
- Откройте ссылку-приглашение в браузере (из вкладки Installation или составленную вручную ссылку).
- В выпадающем списке Add to Server выберите свой сервер.
- Нажмите Continue, затем Authorize.
- При появлении CAPTCHA пройдите её.
Для приглашения бота на сервер Discord нужны права Manage Server. Если вашего сервера нет в списке, попросите администратора сервера воспользоваться ссылкой-приглашением самостоятельно.
После авторизации бот появится в списке участников сервера (он будет показан как оффлайн, пока вы не запустите шлюз Hermes).
Шаг 7: определение вашего Discord User ID
Hermes Agent использует ваш Discord User ID, чтобы определять, кто может взаимодействовать с ботом. Чтобы его найти:
- Откройте Discord (десктопное приложение или веб-версию).
- Перейдите в Settings → Advanced → включите Developer Mode (ON).
- Закройте настройки.
- Кликните правой кнопкой мыши по своему имени пользователя (в сообщении, списке участников или профиле) → Copy User ID.
Ваш User ID — это длинное число вроде 284102345871466496.
Developer Mode также позволяет таким же образом копировать Channel ID и Server ID — кликните правой кнопкой по названию канала или сервера и выберите Copy ID. Channel ID понадобится, если вы захотите вручную задать домашний канал.
Шаг 8: настройка Hermes Agent
Вариант A: интерактивная настройка (рекомендуется)
Запустите команду мастера настройки:
hermes gateway setup
Выберите Discord, когда система спросит, и вставьте токен бота. Мастер проверит его в Discord (неверный или устаревший токен отклоняется до сохранения), проверит привилегированные intent-ы, напечатает ссылку-приглашение и предложит внести в список разрешённых владельца бота — то есть вас. Дополнительных пользователей можно добавить по user ID или имени пользователя.
Вариант B: ручная настройка
Добавьте следующее в файл ~/.hermes/.env:
# Required
DISCORD_BOT_TOKEN=your-bot-token
DISCORD_ALLOWED_USERS=284102345871466496
# Multiple allowed users (comma-separated)
# DISCORD_ALLOWED_USERS=284102345871466496,198765432109876543
Затем запустите шлюз:
hermes gateway
Бот должен появиться в сети в Discord в течение нескольких секунд. Отправьте ему сообщение — личное или в доступном ему канале — чтобы проверить работу.
Команду hermes gateway можно запустить в фоновом режиме или как сервис systemd для постоянной работы. Подробности — в документации по развёртыванию.
Справочник по конфигурации
Поведение в Discord управляется через два файла: ~/.hermes/.env — для учётных данных и переключателей на уровне переменных окружения, и ~/.hermes/config.yaml — для структурированных настроек. Переменные окружения всегда имеют приоритет над значениями config.yaml, если заданы оба.
Переменные окружения (.env)
| Переменная | Обязательна | По умолчанию | Описание |
|---|---|---|---|
DISCORD_BOT_TOKEN | Да | — | Токен бота из Discord Developer Portal. |
DISCORD_ALLOWED_USERS | Условно | — | Список Discord user ID через запятую, которым разрешено взаимодействовать с ботом. Без этого параметра или DISCORD_ALLOWED_ROLES шлюз отказывает всем пользователям, если только не задано DISCORD_ALLOW_ALL_USERS=true, GATEWAY_ALLOW_ALL_USERS=true, либо DISCORD_ALLOWED_CHANNELS явно не ограничивает доступ к серверу. Имена пользователей тоже работают: они преобразуются в ID при подключении бота (нужен Server Members Intent). Отображаемые имена и серверные никнеймы не сопоставляются никогда, потому что их может задать любой участник. |
DISCORD_ALLOWED_ROLES | Нет | — | Список ID ролей Discord через запятую. Любой участник с одной из этих ролей авторизован — семантика ИЛИ с DISCORD_ALLOWED_USERS. Автоматически включает Server Members Intent при подключении. Полезно, когда команда модерации часто меняется: новые модераторы получают доступ сразу после выдачи роли, без изменения конфигурации. |
DISCORD_ALLOW_ALL_USERS | Нет | false | Явное разрешение для всех пользователей Discord, способных достучаться до бота. Восстанавливает открытое поведение, существовавшее до версии 0.18, только для Discord; используйте лишь для доверенных/приватных серверов или в разработке. |
GATEWAY_ALLOW_ALL_USERS | Нет | false | Глобальное разрешение «все пользователи» для всех платформ шлюза. Предпочитайте специфичный для платформы DISCORD_ALLOW_ALL_USERS, если только вы намеренно не хотите открыть все подключённые платформы. |
DISCORD_HOME_CHANNEL | Нет | — | ID канала, куда бот отправляет проактивные сообщения (вывод cron-задач, напоминания, уведомления). |
DISCORD_HOME_CHANNEL_NAME | Нет | "Home" | Отображаемое имя домашнего канала в логах и статусе. |
DISCORD_COMMAND_SYNC_POLICY | Нет | "safe" | Управляет синхронизацией нативных слэш-команд при запуске. "safe" сравнивает существующие глобальные команды и обновляет только изменившееся, пересоздавая команды, когда метаданные Discord не могут быть применены через патч. "bulk" сохраняет старое поведение tree.sync(). "off" полностью пропускает синхронизацию при запуске. |
DISCORD_REQUIRE_MENTION | Нет | true | При true бот отвечает в каналах сервера только при @упоминании. Установите false, чтобы отвечать на все сообщения в каждом канале. |
DISCORD_THREAD_REQUIRE_MENTION | Нет | false | При true отключается «сокращение» упоминания внутри треда — треды требуют @упоминания так же, как и каналы, даже после того, как бот уже участвовал в разговоре. Используйте это, когда несколько ботов делят один тред и вы хотите, чтобы каждый срабатывал только по явному @упоминанию. |
DISCORD_FREE_RESPONSE_CHANNELS | Нет | — | Список ID каналов через запятую, где бот отвечает без необходимости @упоминания, даже если DISCORD_REQUIRE_MENTION равен true. |
DISCORD_IGNORE_NO_MENTION | Нет | true | При true бот молчит, если сообщение @упоминает других пользователей, но не упоминает бота. Предотвращает встревание бота в чужие разговоры. Применяется только в каналах сервера, не в личных сообщениях. |
DISCORD_AUTO_THREAD | Нет | true | При true автоматически создаёт новый тред для каждого @упоминания в текстовом канале, изолируя каждый разговор (похоже на поведение Slack). Сообщения, уже находящиеся в тредах или личных сообщениях, не затрагиваются. |
DISCORD_FREE_RESPONSE_AUTO_THREAD | Нет | false | При true каналы свободного ответа (перечисленные в DISCORD_FREE_RESPONSE_CHANNELS) тоже автоматически создают тред на каждое сообщение верхнего уровня, оставаясь без упоминаний. Значение по умолчанию false сохраняет лёгкий режим ответа прямо в канале. Требует DISCORD_AUTO_THREAD=true; DISCORD_NO_THREAD_CHANNELS по-прежнему имеет приоритет, а каналы, связанные с голосовыми, эту настройку всегда игнорируют. |
DISCORD_ALLOW_BOTS | Нет | "none" | Управляет тем, как бот обрабатывает сообщения от других ботов Discord. "none" — игнорировать всех остальных ботов. "mentions" — принимать только сообщения ботов, которые @упоминают Hermes. "all" — принимать все сообщения ботов. По умолчанию оба включающих режима всё равно требуют буквального упоминания в тексте; см. следующую настройку. |
DISCORD_BOTS_REQUIRE_INLINE_MENTION | Нет | true | Требовать буквальный токен <@BOT_ID> / <@!BOT_ID>, чтобы начать передачу от бота. Одних метаданных ответа для этого недостаточно. Короткие продолжения от того же отправителя в том же канале принимаются, как описано ниже. Ставьте false только для доверенных ретрансляторов, которым нужен старый порядок приёма. На сообщения людей не влияет. |
DISCORD_REACTIONS | Нет | true | При true бот добавляет эмодзи-реакции к сообщениям во время обработки (👀 при старте, ✅ при успехе, ❌ при ошибке). Установите false, чтобы полностью отключить реакции. |
DISCORD_IGNORED_CHANNELS | Нет | — | Список ID каналов через запятую, где бот никогда не отвечает, даже при @упоминании. Имеет приоритет над всеми остальными настройками каналов. |
DISCORD_ALLOWED_CHANNELS | Нет | — | Список ID каналов через запятую. При установке бот отвечает только в этих каналах (плюс в личных сообщениях, если они разрешены). Переопределяет discord.allowed_channels из config.yaml. Комбинируйте с DISCORD_IGNORED_CHANNELS, чтобы выразить правила разрешения/запрета. |
DISCORD_NO_THREAD_CHANNELS | Нет | — | Список ID каналов через запятую, где бот отвечает прямо в канале вместо создания треда. Актуально только когда DISCORD_AUTO_THREAD равен true. |
DISCORD_HISTORY_BACKFILL | Нет | true | При true добавляет недавнюю историю канала (с момента последнего ответа бота) к сообщению пользователя при упоминании бота. Восстанавливает контекст, который бот иначе упустил бы при require_mention. Пропускается в личных сообщениях и каналах свободного ответа. Установите false, чтобы отключить. |
DISCORD_HISTORY_BACKFILL_LIMIT | Нет | 50 | Максимальное число сообщений для сканирования назад при сборе блока восстановления истории. На практике сканирование обычно завершается раньше — на последнем собственном сообщении бота в канале. |
DISCORD_REPLY_TO_MODE | Нет | "first" | Управляет поведением ссылки на сообщение при ответе: "off" — никогда не ссылаться на исходное сообщение, "first" — ссылка только на первый фрагмент ответа (по умолчанию), "all" — ссылка на каждый фрагмент. |
DISCORD_ALLOW_MENTION_EVERYONE | Нет | false | При false (по умолчанию) бот не может упомянуть @everyone или @here, даже если ответ содержит эти токены. Установите true, чтобы разрешить. См. Контроль упоминаний ниже. |
DISCORD_ALLOW_MENTION_ROLES | Нет | false | При false (по умолчанию) бот не может упоминать роли через @role. Установите true, чтобы разрешить. |
DISCORD_ALLOW_MENTION_USERS | Нет | true | При true (по умолчанию) бот может упоминать отдельных пользователей по ID. |
DISCORD_ALLOW_MENTION_REPLIED_USER | Нет | true | При true (по умолчанию) ответ на сообщение упоминает автора исходного сообщения. |
DISCORD_PROXY | Нет | — | URL прокси для соединений Discord (HTTP, WebSocket, REST). Переопределяет HTTPS_PROXY/ALL_PROXY. Поддерживает схемы http://, https:// и socks5://. |
DISCORD_ALLOW_ANY_ATTACHMENT | Нет | false | При true бот принимает вложения любого типа файла (не только встроенный список PDF/text/zip/office). Неизвестные типы кэшируются на диск и передаются агенту как локальный путь с MIME application/octet-stream, чтобы он мог изучить файл через terminal / read_file / ffprobe и т. д. |
DISCORD_MAX_ATTACHMENT_BYTES | Нет | 33554432 | Максимальное число байт на вложение, которое шлюз скачивает и кэширует. По умолчанию 32 МиБ. Установите 0 для снятия ограничения (вложения хранятся в памяти во время записи, так что безлимитный режим несёт реальную нагрузку на память). |
HERMES_DISCORD_TEXT_BATCH_DELAY_SECONDS | Нет | 0.6 | Окно ожидания, которое адаптер выдерживает перед отправкой накопленного текстового фрагмента. Полезно для сглаживания потокового вывода. |
HERMES_DISCORD_TEXT_BATCH_SPLIT_DELAY_SECONDS | Нет | 2.0 | Более долгий период тишины для разбиений Discord у самого лимита длины и для фрагментов-продолжений от недавно отмеченного бота в том же канале. |
Передача между ботами: отметить один раз, собрать серию
Приём сообщений от ботов по-прежнему включается явно (DISCORD_ALLOW_BOTS=none по умолчанию). Если он включён в режиме mentions или all, для начала передачи от бота по умолчанию нужен буквальный <@BOT_ID> / <@!BOT_ID> в тексте сообщения. Одного автоматического пинга Discord при ответе для этого недостаточно. Сообщения людей обрабатываются с упоминаниями как прежде.
После принятого упоминания от бота Hermes ненадолго принимает сообщения без упоминания от того же бота в том же канале или треде. Текстовые продолжения попадают в существующий пакетировщик текста, так что быстро разбитый на части ответ может дойти до агента целиком, без повтора отметки в каждой части. Никакого особого протокола отправителя или маркеров частей не нужно.
Например, бот A отправляет <@BOT_B_ID> Here is the review …, а сразу за ним — два неотмеченных текстовых фрагмента в том же треде. Бот B принимает эти фрагменты в окне продолжения и объединяет их с отмеченным текстом. Когда окно истекло, неотмеченное сообщение или пинг ответа при политике по умолчанию новую передачу начать не могут. Явные взаимные отметки по-прежнему работают: механизм защищает от случайных петель через метаданные ответа, а не от намеренно продолжаемых разговоров.
Тайминги и ограничения
Окно приёма длится max(HERMES_DISCORD_TEXT_BATCH_DELAY_SECONDS, HERMES_DISCORD_TEXT_BATCH_SPLIT_DELAY_SECONDS) после принятого упоминания (2 секунды при значениях по умолчанию), и каждое принятое продолжение взводит его заново, поэтому длинная передача, идущая с темпом отправки Discord, доходит целиком. Отдельно от этого каждый поставленный в очередь текстовый фрагмент перезапускает таймер тишины пакета; пакет от отмеченного бота использует период тишины для разбиений, даже если его первый фрагмент короткий. Эти настройки управляют пакетированием на приёмной стороне, а не темпом отправителя. Отключение пакетирования текста (HERMES_DISCORD_TEXT_BATCH_DELAY_SECONDS=0) отключает и приём продолжений.
Это эвристика для коротких серий, а не гарантированная доставка сообщения из нескольких частей. Запоздавшему фрагменту за пределами окна при политике по умолчанию нужно собственное упоминание. Посторонние сообщения того же бота в том же канале внутри окна тоже могут быть приняты. Исключение не ограничено текстом: вложения и команды могут пройти приём, но в этот пакетировщик попадает только текст, а остальные типы сообщений обрабатываются обычным путём. Существующие ограничения каналов и DISCORD_ALLOW_BOTS=none продолжают действовать. Поведение истории и дозагрузки не меняется. Защита шлюза от петель ботов остаётся страховкой: после 20 сообщений от ботов в одном канале за 5 минут дальнейшие сообщения ботов там отбрасываются на 10 минут (настраивается в gateway.bot_loop_guard в config.yaml; сообщения людей не считаются никогда).
Совместимость с доверенными ретрансляторами
Требование буквального упоминания теперь по умолчанию включено (раньше было выключено), в том числе при DISCORD_ALLOW_BOTS=all. Если существующий ретранслятор намеренно опирается на пинги ответа или сообщения ботов без упоминания, верните старый порядок приёма явно:
discord:
bots_require_inline_mention: false
Существующее переопределение через окружение DISCORD_BOTS_REQUIRE_INLINE_MENTION=false тоже поддерживается, когда параметр в YAML не задан. С этим отказом mentions принимает разрешённые упоминания Discord, включая пинги ответа, а all снимает требование упоминания именно для ботов; остальные правила упоминаний в каналах продолжают действовать. В этом режиме совместимости принятый пинг ответа тоже может открыть окно продолжения. Используйте его только для доверенных ретрансляторов: он возвращает риск случайных петель через ответы.
Файл конфигурации (config.yaml)
Раздел discord в ~/.hermes/config.yaml отражает переменные окружения выше. Настройки config.yaml применяются как значения по умолчанию — если соответствующая переменная окружения уже установлена, побеждает она.
# Настройки, специфичные для Discord
discord:
require_mention: true # Требовать @mention в каналах сервера
thread_require_mention: false # Если true, требовать @mention и в тредах (треды с несколькими ботами)
bots_require_inline_mention: true # Авторы-боты должны набрать буквальное @mention (по умолчанию: true)
free_response_channels: "" # ID каналов через запятую (или YAML-список)
auto_thread: true # Автосоздание тредов при @mention
free_response_auto_thread: false # Если true, free_response_channels тоже создают треды (по умолчанию: ответ в канале)
reactions: true # Добавлять эмодзи-реакции во время обработки
ignored_channels: [] # ID каналов, где бот никогда не отвечает
no_thread_channels: [] # ID каналов, где бот отвечает без создания треда
history_backfill: true # Добавлять недавнюю историю канала при упоминании (по умолчанию: true)
history_backfill_limit: 50 # Макс. число сообщений для сканирования назад (по умолчанию: 50)
missed_message_backfill: # Replay messages missed while disconnected (opt-in)
enabled: false
channels: [] # Empty uses free_response_channels
window_seconds: 21600 # Look back at most 6 hours
limit: 100 # Global scan cap per reconnect
max_dispatches: 10 # Recovery dispatch cap per reconnect
max_attempts: 3 # Lifetime re-dispatch cap per message
channel_prompts: {} # Эфемерные системные промпты для отдельных каналов
voice_channel_inactivity_timeout_seconds: 300 # Set 0 to stay in VC until explicit /voice leave
voice_playback_timeout_seconds: 120 # Minimum playback watchdog; long clips get duration+padding
allow_mentions: # Что боту разрешено упоминать (безопасные значения по умолчанию)
everyone: false # Упоминания @everyone / @here (по умолчанию: false)
roles: false # Упоминания @role (по умолчанию: false)
users: true # Упоминания @user (по умолчанию: true)
replied_user: true # Упоминание автора при ответе (по умолчанию: true)
# Изоляция сессий (применяется ко всем платформам шлюза, не только к Discord)
group_sessions_per_user: true # Изолировать сессии по пользователям в общих каналах
discord.require_mention
Тип: boolean — По умолчанию: true
Если включено, бот отвечает в каналах сервера только при прямом @упоминании. Личные сообщения всегда получают ответ независимо от этой настройки.
discord.thread_require_mention
Тип: boolean — По умолчанию: false
По умолчанию, после того как бот один раз поучаствовал в треде (автосоздан при @упоминании или бот уже ответил там), он продолжает отвечать на каждое последующее сообщение в этом треде без необходимости повторного @упоминания. Это правильное поведение по умолчанию для разговоров один на один.
В тредах с несколькими ботами, где пользователи обращаются к одному боту за раз, такое поведение по умолчанию становится проблемой — каждый другой бот в треде тоже срабатывает на каждое сообщение, расходуя кредиты и засоряя канал. Установите thread_require_mention: true, чтобы отключить это «сокращение» внутри треда и применять к тредам те же правила, что и к каналам. Явные @упоминания по-прежнему работают как раньше.
discord:
require_mention: true
thread_require_mention: true # настройка для нескольких ботов
discord.free_response_channels
Тип: строка или список — По умолчанию: ""
ID каналов, где бот отвечает на все сообщения без необходимости @упоминания. Принимает либо строку через запятую, либо список YAML:
# String format
discord:
free_response_channels: "1234567890,9876543210"
# List format
discord:
free_response_channels:
- 1234567890
- 9876543210
Если родительский канал треда указан в этом списке, тред тоже становится свободным от упоминаний.
Каналы свободного ответа также по умолчанию пропускают автосоздание тредов — бот отвечает прямо в канале, а не открывает новый тред на каждое сообщение. Это позволяет каналу оставаться удобной площадкой для лёгкого общения.
Чтобы включить треды для каналов свободного ответа, задайте discord.free_response_auto_thread: true (или DISCORD_FREE_RESPONSE_AUTO_THREAD=true). В этом режиме каждое новое сообщение верхнего уровня в свободном канале по-прежнему получает собственный тред, но канал остаётся без @упоминаний. Требует discord.auto_thread: true.
discord.free_response_auto_thread
Тип: boolean — По умолчанию: false
При true каналы из discord.free_response_channels тоже автоматически создают тред на каждое сообщение верхнего уровня, а не отвечают прямо в канале. Канал остаётся без упоминаний; меняется только то, где живёт разговор.
discord:
free_response_channels:
- 1234567890
auto_thread: true # required — this flag refines it
free_response_auto_thread: true # thread every top-level message there
Требует discord.auto_thread: true (если он выключен, треды не создаются нигде). discord.no_thread_channels по-прежнему имеет приоритет, текстовые каналы, связанные с голосовыми, всегда отвечают прямо в канале, а сообщения-ответы никогда не получают автотред.
DISCORD_FREE_RESPONSE_AUTO_THREAD имеет приоритет над ключом config.yaml, если заданы оба: значение из YAML лишь засевает переменную окружения, когда она ещё не задана, как и у любого другого моста discord.*.
discord.auto_thread
Тип: boolean — По умолчанию: true
Если включено, каждое @упоминание в обычном текстовом канале автоматически создаёт новый тред для разговора. Это позволяет держать основной канал чистым и даёт каждому разговору собственную изолированную историю сессии. После создания треда последующие сообщения в нём не требуют @упоминания — бот знает, что уже участвует в разговоре. Установите thread_require_mention в true, чтобы отключить это «сокращение» внутри треда для сценариев с несколькими ботами.
Сообщения, отправленные в уже существующих тредах или личных сообщениях, этой настройкой не затрагиваются. Каналы, перечисленные в discord.no_thread_channels, а также каналы из discord.free_response_channels, если только discord.free_response_auto_thread не равен true, тоже обходят автосоздание тредов и получают ответ прямо в канале.
discord.reactions
Тип: boolean — По умолчанию: true
Управляет тем, добавляет ли бот эмодзи-реакции к сообщениям в качестве визуальной обратной связи:
- 👀 добавляется, когда бот начинает обрабатывать сообщение
- ✅ добавляется, когда ответ успешно доставлен
- ❌ добавляется при ошибке во время обработки
Отключите это, если реакции отвлекают, или если у роли бота нет права Add Reactions.
discord.ignored_channels
Тип: строка или список — По умолчанию: []
ID каналов, где бот никогда не отвечает, даже при прямом @упоминании. Это правило имеет наивысший приоритет — если канал в этом списке, бот молча игнорирует все сообщения в нём, независимо от require_mention, free_response_channels или любых других настроек.
# String format
discord:
ignored_channels: "1234567890,9876543210"
# List format
discord:
ignored_channels:
- 1234567890
- 9876543210
Если родительский канал треда указан в этом списке, сообщения в этом треде также игнорируются.
discord.no_thread_channels
Тип: строка или список — По умолчанию: []
ID каналов, где бот отвечает прямо в канале вместо автосоздания треда. Это действует только когда auto_thread равен true (по умолчанию). В этих каналах бот отвечает прямо в канале, как в обычном сообщении, а не порождает новый тред.
discord:
no_thread_channels:
- 1234567890 # Bot responds inline here
Полезно для каналов, предназначенных специально для общения с ботом, где треды создавали бы лишний шум.
discord.channel_prompts
Тип: словарь — По умолчанию: {}
Эфемерные системные промпты для отдельных каналов, которые внедряются на каждом ходу в соответствующем канале или треде Discord без сохранения в истории переписки.
discord:
channel_prompts:
"1234567890": |
This channel is for research tasks. Prefer deep comparisons,
citations, and concise synthesis.
"9876543210": |
This forum is for therapy-style support. Be warm, grounded,
and non-judgmental.
Поведение:
- Точные совпадения ID треда/канала имеют приоритет.
- Если сообщение приходит внутри треда или поста форума, а у этого треда нет явной записи, Hermes переходит к ID родительского канала/форума.
- Промпты применяются эфемерно во время выполнения, так что их изменение немедленно влияет на будущие ходы без переписывания прошлой истории сессии.
discord.history_backfill
Тип: boolean — По умолчанию: true
Если включено, бот восстанавливает пропущенные сообщения канала при каждом @упоминании. При require_mention: true бот обрабатывает только сообщения, которые напрямую его тегают — всё остальное в канале не попадает в историю сессии. Восстановление истории сканирует недавнюю историю канала назад при срабатывании, собирая сообщения между последним ответом бота и текущим упоминанием, и включает их как контекст.
Поведение по типам площадок:
- Каналы сервера (при
require_mention: true): восстановление сканирует канал с момента последнего ответа бота. Полезно, когда другие участники писали, пока бота не упоминали. - Треды: восстановление сканирует только сам тред —
channel.history()Discord для треда возвращает только сообщения этого треда, а не родительского канала. Это правильный охват, поскольку треды обычно самодостаточные разговоры. - Личные сообщения: пропускается. Каждое сообщение в личке вызывает бота, так что история сессии уже полная — нет пробела упоминания, который нужно заполнять.
- Каналы свободного ответа и треды, автосозданные самим ботом: пропускается по той же причине — без ограничения по упоминанию нет и пробела.
Пользовательские сессии (group_sessions_per_user: true, по умолчанию) также выигрывают: в сессии пользователя не хватает контекста, опубликованного другими участниками канала, и собственных сообщений пользователя до того, как он тегнул бота. Восстановление заполняет оба пробела.
discord:
history_backfill: true # по умолчанию
Чтобы отключить:
discord:
history_backfill: false
Примечание: сообщения, поступившие во время обработки бота (между триггером и ответом), не захватываются. Это принятое упрощение — пользователь может отправить сообщение повторно или тегнуть бота ещё раз.
discord.history_backfill_limit
Тип: integer — По умолчанию: 50
Максимальное число сообщений для сканирования назад при восстановлении контекста канала. На практике сканирование обычно завершается намного раньше — на последнем собственном сообщении бота в канале, которое является естественной границей между ходами. Этот лимит — предохранитель для холодного старта и длинных пробелов, когда в недавней истории нет предыдущего сообщения бота.
discord:
history_backfill: true
history_backfill_limit: 50
discord.missed_message_backfill
Тип: объект — по умолчанию: выключено
Окно возобновления WebSocket у Discord может истечь во время перезапуска или сетевого сбоя. Сообщения, отправленные в этот промежуток, живыми событиями шлюза уже не доставляются. Когда опция включена, Hermes после переподключения к Discord просматривает ограниченный набор историй заданных каналов и тредов, а затем прогоняет ещё не обработанные сообщения по тому же пути, что и живые события: авторизация, упоминания, каналы, дедупликация, отправка.
discord:
missed_message_backfill:
enabled: true
channels: ["123456789012345678"]
window_seconds: 3600
limit: 100
max_dispatches: 10
max_attempts: 3
Если channels пуст, Hermes берёт discord.free_response_channels. Значение "*" ставьте, только когда боту действительно положено просматривать каждый доступный текстовый канал сервера. Журнал восстановления лежит в профиле по пути gateway/discord_message_recovery.db — так успешно отвеченное сообщение не проиграется заново после следующего перезапуска. Сообщение считается отвеченным, как только его ход доставил финальный ответ, независимо от того, была ли у ответа ссылка на сообщение Discord (включая reply_to_mode: "off", потоковые ответы и ответы из одних медиа).
max_dispatches ограничивает одно сканирование; max_attempts (по умолчанию 3) ограничивает, сколько раз одно сообщение вообще может быть повторно отправлено в работу, чтобы сообщение, чей ход раз за разом падает, не прогонялось заново при каждом переподключении. window_seconds соблюдается всегда: курсор сканирования канала может сузить просмотр, но никогда не заглядывает дальше окна.
group_sessions_per_user
Тип: boolean — По умолчанию: true
Это глобальная настройка шлюза (не специфичная для Discord), которая управляет тем, получают ли пользователи одного канала изолированные истории сессий.
При true: Alice и Bob, общаясь в #research, ведут каждый свой отдельный разговор с Hermes. При false: весь канал делит одну переписку и один слот запущенного агента.
group_sessions_per_user: true
Полные последствия каждого режима см. в разделе Модель сессий выше.
display.tool_progress
Тип: строка — По умолчанию: "all" — Значения: off, new, all, verbose
Управляет тем, отправляет ли бот сообщения о ходе выполнения в чат во время обработки (например, «Читаю файл…», «Выполняю команду терминала…»). Это глобальная настройка шлюза, применяемая ко всем платформам.
display:
tool_progress: "all" # off | new | all | verbose
off— без сообщений о ходе выполненияnew— показывать только первый вызов инструмента за ходall— показывать все вызовы инструментов (обрезаются до 40 символов в сообщениях шлюза)verbose— показывать полные детали вызовов инструментов (может давать длинные сообщения)
display.tool_progress_command
Тип: boolean — По умолчанию: false
Если включено, делает слэш-команду /verbose доступной в шлюзе, позволяя переключаться между режимами отображения хода выполнения (off → new → all → verbose → off) без правки config.yaml.
display:
tool_progress_command: true
display.reasoning_style
Тип: строка — по умолчанию (Discord): "subtext" — значения: code, blockquote, subtext
Определяет, как рисуется блок рассуждений модели, когда их отображение включено. В Discord по умолчанию стоит subtext: используется нативный мелкий серый текст метаданных -# , поэтому рассуждения остаются визуально вторичными по отношению к ответу. blockquote рисует их цитатой через >, а code (умолчание на других платформах) — блоком кода. Длинные рассуждения сворачиваются до первых 15 строк.
display:
platforms:
discord:
reasoning_style: subtext # code | blockquote | subtext
Контроль доступа к слэш-командам
По умолчанию любой разрешённый пользователь может выполнять любую слэш-команду. Чтобы разделить список разрешённых пользователей на администраторов (полный доступ к слэш-командам) и обычных пользователей (только явно разрешённые команды), добавьте allow_admin_from и user_allowed_commands в блок extra платформы Discord:
gateway:
platforms:
discord:
extra:
# Existing user allowlist (unchanged)
allow_from:
- "123456789012345678" # admin user ID
- "999888777666555444" # regular user ID
# NEW — admins get all slash commands (built-in + plugin)
allow_admin_from:
- "123456789012345678"
# NEW — non-admin allowed users can only run these slash commands.
# /help and /whoami are always allowed so users can see their access.
user_allowed_commands:
- status
- model
- history
# Optional: separate admin / command lists for server channels
group_allow_admin_from:
- "123456789012345678"
group_user_allowed_commands:
- status
Поведение:
- Пользователь из
allow_admin_fromдля данной области видимости (личные сообщения или канал сервера) может выполнять любую зарегистрированную слэш-команду — как встроенную, так и зарегистрированную плагином — через живой реестр команд. - Пользователь, не входящий в
allow_admin_from, может выполнять только команды из спискаuser_allowed_commands, плюс всегда разрешённый минимум:/helpи/whoami. - Обычный чат (не слэш-сообщения) этим не затрагивается. Пользователи без прав администратора по-прежнему могут обычно общаться с агентом — они просто не могут вызывать произвольные команды.
- Обратная совместимость: если
allow_admin_fromне задано для области видимости, ограничение слэш-команд для неё отключено. Существующие установки продолжают работать без изменений. - Статус администратора в личных сообщениях не подразумевает статус администратора в каналах сервера. У каждой области видимости свой список администраторов.
Используйте /whoami, чтобы увидеть активную область видимости, свой уровень (администратор / пользователь / без ограничений) и какие слэш-команды вам доступны.
Интерактивный выбор модели
Отправьте /model без аргументов в канал Discord, чтобы открыть выбор модели через выпадающие списки:
- Выбор провайдера — выпадающий список Select с доступными провайдерами (до 25).
- Выбор модели — второй выпадающий список с моделями выбранного провайдера (до 25).
Выбор истекает через 120 секунд. Взаимодействовать с ним могут только авторизованные пользователи (те, кто указан в DISCORD_ALLOWED_USERS). Если вы знаете название модели, введите /model <название> напрямую.
Нативные слэш-команды для навыков
Hermes автоматически регистрирует установленные навыки как нативные команды приложения Discord. Это значит, что навыки появляются в меню автодополнения / Discord вместе со встроенными командами.
- Каждый навык становится слэш-командой Discord (например,
/code-review,/ascii-art) - Навыки принимают опциональный строковый параметр
args - У Discord есть лимит в 100 команд приложения на бота — если у вас навыков больше, чем доступных слотов, лишние навыки пропускаются с предупреждением в логах
- Навыки регистрируются при запуске бота вместе со встроенными командами вроде
/model,/resetи/bg
Дополнительная настройка не требуется — любой навык, установленный через hermes skills install, автоматически регистрируется как слэш-команда Discord при следующем перезапуске шлюза.
Отключение регистрации слэш-команд
Если вы запускаете несколько шлюзов Hermes для одного и того же приложения Discord (например, staging + production), только один из них должен владеть глобальной регистрацией слэш-команд — иначе побеждает последний запуск, и регистрации начинают мигать. Отключите регистрацию слэш-команд на «дополнительном» шлюзе:
gateway:
platforms:
discord:
extra:
slash_commands: false # default: true
Оставив это значение true на «основном» шлюзе, вы сохраняете обычное поведение — глобальные команды меню / для встроенных функций и установленных навыков.
Отправка медиа (встроенные теги MEDIA:)
Адаптер Discord поддерживает нативную загрузку файлов для каждого распространённого типа медиа через встроенные теги MEDIA:/path/to/file, генерируемые в ответе агента — адаптер убирает тег и автоматически загружает файл:
| Тип | Как доставляется |
|---|---|
| Изображения (PNG/JPG/WebP) | Нативное вложение-изображение Discord со встроенным предпросмотром |
| Анимированные GIF | send_animation загружает как animation.gif, чтобы Discord проигрывал его встроенно (а не как статичную миниатюру) |
| Видео (MP4/MOV) | send_video — нативный видеоплеер |
| Аудио / голос | send_voice — нативное голосовое сообщение, когда возможно, иначе файловое вложение |
| Документы (PDF/ZIP/docx и т. п.) | send_document — нативное вложение с кнопкой скачивания |
Лимит размера загрузки Discord зависит от уровня буста сервера (25 МБ бесплатно, до 500 МБ). Если Hermes получает HTTP 413, адаптер переходит к резервному варианту — ссылке на локальный путь в кэше, вместо тихого отказа.
Приём файлов произвольного типа
Принимается любой тип файла, загруженный пользователем. Пропуском служит авторизация для сообщений агенту, а не расширение файла. Каждая загрузка скачивается, кэшируется в ~/.hermes/cache/documents/ и передаётся агенту как событие сообщения типа DOCUMENT, чтобы он мог изучить файл с помощью terminal (ffprobe, unzip, file, strings и т. д.) или read_file.
- Известные типы (PDF, docx/xlsx/pptx, zip, изображения/аудио/видео и т. д.) сохраняют точный MIME-тип.
- Неизвестные типы получают заявленный тип контента при загрузке, либо
application/octet-stream, если он не указан. - Небольшие файлы, декодируемые как UTF-8 (текст, код, конфигурация, HTML, CSS, JSON, YAML…), автоматически вставляются в промпт объёмом до 100 КиБ. Бинарные файлы, которые не удаётся декодировать, передаются только как заметка с указанием пути (автоматически преобразуемого для песочниц Docker/Modal через
to_agent_visible_cache_path), чтобы они не раздували окно контекста.
Единственное ограничение на входящие файлы — лимит размера на файл (по умолчанию 32 МиБ):
discord:
# Опционально — повысить/отключить лимит размера файла. По умолчанию 32 МиБ.
# Весь файл хранится в памяти во время кэширования, поэтому безлимитные
# загрузки несут реальную нагрузку на память.
max_attachment_bytes: 33554432 # bytes; 0 = unlimited
Эквивалентная переменная окружения: DISCORD_MAX_ATTACHMENT_BYTES=33554432 (или 0 для снятия ограничения).
Устаревший флаг discord.allow_any_attachment теперь не выполняет никаких действий — файлы любого типа принимаются всегда — и оставлен только для того, чтобы существующие конфигурации не вызывали ошибку.
Отключение лимита размера (max_attachment_bytes: 0) означает, что пользователь может отправить боту многогигабайтный файл, и шлюз послушно буферизует его в памяти, кэшируя на диск. Устанавливайте это только на доверенных однопользовательских установках. Для общих ботов оставьте лимит по умолчанию 32 МиБ или повышайте его осторожно.
Интерактивные запросы (clarify)
Когда агент вызывает инструмент clarify — чтобы спросить, какой подход вы предпочитаете, получить обратную связь после задачи или уточнить перед нетривиальным решением — Discord отображает вопрос с кнопкой на каждый вариант:
Which framework should I use for the dashboard?
[1. Next.js] [2. Remix] [3. Astro] [Other (type answer)]
Нажмите на пронумерованную кнопку, чтобы ответить, или на Other, чтобы ввести произвольный ответ (следующее ваше сообщение в этом канале станет ответом). Открытые вызовы clarify (без предустановленных вариантов) пропускают кнопки и просто ожидают ваше следующее сообщение.
Кнопки становятся неактивными после выбора, чтобы повторные нажатия не разрешали запрос дважды. Настройте тайм-аут ответа через agent.clarify_timeout в ~/.hermes/config.yaml (по умолчанию 3600 секунд; 0 или меньше — без ограничения). Если вы не ответите в течение тайм-аута, агент разблокируется с "outcome": "timed_out" и адаптируется, вместо того чтобы зависать. Ответьте skip, чтобы пропустить вопрос.
Раскладка запросов
Интерактивные запросы (подтверждения команд, вопросы clarify и подтверждения слэш-команд) используют одну раскладку: обычное сообщение несёт всё содержимое — команду и причину, по которой её отметили, плюс срок подтверждения, либо вопрос и подсказку для ответа; карточка-embed под ним — только заголовок, а кнопки стоят под карточкой. Всё, что нужно для решения, есть в обычном тексте, поэтому запрос читается правильно в клиентах, которые скрывают или отделяют embed-карточки, а в клиентах, которые их показывают, ничего не дублируется.
Домашний канал
Вы можете назначить «домашний канал», куда бот отправляет проактивные сообщения (например, вывод cron-задач, напоминания и уведомления). Есть два способа это сделать:
Через слэш-команду
Введите /sethome в любом канале Discord, где присутствует бот. Этот канал станет домашним.
Ручная настройка
Добавьте это в ~/.hermes/.env:
DISCORD_HOME_CHANNEL=123456789012345678
DISCORD_HOME_CHANNEL_NAME="#bot-updates"
Замените ID на реальный ID канала (правый клик → Copy Channel ID при включённом Developer Mode).
Голосовые сообщения
Hermes Agent поддерживает голосовые сообщения Discord:
- Входящие голосовые сообщения автоматически распознаются настроенным STT-провайдером: локальный
faster-whisper(без ключа), Groq Whisper (GROQ_API_KEY) или OpenAI Whisper (VOICE_TOOLS_OPENAI_KEY). - Синтез речи (TTS): используйте
/voice tts, чтобы бот отправлял озвученные ответы вместе с текстовыми. - Голосовые каналы Discord: Hermes также может подключаться к голосовому каналу, слушать говорящих пользователей и отвечать голосом в канале.
Полное руководство по настройке и работе см. в:
Аудиоэффекты голосового канала (фон + голосовые подтверждения)
Когда бот находится в голосовом канале, ему можно придать более живое ощущение общения: короткое голосовое подтверждение («сейчас посмотрю») перед началом работы и лёгкий фоновый звук «размышления», который проигрывается, пока выполняются инструменты — речь приглушает фон и снова усиливает его по завершении, похоже на голосовой режим Grok.
discord.py воспроизводит только один аудиопоток на соединение, поэтому Hermes устанавливает программный микшер на исходящий поток, суммируя фоновую петлю, подтверждения и ответы TTS в единый поток — они накладываются друг на друга, а не обрывают друг друга.
Эта функция отключена по умолчанию. Включите её в config.yaml:
discord:
voice_fx:
enabled: true # master switch
ambient_enabled: true # idle "thinking" bed while tools run
ambient_path: "" # custom loop file (any audio format); "" = built-in synthesised pad
ambient_gain: 0.18 # idle bed loudness (0.0–1.0)
duck_gain: 0.06 # ambient loudness while the bot is speaking
speech_gain: 1.0 # TTS / acknowledgement loudness
ack_enabled: true # speak a short phrase before the first tool call of a turn
ack_phrases: # picked at random; set to [] to disable the spoken ack
- "Let me look into that."
- "One moment."
- "Checking on that now."
Примечания:
- Поставьте
voice_channel_inactivity_timeout_seconds: 0, если хотите, чтобы бот оставался в голосовом канале до явного/voice leaveили ручного отключения. Значение по умолчанию сохраняет исторический автовыход по 300 секундам простоя. voice_playback_timeout_seconds— нижняя граница, а не жёсткий потолок для длинного TTS. Hermes определяет длительность сгенерированного аудио и ждётduration + 30 с, когда это больше настроенной границы.- Подтверждение срабатывает не более одного раза за ход, только когда бот находится в голосовом канале и микшер активен. Используется настроенный вами провайдер TTS.
ambient_pathпринимает любой файл, который может декодироватьffmpeg; он зацикливается бесшовно. Оставьте поле пустым, чтобы использовать встроенный синтезированный фон (без дополнительных файлов).- Все настройки находятся в
config.yaml(не в.env) — они относятся к поведению, а не к секретам. - Когда
voice_fx.enabledравенfalse, воспроизведение голоса использует исходный однократный путь, и ничего не меняется.
Форумные каналы
Форумные каналы Discord (тип 15) не принимают прямые сообщения — каждый пост в форуме должен быть тредом. Hermes автоматически распознаёт форумные каналы и создаёт новый тред-пост, когда нужно туда что-то отправить, так что текстовые ответы, TTS, изображения, голосовые сообщения и файловые вложения работают без специальной обработки со стороны агента.
- Название треда формируется из первой строки сообщения (префикс markdown-заголовка удаляется, ограничение 100 символов). Если сообщение состоит только из вложения, в качестве резервного имени треда используется имя файла.
- Вложения идут вместе со стартовым сообщением нового треда — без отдельного шага загрузки, без частичных отправок.
- Один вызов — один тред: каждая отправка в форум создаёт новый тред. Последующие отправки в тот же форум, соответственно, создадут отдельные треды.
- Определение происходит в три уровня: сначала кэш каталога каналов, затем локальный для процесса кэш проверок и, в крайнем случае, живой запрос
GET /channels/{id}(результат которого затем запоминается на всё время работы процесса).
Обновление каталога (/channels refresh на платформах, где это доступно, или перезапуск шлюза) наполняет кэш любыми форумными каналами, созданными после запуска бота.
Устранение неполадок
Бот онлайн, но не отвечает на сообщения
Причина: обычно авторизация Discord отказывает по умолчанию из-за отсутствия настроенной политики доступа. (Выключенный Message Content Intent, наоборот, оставляет бота офлайн; см. Шаг 3.)
Решение:
-
Перейдите в Developer Portal → ваше приложение → Bot → Privileged Gateway Intents → включите Message Content Intent → Save Changes.
-
Убедитесь, что настроена хотя бы одна политика доступа Discord:
# рекомендуется: разрешить конкретных пользователей DISCORD_ALLOWED_USERS=284102345871466496 # или разрешить доверенному серверу/dev-боту вести себя как Discord до версии 0.18 DISCORD_ALLOW_ALL_USERS=true -
Перезапустите шлюз:
hermes gateway restart
Если в логе шлюза видно, что Discord подключён и проверки REST API проходят, но каждое входящее сообщение остаётся без ответа, поищите это предупреждение в ~/.hermes/logs/gateway.log:
No Discord access policy configured; inbound Discord messages will be denied by default.
Hermes 0.18 намеренно отказывает по умолчанию для внешне доступных адаптеров. Discord-бот без DISCORD_ALLOWED_USERS, без DISCORD_ALLOWED_ROLES, без DISCORD_ALLOWED_CHANNELS и без явного флага allow-all успешно подключится, но будет отклонять входящих пользователей до обычной обработки сообщений.
Ошибка «Privileged intents» / PrivilegedIntentsRequired при запуске
Причина: Hermes запрашивает привилегированные Gateway Intents, которые не включены для вашего бота в Developer Portal. Discord отклоняет WebSocket-соединение. Hermes всегда запрашивает Message Content Intent. Также он запрашивает Server Members Intent, если в вашем allowlist используются имена пользователей (не числовые ID) или задан DISCORD_ALLOWED_ROLES. Presence Intent не требуется.
Решение:
- Перейдите в Developer Portal → ваше приложение → Bot → Privileged Gateway Intents.
- Включите Message Content Intent (обязательно). Включите Server Members Intent, если используете allowlist по именам или ролям.
- Нажмите Save Changes, затем перезапустите шлюз (
hermes gateway restart).
В логе шлюза должно быть указано, какие именно intent-ы запросил Hermes. Пока они не включены, Discord будет продолжать отклонять соединение — это ошибка настройки в портале, а не сетевой сбой.
Бот не видит сообщения в конкретном канале
Причина: у роли бота нет прав на просмотр этого канала.
Решение: в Discord перейдите в настройки канала → Permissions → добавьте роль бота с включёнными правами View Channel и Read Message History.
Ошибки 403 Forbidden
Причина: у бота не хватает необходимых прав.
Решение: пригласите бота заново с правильными правами, используя ссылку из Шага 5, либо вручную настройте права роли бота в Server Settings → Roles.
Если /thread сообщает об ошибке Discord 50001 (Missing Access), проверьте действующие права
бота в родительском канале. Ему нужны View Channel, Send Messages, Create Public
Threads и Send Messages in Threads. Проверьте также переопределения прав родительской
категории и самого канала: явный запрет там может перекрыть права, выданные ролью сервера.
Бот оффлайн
Причина: шлюз Hermes не запущен, либо токен неверен.
Решение: проверьте, что hermes gateway запущен. Проверьте DISCORD_BOT_TOKEN в файле .env. Если вы недавно сбрасывали токен, обновите его.
«User not allowed» / бот игнорирует вас
Причина: ваш User ID отсутствует в DISCORD_ALLOWED_USERS.
Решение: добавьте свой User ID в DISCORD_ALLOWED_USERS в ~/.hermes/.env и перезапустите шлюз.
Люди в одном канале неожиданно делят контекст
Причина: group_sessions_per_user отключён, либо платформа не может предоставить ID пользователя для сообщений в этом контексте.
Решение: установите это в ~/.hermes/config.yaml и перезапустите шлюз:
group_sessions_per_user: true
Если вы намеренно хотите общую переписку в комнате, оставьте эту настройку выключенной — просто учитывайте общую историю переписки и общее поведение прерываний.
Безопасность
Всегда устанавливайте DISCORD_ALLOWED_USERS (или DISCORD_ALLOWED_ROLES), чтобы ограничить круг людей, которые могут взаимодействовать с ботом. Без этого шлюз по умолчанию отказывает всем пользователям в качестве меры безопасности. Авторизуйте только тех, кому доверяете — авторизованные пользователи получают полный доступ к возможностям агента, включая использование инструментов и доступ к системе.
Контроль доступа на основе ролей
Для серверов, где доступ управляется ролями, а не списками отдельных пользователей (команды модераторов, служба поддержки, внутренние инструменты), используйте DISCORD_ALLOWED_ROLES — список ID ролей через запятую. Любой участник с одной из этих ролей авторизован.
# ~/.hermes/.env — works alongside or instead of DISCORD_ALLOWED_USERS
DISCORD_ALLOWED_ROLES=987654321098765432,876543210987654321
Семантика:
- ИЛИ со списком пользователей. Пользователь авторизован, если его ID есть в
DISCORD_ALLOWED_USERSили у него есть любая роль изDISCORD_ALLOWED_ROLES. - Server Members Intent включается автоматически. Когда задан
DISCORD_ALLOWED_ROLES, бот при подключении включает Members intent — это необходимо, чтобы Discord присылал информацию о ролях вместе с записями участников. - ID ролей, а не имена. Получите их в Discord: User Settings → Advanced → Developer Mode ON, затем правый клик по любой роли → Copy Role ID.
- Резерв для личных сообщений. В личных сообщениях проверка роли сканирует общие серверы; пользователь с разрешённой ролью на любом общем сервере авторизован и в личных сообщениях тоже.
Это предпочтительный паттерн, когда команда модерации часто меняется: новые модераторы получают доступ в момент выдачи роли, без правки .env и перезапуска шлюза.
Контроль упоминаний
По умолчанию Hermes блокирует упоминания ботом @everyone, @here и упоминания ролей, даже если они содержатся в ответе. Это защищает от того, чтобы неудачно составленный промпт или процитированный пользовательский контент не заспамил весь сервер. Отдельные упоминания @user и упоминания-ссылки при ответе (маленький чип «отвечает на…») остаются включёнными, чтобы обычное общение продолжало работать.
Эти настройки по умолчанию можно ослабить через переменные окружения или config.yaml:
# ~/.hermes/config.yaml
discord:
allow_mentions:
everyone: false # allow the bot to ping @everyone / @here
roles: false # allow the bot to ping @role mentions
users: true # allow the bot to ping individual @users
replied_user: true # ping the author when replying to their message
# ~/.hermes/.env — env vars win over config.yaml
DISCORD_ALLOW_MENTION_EVERYONE=false
DISCORD_ALLOW_MENTION_ROLES=false
DISCORD_ALLOW_MENTION_USERS=true
DISCORD_ALLOW_MENTION_REPLIED_USER=true
Оставляйте everyone и roles в значении false, если вы точно не знаете, зачем они вам нужны. LLM очень легко может сгенерировать строку @everyone внутри обычного на вид ответа; без этой защиты это уведомило бы всех участников вашего сервера.
Подробнее о защите вашего развёртывания Hermes Agent см. в Руководстве по безопасности.